Merge pull request #91 from davidgiven/dtrg-m68k
Add a Musashi-based 68020 emulator; use it to run the linux68k tests.
This commit is contained in:
		
						commit
						37f466a8f4
					
				
					 27 changed files with 20873 additions and 5 deletions
				
			
		
							
								
								
									
										2
									
								
								Makefile
									
										
									
									
									
								
							
							
						
						
									
										2
									
								
								Makefile
									
										
									
									
									
								
							| 
						 | 
				
			
			@ -24,7 +24,7 @@ BUILDDIR = $(ACK_TEMP_DIR)/ack-build
 | 
			
		|||
 | 
			
		||||
# What build flags do you want to use for native code?
 | 
			
		||||
 | 
			
		||||
CFLAGS = -g -O -Wno-return-type
 | 
			
		||||
CFLAGS = -g -Og -Wno-return-type
 | 
			
		||||
LDFLAGS = 
 | 
			
		||||
 | 
			
		||||
# Various commands.
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -18,6 +18,7 @@ vars.plats = {
 | 
			
		|||
	"pdpv7",
 | 
			
		||||
}
 | 
			
		||||
vars.plats_with_tests = {
 | 
			
		||||
	"linux68k",
 | 
			
		||||
	"linux386",
 | 
			
		||||
	"linuxppc",
 | 
			
		||||
	--"qemuppc",
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										58
									
								
								plat/linux68k/emu/build.lua
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										58
									
								
								plat/linux68k/emu/build.lua
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,58 @@
 | 
			
		|||
cprogram {
 | 
			
		||||
	name = "m68kmake",
 | 
			
		||||
	srcs = {
 | 
			
		||||
		"./musashi/m68kmake.c"
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
normalrule {
 | 
			
		||||
	name = "m68k_engine",
 | 
			
		||||
	ins = {
 | 
			
		||||
		"+m68kmake",
 | 
			
		||||
		"./musashi/m68k_in.c",
 | 
			
		||||
		"./musashi/m68kcpu.h",
 | 
			
		||||
		"./m68kconf.h",
 | 
			
		||||
		"./musashi/m68kcpu.c",
 | 
			
		||||
		"./musashi/m68kdasm.c",
 | 
			
		||||
		"./musashi/m68k.h",
 | 
			
		||||
	},
 | 
			
		||||
	outleaves = {
 | 
			
		||||
		"m68kopac.c",
 | 
			
		||||
		"m68kopdm.c",
 | 
			
		||||
		"m68kopnz.c",
 | 
			
		||||
		"m68kops.c",
 | 
			
		||||
		"m68kops.h",
 | 
			
		||||
		"m68kcpu.h",
 | 
			
		||||
		"m68kconf.h",
 | 
			
		||||
		"m68kcpu.c",
 | 
			
		||||
		"m68kdasm.c",
 | 
			
		||||
		"m68k.h",
 | 
			
		||||
	},
 | 
			
		||||
	commands = {
 | 
			
		||||
		"cp %{ins[2]} %{ins[3]} %{ins[4]} %{ins[5]} %{ins[6]} %{ins[7]} %{dir}",
 | 
			
		||||
		"cd %{dir} && %{ins[1]}"
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
clibrary {
 | 
			
		||||
	name = "headers",
 | 
			
		||||
	srcs = {},
 | 
			
		||||
	hdrs = {
 | 
			
		||||
		matching(filenamesof("+m68k_engine"), "%.h$"),
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
cprogram {
 | 
			
		||||
	name = "emu68k",
 | 
			
		||||
	vars = {
 | 
			
		||||
		["+cflags"] = {"-DM68K_COMPILE_FOR_MAME=0"}
 | 
			
		||||
	},
 | 
			
		||||
	srcs = {
 | 
			
		||||
		"./sim.c",
 | 
			
		||||
		matching(filenamesof("+m68k_engine"), "%.c$"),
 | 
			
		||||
	},
 | 
			
		||||
	deps = {
 | 
			
		||||
		"+headers",
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										193
									
								
								plat/linux68k/emu/m68kconf.h
									
										
									
									
									
										Executable file
									
								
							
							
						
						
									
										193
									
								
								plat/linux68k/emu/m68kconf.h
									
										
									
									
									
										Executable file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,193 @@
 | 
			
		|||
/* ======================================================================== */
 | 
			
		||||
/* ========================= LICENSING & COPYRIGHT ======================== */
 | 
			
		||||
/* ======================================================================== */
 | 
			
		||||
/*
 | 
			
		||||
 *                                  MUSASHI
 | 
			
		||||
 *                                Version 3.4
 | 
			
		||||
 *
 | 
			
		||||
 * A portable Motorola M680x0 processor emulation engine.
 | 
			
		||||
 * Copyright 1998-2001 Karl Stenerud.  All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * This code may be freely used for non-commercial purposes as long as this
 | 
			
		||||
 * copyright notice remains unaltered in the source code and any binary files
 | 
			
		||||
 * containing this code in compiled form.
 | 
			
		||||
 *
 | 
			
		||||
 * All other lisencing terms must be negotiated with the author
 | 
			
		||||
 * (Karl Stenerud).
 | 
			
		||||
 *
 | 
			
		||||
 * The latest version of this code can be obtained at:
 | 
			
		||||
 * http://kstenerud.cjb.net
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#ifndef M68KCONF__HEADER
 | 
			
		||||
#define M68KCONF__HEADER
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* Configuration switches.
 | 
			
		||||
 * Use OPT_SPECIFY_HANDLER for configuration options that allow callbacks.
 | 
			
		||||
 * OPT_SPECIFY_HANDLER causes the core to link directly to the function
 | 
			
		||||
 * or macro you specify, rather than using callback functions whose pointer
 | 
			
		||||
 * must be passed in using m68k_set_xxx_callback().
 | 
			
		||||
 */
 | 
			
		||||
#define OPT_OFF             0
 | 
			
		||||
#define OPT_ON              1
 | 
			
		||||
#define OPT_SPECIFY_HANDLER 2
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* ======================================================================== */
 | 
			
		||||
/* ============================== MAME STUFF ============================== */
 | 
			
		||||
/* ======================================================================== */
 | 
			
		||||
 | 
			
		||||
/* If you're compiling this for MAME, only change M68K_COMPILE_FOR_MAME
 | 
			
		||||
 * to OPT_ON and use m68kmame.h to configure the 68k core.
 | 
			
		||||
 */
 | 
			
		||||
#ifndef M68K_COMPILE_FOR_MAME
 | 
			
		||||
#define M68K_COMPILE_FOR_MAME      OPT_OFF
 | 
			
		||||
#endif /* M68K_COMPILE_FOR_MAME */
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#if M68K_COMPILE_FOR_MAME == OPT_OFF
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* ======================================================================== */
 | 
			
		||||
/* ============================= CONFIGURATION ============================ */
 | 
			
		||||
/* ======================================================================== */
 | 
			
		||||
 | 
			
		||||
/* Turn ON if you want to use the following M68K variants */
 | 
			
		||||
#define M68K_EMULATE_010            OPT_ON
 | 
			
		||||
#define M68K_EMULATE_EC020          OPT_ON
 | 
			
		||||
#define M68K_EMULATE_020            OPT_ON
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* If ON, the CPU will call m68k_read_immediate_xx() for immediate addressing
 | 
			
		||||
 * and m68k_read_pcrelative_xx() for PC-relative addressing.
 | 
			
		||||
 * If off, all read requests from the CPU will be redirected to m68k_read_xx()
 | 
			
		||||
 */
 | 
			
		||||
#define M68K_SEPARATE_READS         OPT_OFF
 | 
			
		||||
 | 
			
		||||
/* If ON, the CPU will call m68k_write_32_pd() when it executes move.l with a
 | 
			
		||||
 * predecrement destination EA mode instead of m68k_write_32().
 | 
			
		||||
 * To simulate real 68k behavior, m68k_write_32_pd() must first write the high
 | 
			
		||||
 * word to [address+2], and then write the low word to [address].
 | 
			
		||||
 */
 | 
			
		||||
#define M68K_SIMULATE_PD_WRITES     OPT_OFF
 | 
			
		||||
 | 
			
		||||
/* If ON, CPU will call the interrupt acknowledge callback when it services an
 | 
			
		||||
 * interrupt.
 | 
			
		||||
 * If off, all interrupts will be autovectored and all interrupt requests will
 | 
			
		||||
 * auto-clear when the interrupt is serviced.
 | 
			
		||||
 */
 | 
			
		||||
#define M68K_EMULATE_INT_ACK        OPT_OFF
 | 
			
		||||
#define M68K_INT_ACK_CALLBACK(A)    cpu_irq_ack(A)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* If ON, CPU will call the breakpoint acknowledge callback when it encounters
 | 
			
		||||
 * a breakpoint instruction and it is running a 68010+.
 | 
			
		||||
 */
 | 
			
		||||
#define M68K_EMULATE_BKPT_ACK       OPT_OFF
 | 
			
		||||
#define M68K_BKPT_ACK_CALLBACK()    your_bkpt_ack_handler_function()
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* If ON, the CPU will monitor the trace flags and take trace exceptions
 | 
			
		||||
 */
 | 
			
		||||
#define M68K_EMULATE_TRACE          OPT_OFF
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* If ON, CPU will call the output reset callback when it encounters a reset
 | 
			
		||||
 * instruction.
 | 
			
		||||
 */
 | 
			
		||||
#define M68K_EMULATE_RESET          OPT_OFF
 | 
			
		||||
#define M68K_RESET_CALLBACK()       cpu_pulse_reset()
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* If ON, CPU will call the set fc callback on every memory access to
 | 
			
		||||
 * differentiate between user/supervisor, program/data access like a real
 | 
			
		||||
 * 68000 would.  This should be enabled and the callback should be set if you
 | 
			
		||||
 * want to properly emulate the m68010 or higher. (moves uses function codes
 | 
			
		||||
 * to read/write data from different address spaces)
 | 
			
		||||
 */
 | 
			
		||||
#define M68K_EMULATE_FC             OPT_OFF
 | 
			
		||||
#define M68K_SET_FC_CALLBACK(A)     cpu_set_fc(A)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* If ON, CPU will call the pc changed callback when it changes the PC by a
 | 
			
		||||
 * large value.  This allows host programs to be nicer when it comes to
 | 
			
		||||
 * fetching immediate data and instructions on a banked memory system.
 | 
			
		||||
 */
 | 
			
		||||
#define M68K_MONITOR_PC             OPT_OFF
 | 
			
		||||
#define M68K_SET_PC_CALLBACK(A)     your_pc_changed_handler_function(A)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* If ON, CPU will call the instruction hook callback before every
 | 
			
		||||
 * instruction.
 | 
			
		||||
 */
 | 
			
		||||
#define M68K_INSTRUCTION_HOOK       OPT_SPECIFY_HANDLER
 | 
			
		||||
#define M68K_INSTRUCTION_CALLBACK() cpu_instr_callback()
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* If ON, the CPU will emulate the 4-byte prefetch queue of a real 68000 */
 | 
			
		||||
#define M68K_EMULATE_PREFETCH       OPT_ON
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* If ON, the CPU will generate address error exceptions if it tries to
 | 
			
		||||
 * access a word or longword at an odd address.
 | 
			
		||||
 * NOTE: This is only emulated properly for 68000 mode.
 | 
			
		||||
 */
 | 
			
		||||
#define M68K_EMULATE_ADDRESS_ERROR  OPT_ON
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* Turn ON to enable logging of illegal instruction calls.
 | 
			
		||||
 * M68K_LOG_FILEHANDLE must be #defined to a stdio file stream.
 | 
			
		||||
 * Turn on M68K_LOG_1010_1111 to log all 1010 and 1111 calls.
 | 
			
		||||
 */
 | 
			
		||||
#define M68K_LOG_ENABLE             OPT_OFF
 | 
			
		||||
#define M68K_LOG_1010_1111          OPT_OFF
 | 
			
		||||
#define M68K_LOG_FILEHANDLE         stderr
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* ----------------------------- COMPATIBILITY ---------------------------- */
 | 
			
		||||
 | 
			
		||||
/* The following options set optimizations that violate the current ANSI
 | 
			
		||||
 * standard, but will be compliant under the forthcoming C9X standard.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* If ON, the enulation core will use 64-bit integers to speed up some
 | 
			
		||||
 * operations.
 | 
			
		||||
*/
 | 
			
		||||
#define M68K_USE_64_BIT  OPT_OFF
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* Set to your compiler's static inline keyword to enable it, or
 | 
			
		||||
 * set it to blank to disable it.
 | 
			
		||||
 * If you define INLINE in the makefile, it will override this value.
 | 
			
		||||
 * NOTE: not enabling inline functions will SEVERELY slow down emulation.
 | 
			
		||||
 */
 | 
			
		||||
#ifndef INLINE
 | 
			
		||||
//#define INLINE static __inline__
 | 
			
		||||
#define INLINE static
 | 
			
		||||
#endif /* INLINE */
 | 
			
		||||
 | 
			
		||||
#endif /* M68K_COMPILE_FOR_MAME */
 | 
			
		||||
 | 
			
		||||
#include "sim.h"
 | 
			
		||||
 | 
			
		||||
#define m68k_read_memory_8(A) cpu_read_byte(A)
 | 
			
		||||
#define m68k_read_memory_16(A) cpu_read_word(A)
 | 
			
		||||
#define m68k_read_memory_32(A) cpu_read_long(A)
 | 
			
		||||
 | 
			
		||||
#define m68k_read_disassembler_16(A) cpu_read_word_dasm(A)
 | 
			
		||||
#define m68k_read_disassembler_32(A) cpu_read_long_dasm(A)
 | 
			
		||||
 | 
			
		||||
#define m68k_write_memory_8(A, V) cpu_write_byte(A, V)
 | 
			
		||||
#define m68k_write_memory_16(A, V) cpu_write_word(A, V)
 | 
			
		||||
#define m68k_write_memory_32(A, V) cpu_write_long(A, V)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* ======================================================================== */
 | 
			
		||||
/* ============================== END OF FILE ============================= */
 | 
			
		||||
/* ======================================================================== */
 | 
			
		||||
 | 
			
		||||
#endif /* M68KCONF__HEADER */
 | 
			
		||||
							
								
								
									
										3
									
								
								plat/linux68k/emu/musashi/README.ACK.md
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								plat/linux68k/emu/musashi/README.ACK.md
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,3 @@
 | 
			
		|||
This is a copy of the Karl Stenerud's Musashi m68k emulator, available from
 | 
			
		||||
https://github.com/kstenerud/Musashi.  It's MIT licensed and so is compatible
 | 
			
		||||
with the ACK.
 | 
			
		||||
							
								
								
									
										290
									
								
								plat/linux68k/emu/musashi/example/example.txt
									
										
									
									
									
										Executable file
									
								
							
							
						
						
									
										290
									
								
								plat/linux68k/emu/musashi/example/example.txt
									
										
									
									
									
										Executable file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,290 @@
 | 
			
		|||
EXAMPLE:
 | 
			
		||||
-------
 | 
			
		||||
As an example, I'll build an imaginary hardware platform.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
The system is fairly simple, comprising a 68000, an input device, an output
 | 
			
		||||
device, a non-maskable-interrupt device, and an interrupt controller.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
The input device receives input from the user and asserts its interrupt
 | 
			
		||||
request line until its value is read.  Reading from the input device's
 | 
			
		||||
memory-mapped port will both clear its interrupt request and read an ASCII
 | 
			
		||||
representation (8 bits) of what the user entered.
 | 
			
		||||
 | 
			
		||||
The output device reads value when it is selected through its memory-mapped
 | 
			
		||||
port and outputs it to a display.  The value it reads will be interpreted as
 | 
			
		||||
an ASCII value and output to the display. The output device is fairly slow
 | 
			
		||||
(it can only process 1 byte per second), and so it asserts its interrupt
 | 
			
		||||
request line when it is ready to receive a byte.  Writing to the output device
 | 
			
		||||
sends a byte to it.  If the output device is not ready, the write is ignored.
 | 
			
		||||
Reading from the output device returns 0 and clears its interrupt request line
 | 
			
		||||
until another byte is written to it and 1 second elapses.
 | 
			
		||||
 | 
			
		||||
The non-maskable-interrupt (NMI) device, as can be surmised from the name,
 | 
			
		||||
generates a non-maskable-interrupt.  This is connected to some kind of external
 | 
			
		||||
switch that the user can push to generate a NMI.
 | 
			
		||||
 | 
			
		||||
Since there are 3 devices interrupting the CPU, an interrupt controller is
 | 
			
		||||
needed.  The interrupt controller takes 7 inputs and encodes the highest
 | 
			
		||||
priority asserted line on the 3 output pins.  the input device is wired to IN2
 | 
			
		||||
and the output device is wired to IN1 on the controller.  The NMI device is
 | 
			
		||||
wired to IN7 and all the other inputs are wired low.
 | 
			
		||||
 | 
			
		||||
The bus is also connected to a 1K ROM and a 256 byte RAM.
 | 
			
		||||
Beware: This platform places ROM and RAM in the same address range and uses
 | 
			
		||||
        the FC pins to select the correct address space!
 | 
			
		||||
        (You didn't expect me to make it easy, did you? =)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Here is the schematic in all its ASCII splendour:
 | 
			
		||||
-------------------------------------------------
 | 
			
		||||
 | 
			
		||||
     NMI     TIED
 | 
			
		||||
    SWITCH   LOW
 | 
			
		||||
      |       |
 | 
			
		||||
      | +-+-+-+
 | 
			
		||||
      | | | | | +------------------------------------------------+
 | 
			
		||||
      | | | | | | +------------------------------------+         |
 | 
			
		||||
      | | | | | | |                                    |         |
 | 
			
		||||
     +-------------+                                   |         |
 | 
			
		||||
     |7 6 5 4 3 2 1|                                   |         |
 | 
			
		||||
     |             |                                   |         |
 | 
			
		||||
     | INT CONTRLR |                                   |         |
 | 
			
		||||
     |             |                                   |         |
 | 
			
		||||
     |i i i        |                                   |         |
 | 
			
		||||
     |2 1 0        |                                   |         |
 | 
			
		||||
     +-------------+                                   |         |
 | 
			
		||||
      | | |                                            |         |
 | 
			
		||||
      | | |     +--------------------------------+--+  |         |
 | 
			
		||||
      o o o     |                                |  |  |         |
 | 
			
		||||
    +--------------+  +-------+  +----------+  +---------+  +----------+
 | 
			
		||||
    | I I I     a  |  |       |  |          |  | r  a  i |  |    i     |
 | 
			
		||||
    | 2 1 0    23  |  |       |  |          |  | e  c    |  |          |
 | 
			
		||||
    |              |  |       |  |          |  | a  k    |  |          |
 | 
			
		||||
    |              |  |       |  |          |  | d       |  |          |
 | 
			
		||||
    |              |  |       |  |          |  |         |  |          |
 | 
			
		||||
    |    M68000    |  |  ROM  |  |   RAM    |  |   IN    |  |   OUT    |
 | 
			
		||||
    |              |  |       |  |          |  |         |  |          |
 | 
			
		||||
    |            a9|--|a9     |--|          |--|         |--|          |
 | 
			
		||||
    |            a8|--|a8     |--|          |--|         |--|          |
 | 
			
		||||
    |            a7|--|a7     |--|a7        |--|         |--|          |
 | 
			
		||||
    |            a6|--|a6     |--|a6        |--|         |--|          |
 | 
			
		||||
    |            a5|--|a5     |--|a5        |--|         |--|          |
 | 
			
		||||
    |            a4|--|a4     |--|a4        |--|         |--|          |
 | 
			
		||||
    |            a3|--|a3     |--|a3        |--|         |--|          |
 | 
			
		||||
    |            a2|--|a2     |--|a2        |--|         |--|          |
 | 
			
		||||
    |            a1|--|a1     |--|a1        |--|         |--|          |
 | 
			
		||||
    |            a0|--|a0     |--|a0        |--|         |--|          |
 | 
			
		||||
    |              |  |       |  |          |  |         |  |          |
 | 
			
		||||
    |           d15|--|d15    |--|d15       |--|         |--|          |
 | 
			
		||||
    |           d14|--|d14    |--|d14       |--|         |--|          |
 | 
			
		||||
    |           d13|--|d13    |--|d13       |--|         |--|          |
 | 
			
		||||
    |           d12|--|d12    |--|d12       |--|         |--|          |
 | 
			
		||||
    |           d11|--|d11    |--|d11       |--|         |--|          |
 | 
			
		||||
    |           d10|--|d10    |--|d10       |--|         |--|          |
 | 
			
		||||
    |            d9|--|d9     |--|d9        |--|         |--|          |
 | 
			
		||||
    |            d8|--|d8     |--|d8        |--|         |--|          |
 | 
			
		||||
    |            d7|--|d7     |--|d7        |--|d7       |--|d7        |
 | 
			
		||||
    |            d6|--|d6     |--|d6        |--|d6       |--|d6        |
 | 
			
		||||
    |            d5|--|d5     |--|d5        |--|d5       |--|d5        |
 | 
			
		||||
    |            d4|--|d4     |--|d4        |--|d4       |--|d4        |
 | 
			
		||||
    |            d3|--|d3     |--|d3        |--|d3       |--|d3        |
 | 
			
		||||
    |            d2|--|d2     |--|d2        |--|d2       |--|d2        |
 | 
			
		||||
    |            d1|--|d1     |--|d1        |--|d1       |--|d1  w     |
 | 
			
		||||
    |            d0|--|d0     |--|d0        |--|d0       |--|d0  r     |
 | 
			
		||||
    |              |  |       |  |          |  |         |  |    i   a |
 | 
			
		||||
    | a      F F F |  |       |  |          |  |         |  |    t   c |
 | 
			
		||||
    |22  rW  2 1 0 |  |  cs   |  | cs   rW  |  |         |  |    e   k |
 | 
			
		||||
    +--------------+  +-------+  +----------+  +---------+  +----------+
 | 
			
		||||
      |   |  | | |        |         |    |                       |   |
 | 
			
		||||
      |   |  | | |        |         |    |                       |   |
 | 
			
		||||
      |   |  | | |    +-------+  +-----+ |                     +---+ |
 | 
			
		||||
      |   |  | | |    |  IC1  |  | IC2 | |                     |AND| |
 | 
			
		||||
      |   |  | | |    |a b c d|  |a b c| |                     +---+ |
 | 
			
		||||
      |   |  | | |    +-------+  +-----+ |                      | |  |
 | 
			
		||||
      |   |  | | |     | | | |    | | |  |                      | +--+
 | 
			
		||||
      |   |  | | |     | | | |    | | |  |                      | |
 | 
			
		||||
      |   |  | | |     | | | |    | | |  |                      | |
 | 
			
		||||
      |   |  | | |     | | | |    | | |  |                      | |
 | 
			
		||||
      |   |  | | +-----)-)-+-)----)-)-+  |                      | |
 | 
			
		||||
      |   |  | +-------)-+---)----)-+    |                      | |
 | 
			
		||||
      |   |  +---------+-----)----+      |                      | |
 | 
			
		||||
      |   |                  |           |                      | |
 | 
			
		||||
      |   +------------------+-----------+----------------------+ |
 | 
			
		||||
      |                                                           |
 | 
			
		||||
      +-----------------------------------------------------------+
 | 
			
		||||
 | 
			
		||||
IC1: output=1 if a=0 and b=1 and c=0 and d=0
 | 
			
		||||
IC2: output=1 if a=0 and b=0 and c=1
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Here is the listing for program.bin:
 | 
			
		||||
-----------------------------------
 | 
			
		||||
 | 
			
		||||
                        INPUT_ADDRESS   equ $800000
 | 
			
		||||
                        OUTPUT_ADDRESS  equ $400000
 | 
			
		||||
                        CIRCULAR_BUFFER equ $c0
 | 
			
		||||
                        CAN_OUTPUT      equ $d0
 | 
			
		||||
                        STACK_AREA      equ $100
 | 
			
		||||
                        
 | 
			
		||||
                        vector_table:
 | 
			
		||||
00000000 0000 0100      	dc.l STACK_AREA				*  0: SP
 | 
			
		||||
00000004 0000 00c0      	dc.l init					*  1: PC
 | 
			
		||||
00000008 0000 0148      	dc.l unhandled_exception	*  2: bus error
 | 
			
		||||
0000000c 0000 0148      	dc.l unhandled_exception	*  3: address error
 | 
			
		||||
00000010 0000 0148      	dc.l unhandled_exception	*  4: illegal instruction
 | 
			
		||||
00000014 0000 0148      	dc.l unhandled_exception	*  5: zero divide
 | 
			
		||||
00000018 0000 0148      	dc.l unhandled_exception	*  6: chk
 | 
			
		||||
0000001c 0000 0148      	dc.l unhandled_exception	*  7: trapv
 | 
			
		||||
00000020 0000 0148      	dc.l unhandled_exception	*  8: privilege violation
 | 
			
		||||
00000024 0000 0148      	dc.l unhandled_exception	*  9: trace
 | 
			
		||||
00000028 0000 0148      	dc.l unhandled_exception	* 10: 1010
 | 
			
		||||
0000002c 0000 0148      	dc.l unhandled_exception	* 11: 1111
 | 
			
		||||
00000030 0000 0148      	dc.l unhandled_exception	* 12: -
 | 
			
		||||
00000034 0000 0148      	dc.l unhandled_exception	* 13: -
 | 
			
		||||
00000038 0000 0148      	dc.l unhandled_exception	* 14: -
 | 
			
		||||
0000003c 0000 0148      	dc.l unhandled_exception	* 15: uninitialized interrupt
 | 
			
		||||
00000040 0000 0148      	dc.l unhandled_exception	* 16: -
 | 
			
		||||
00000044 0000 0148      	dc.l unhandled_exception	* 17: -
 | 
			
		||||
00000048 0000 0148      	dc.l unhandled_exception	* 18: -
 | 
			
		||||
0000004c 0000 0148      	dc.l unhandled_exception	* 19: -
 | 
			
		||||
00000050 0000 0148      	dc.l unhandled_exception	* 20: -
 | 
			
		||||
00000054 0000 0148      	dc.l unhandled_exception	* 21: -
 | 
			
		||||
00000058 0000 0148      	dc.l unhandled_exception	* 22: -
 | 
			
		||||
0000005c 0000 0148      	dc.l unhandled_exception	* 23: -
 | 
			
		||||
00000060 0000 0148      	dc.l unhandled_exception	* 24: spurious interrupt
 | 
			
		||||
00000064 0000 0136      	dc.l output_ready			* 25: l1 irq
 | 
			
		||||
00000068 0000 010e      	dc.l input_ready			* 26: l2 irq
 | 
			
		||||
0000006c 0000 0148      	dc.l unhandled_exception	* 27: l3 irq
 | 
			
		||||
00000070 0000 0148      	dc.l unhandled_exception	* 28: l4 irq
 | 
			
		||||
00000074 0000 0148      	dc.l unhandled_exception	* 29: l5 irq
 | 
			
		||||
00000078 0000 0148      	dc.l unhandled_exception	* 30: l6 irq
 | 
			
		||||
0000007c 0000 014e      	dc.l nmi					* 31: l7 irq
 | 
			
		||||
00000080 0000 0148      	dc.l unhandled_exception	* 32: trap 0
 | 
			
		||||
00000084 0000 0148      	dc.l unhandled_exception	* 33: trap 1
 | 
			
		||||
00000088 0000 0148      	dc.l unhandled_exception	* 34: trap 2
 | 
			
		||||
0000008c 0000 0148      	dc.l unhandled_exception	* 35: trap 3
 | 
			
		||||
00000090 0000 0148      	dc.l unhandled_exception	* 36: trap 4
 | 
			
		||||
00000094 0000 0148      	dc.l unhandled_exception	* 37: trap 5
 | 
			
		||||
00000098 0000 0148      	dc.l unhandled_exception	* 38: trap 6
 | 
			
		||||
0000009c 0000 0148      	dc.l unhandled_exception	* 39: trap 7
 | 
			
		||||
000000a0 0000 0148      	dc.l unhandled_exception	* 40: trap 8
 | 
			
		||||
000000a4 0000 0148      	dc.l unhandled_exception	* 41: trap 9
 | 
			
		||||
000000a8 0000 0148      	dc.l unhandled_exception	* 42: trap 10
 | 
			
		||||
000000ac 0000 0148      	dc.l unhandled_exception	* 43: trap 11
 | 
			
		||||
000000b0 0000 0148      	dc.l unhandled_exception	* 44: trap 12
 | 
			
		||||
000000b4 0000 0148      	dc.l unhandled_exception	* 45: trap 13
 | 
			
		||||
000000b8 0000 0148      	dc.l unhandled_exception	* 46: trap 14
 | 
			
		||||
000000bc 0000 0148      	dc.l unhandled_exception	* 47: trap 15
 | 
			
		||||
                        * This is the end of the useful part of the table.
 | 
			
		||||
                        * We will now do the Capcom thing and put code starting at $c0.
 | 
			
		||||
                        
 | 
			
		||||
                        init:
 | 
			
		||||
                        * Copy the exception vector table to RAM.
 | 
			
		||||
000000c0 227c 0000 0000 	move.l  #0, a1						* a1 is RAM index
 | 
			
		||||
000000c6 303c 002f      	move.w  #47, d0						* d0 is counter (48 vectors)
 | 
			
		||||
000000ca 41fa 0006      	lea.l   (copy_table,PC), a0			* a0 is scratch
 | 
			
		||||
000000ce 2208           	move.l  a0, d1						* d1 is ROM index
 | 
			
		||||
000000d0 4481           	neg.l   d1
 | 
			
		||||
                        copy_table:
 | 
			
		||||
000000d2 22fb 18fe      	dc.l    $22fb18fe					* stoopid as68k generates 020 code here
 | 
			
		||||
                        *	move.l  (copy_table,PC,d1.l), (a1)+
 | 
			
		||||
000000d6 5841           	addq    #4, d1
 | 
			
		||||
000000d8 51c8 fff8      	dbf     d0, copy_table
 | 
			
		||||
                        
 | 
			
		||||
                        main_init:
 | 
			
		||||
                        * Initialize main program
 | 
			
		||||
000000dc 11fc 0000 00d0 	move.b  #0, CAN_OUTPUT
 | 
			
		||||
000000e2 4df8 00c0      	lea.l   CIRCULAR_BUFFER, a6
 | 
			
		||||
000000e6 7c00           	moveq   #0, d6						* output buffer ptr
 | 
			
		||||
000000e8 7e00           	moveq   #0, d7						* input buffer ptr
 | 
			
		||||
000000ea 027c f8ff      	andi    #$f8ff, SR					* clear interrupt mask
 | 
			
		||||
                        main:
 | 
			
		||||
                        * Main program
 | 
			
		||||
000000ee 4a38 00d0      	tst.b   CAN_OUTPUT					* can we output?
 | 
			
		||||
000000f2 67fa           	beq     main
 | 
			
		||||
000000f4 be06           	cmp.b   d6, d7						* is there data?
 | 
			
		||||
000000f6 67f6           	beq     main
 | 
			
		||||
000000f8 11fc 0000 00d0 	move.b  #0, CAN_OUTPUT
 | 
			
		||||
000000fe 13f6 6000 0040 	move.b  (0,a6,d6.w), OUTPUT_ADDRESS	* write data
 | 
			
		||||
         0000
 | 
			
		||||
00000106 5246           	addq    #1, d6
 | 
			
		||||
00000108 0206 000f      	andi.b  #15, d6						* update circular buffer
 | 
			
		||||
0000010c 60e0           	bra     main
 | 
			
		||||
                        
 | 
			
		||||
                        
 | 
			
		||||
                        input_ready:
 | 
			
		||||
0000010e 2f00           	move.l  d0, -(a7)
 | 
			
		||||
00000110 2f01           	move.l  d1, -(a7)
 | 
			
		||||
00000112 1239 0080 0000 	move.b  INPUT_ADDRESS, d1			* read data
 | 
			
		||||
00000118 1007           	move.b  d7, d0						* check if buffer full
 | 
			
		||||
0000011a 5240           	addq    #1, d0
 | 
			
		||||
0000011c 0200 000f      	andi.b  #15, d0
 | 
			
		||||
00000120 bc00           	cmp.b   d0, d6
 | 
			
		||||
00000122 6700 000c      	beq     input_ready_quit			* throw away if full
 | 
			
		||||
00000126 1d81 7000      	move.b  d1, (0,a6,d7.w)				* store the data
 | 
			
		||||
0000012a 5247           	addq    #1, d7
 | 
			
		||||
0000012c 0207 000f      	andi.b  #15, d7						* update circular buffer
 | 
			
		||||
                        input_ready_quit:
 | 
			
		||||
00000130 221f           	move.l  (a7)+, d1
 | 
			
		||||
00000132 201f           	move.l  (a7)+, d0
 | 
			
		||||
00000134 4e73           	rte
 | 
			
		||||
                        
 | 
			
		||||
                        output_ready:
 | 
			
		||||
00000136 2f00           	move.l  d0, -(a7)
 | 
			
		||||
00000138 11fc 0001 00d0 	move.b  #1, CAN_OUTPUT
 | 
			
		||||
0000013e 1039 0040 0000 	move.b  OUTPUT_ADDRESS, d0			* acknowledge the interrupt
 | 
			
		||||
00000144 201f           	move.l  (a7)+, d0
 | 
			
		||||
00000146 4e73           	rte
 | 
			
		||||
                        
 | 
			
		||||
                        unhandled_exception:
 | 
			
		||||
00000148 4e72 2700      	stop	#$2700						* wait for NMI
 | 
			
		||||
0000014c 60fa           	bra     unhandled_exception			* shouldn't get here
 | 
			
		||||
                        
 | 
			
		||||
                        nmi:
 | 
			
		||||
                        * perform a soft reset
 | 
			
		||||
0000014e 46fc 2700      	move    #$2700, SR					* set status register
 | 
			
		||||
00000152 2e7a feac      	move.l  (vector_table,PC), a7		* reset stack pointer
 | 
			
		||||
00000156 4e70           	reset								* reset peripherals
 | 
			
		||||
00000158 4efa feaa      	jmp     (vector_table+4,PC)			* reset program counter
 | 
			
		||||
                        
 | 
			
		||||
                        END
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Compiling the example host environment:
 | 
			
		||||
--------------------------------------
 | 
			
		||||
 | 
			
		||||
I've only put in an os-dependant portion for dos/windows, so you'll either
 | 
			
		||||
have to compile for that system or make your own osd code based on osd_dos.c
 | 
			
		||||
and modify the makefile accordingly.
 | 
			
		||||
 | 
			
		||||
I compiled this example using the compiler from mingw (www.mingw.org) but you
 | 
			
		||||
could also use djgpp (www.delorie.com).
 | 
			
		||||
 | 
			
		||||
- Copy the m68k files to a directory.  Then extract the files from example.zip to
 | 
			
		||||
  the same directory, overwriting m68kconf.h.  program.bin is the actual 68000
 | 
			
		||||
  program you will be running.
 | 
			
		||||
- Make your own osd_get_key() in the same fashion as in osd_dos.c if you're not
 | 
			
		||||
  compiling for dos/windows.
 | 
			
		||||
- Type make
 | 
			
		||||
- Perform the necessary animal sacrifices.
 | 
			
		||||
- Type sim program.bin
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Keys:
 | 
			
		||||
	ESC           - quits the simulator
 | 
			
		||||
	~             - generates an NMI interrupt
 | 
			
		||||
	Any other key - Genearate input for the input device
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Note: I've cheated a bit in the emulation.  There is no speed control
 | 
			
		||||
      to set the speed the CPU runs at; it simply runs as fast as your
 | 
			
		||||
      processor can run it.
 | 
			
		||||
      To add speed control, you will need a high-precision timestamp
 | 
			
		||||
      function (like the RDTSC instruction for newer Pentium CPUs)
 | 
			
		||||
      and a bit of arithmetic to make the cycles argument for m68k_execute().
 | 
			
		||||
      I'll leave that as an excercise to the reader.
 | 
			
		||||
							
								
								
									
										192
									
								
								plat/linux68k/emu/musashi/example/m68kconf.h
									
										
									
									
									
										Executable file
									
								
							
							
						
						
									
										192
									
								
								plat/linux68k/emu/musashi/example/m68kconf.h
									
										
									
									
									
										Executable file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,192 @@
 | 
			
		|||
/* ======================================================================== */
 | 
			
		||||
/* ========================= LICENSING & COPYRIGHT ======================== */
 | 
			
		||||
/* ======================================================================== */
 | 
			
		||||
/*
 | 
			
		||||
 *                                  MUSASHI
 | 
			
		||||
 *                                Version 3.4
 | 
			
		||||
 *
 | 
			
		||||
 * A portable Motorola M680x0 processor emulation engine.
 | 
			
		||||
 * Copyright 1998-2001 Karl Stenerud.  All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * This code may be freely used for non-commercial purposes as long as this
 | 
			
		||||
 * copyright notice remains unaltered in the source code and any binary files
 | 
			
		||||
 * containing this code in compiled form.
 | 
			
		||||
 *
 | 
			
		||||
 * All other lisencing terms must be negotiated with the author
 | 
			
		||||
 * (Karl Stenerud).
 | 
			
		||||
 *
 | 
			
		||||
 * The latest version of this code can be obtained at:
 | 
			
		||||
 * http://kstenerud.cjb.net
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#ifndef M68KCONF__HEADER
 | 
			
		||||
#define M68KCONF__HEADER
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* Configuration switches.
 | 
			
		||||
 * Use OPT_SPECIFY_HANDLER for configuration options that allow callbacks.
 | 
			
		||||
 * OPT_SPECIFY_HANDLER causes the core to link directly to the function
 | 
			
		||||
 * or macro you specify, rather than using callback functions whose pointer
 | 
			
		||||
 * must be passed in using m68k_set_xxx_callback().
 | 
			
		||||
 */
 | 
			
		||||
#define OPT_OFF             0
 | 
			
		||||
#define OPT_ON              1
 | 
			
		||||
#define OPT_SPECIFY_HANDLER 2
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* ======================================================================== */
 | 
			
		||||
/* ============================== MAME STUFF ============================== */
 | 
			
		||||
/* ======================================================================== */
 | 
			
		||||
 | 
			
		||||
/* If you're compiling this for MAME, only change M68K_COMPILE_FOR_MAME
 | 
			
		||||
 * to OPT_ON and use m68kmame.h to configure the 68k core.
 | 
			
		||||
 */
 | 
			
		||||
#ifndef M68K_COMPILE_FOR_MAME
 | 
			
		||||
#define M68K_COMPILE_FOR_MAME      OPT_OFF
 | 
			
		||||
#endif /* M68K_COMPILE_FOR_MAME */
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#if M68K_COMPILE_FOR_MAME == OPT_OFF
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* ======================================================================== */
 | 
			
		||||
/* ============================= CONFIGURATION ============================ */
 | 
			
		||||
/* ======================================================================== */
 | 
			
		||||
 | 
			
		||||
/* Turn ON if you want to use the following M68K variants */
 | 
			
		||||
#define M68K_EMULATE_010            OPT_ON
 | 
			
		||||
#define M68K_EMULATE_EC020          OPT_ON
 | 
			
		||||
#define M68K_EMULATE_020            OPT_ON
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* If ON, the CPU will call m68k_read_immediate_xx() for immediate addressing
 | 
			
		||||
 * and m68k_read_pcrelative_xx() for PC-relative addressing.
 | 
			
		||||
 * If off, all read requests from the CPU will be redirected to m68k_read_xx()
 | 
			
		||||
 */
 | 
			
		||||
#define M68K_SEPARATE_READS         OPT_OFF
 | 
			
		||||
 | 
			
		||||
/* If ON, the CPU will call m68k_write_32_pd() when it executes move.l with a
 | 
			
		||||
 * predecrement destination EA mode instead of m68k_write_32().
 | 
			
		||||
 * To simulate real 68k behavior, m68k_write_32_pd() must first write the high
 | 
			
		||||
 * word to [address+2], and then write the low word to [address].
 | 
			
		||||
 */
 | 
			
		||||
#define M68K_SIMULATE_PD_WRITES     OPT_OFF
 | 
			
		||||
 | 
			
		||||
/* If ON, CPU will call the interrupt acknowledge callback when it services an
 | 
			
		||||
 * interrupt.
 | 
			
		||||
 * If off, all interrupts will be autovectored and all interrupt requests will
 | 
			
		||||
 * auto-clear when the interrupt is serviced.
 | 
			
		||||
 */
 | 
			
		||||
#define M68K_EMULATE_INT_ACK        OPT_SPECIFY_HANDLER
 | 
			
		||||
#define M68K_INT_ACK_CALLBACK(A)    cpu_irq_ack(A)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* If ON, CPU will call the breakpoint acknowledge callback when it encounters
 | 
			
		||||
 * a breakpoint instruction and it is running a 68010+.
 | 
			
		||||
 */
 | 
			
		||||
#define M68K_EMULATE_BKPT_ACK       OPT_OFF
 | 
			
		||||
#define M68K_BKPT_ACK_CALLBACK()    your_bkpt_ack_handler_function()
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* If ON, the CPU will monitor the trace flags and take trace exceptions
 | 
			
		||||
 */
 | 
			
		||||
#define M68K_EMULATE_TRACE          OPT_OFF
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* If ON, CPU will call the output reset callback when it encounters a reset
 | 
			
		||||
 * instruction.
 | 
			
		||||
 */
 | 
			
		||||
#define M68K_EMULATE_RESET          OPT_SPECIFY_HANDLER
 | 
			
		||||
#define M68K_RESET_CALLBACK()       cpu_pulse_reset()
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* If ON, CPU will call the set fc callback on every memory access to
 | 
			
		||||
 * differentiate between user/supervisor, program/data access like a real
 | 
			
		||||
 * 68000 would.  This should be enabled and the callback should be set if you
 | 
			
		||||
 * want to properly emulate the m68010 or higher. (moves uses function codes
 | 
			
		||||
 * to read/write data from different address spaces)
 | 
			
		||||
 */
 | 
			
		||||
#define M68K_EMULATE_FC             OPT_SPECIFY_HANDLER
 | 
			
		||||
#define M68K_SET_FC_CALLBACK(A)     cpu_set_fc(A)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* If ON, CPU will call the pc changed callback when it changes the PC by a
 | 
			
		||||
 * large value.  This allows host programs to be nicer when it comes to
 | 
			
		||||
 * fetching immediate data and instructions on a banked memory system.
 | 
			
		||||
 */
 | 
			
		||||
#define M68K_MONITOR_PC             OPT_OFF
 | 
			
		||||
#define M68K_SET_PC_CALLBACK(A)     your_pc_changed_handler_function(A)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* If ON, CPU will call the instruction hook callback before every
 | 
			
		||||
 * instruction.
 | 
			
		||||
 */
 | 
			
		||||
#define M68K_INSTRUCTION_HOOK       OPT_SPECIFY_HANDLER
 | 
			
		||||
#define M68K_INSTRUCTION_CALLBACK() cpu_instr_callback()
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* If ON, the CPU will emulate the 4-byte prefetch queue of a real 68000 */
 | 
			
		||||
#define M68K_EMULATE_PREFETCH       OPT_ON
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* If ON, the CPU will generate address error exceptions if it tries to
 | 
			
		||||
 * access a word or longword at an odd address.
 | 
			
		||||
 * NOTE: This is only emulated properly for 68000 mode.
 | 
			
		||||
 */
 | 
			
		||||
#define M68K_EMULATE_ADDRESS_ERROR  OPT_ON
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* Turn ON to enable logging of illegal instruction calls.
 | 
			
		||||
 * M68K_LOG_FILEHANDLE must be #defined to a stdio file stream.
 | 
			
		||||
 * Turn on M68K_LOG_1010_1111 to log all 1010 and 1111 calls.
 | 
			
		||||
 */
 | 
			
		||||
#define M68K_LOG_ENABLE             OPT_OFF
 | 
			
		||||
#define M68K_LOG_1010_1111          OPT_OFF
 | 
			
		||||
#define M68K_LOG_FILEHANDLE         some_file_handle
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* ----------------------------- COMPATIBILITY ---------------------------- */
 | 
			
		||||
 | 
			
		||||
/* The following options set optimizations that violate the current ANSI
 | 
			
		||||
 * standard, but will be compliant under the forthcoming C9X standard.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* If ON, the enulation core will use 64-bit integers to speed up some
 | 
			
		||||
 * operations.
 | 
			
		||||
*/
 | 
			
		||||
#define M68K_USE_64_BIT  OPT_OFF
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* Set to your compiler's static inline keyword to enable it, or
 | 
			
		||||
 * set it to blank to disable it.
 | 
			
		||||
 * If you define INLINE in the makefile, it will override this value.
 | 
			
		||||
 * NOTE: not enabling inline functions will SEVERELY slow down emulation.
 | 
			
		||||
 */
 | 
			
		||||
#ifndef INLINE
 | 
			
		||||
#define INLINE static __inline__
 | 
			
		||||
#endif /* INLINE */
 | 
			
		||||
 | 
			
		||||
#endif /* M68K_COMPILE_FOR_MAME */
 | 
			
		||||
 | 
			
		||||
#include "sim.h"
 | 
			
		||||
 | 
			
		||||
#define m68k_read_memory_8(A) cpu_read_byte(A)
 | 
			
		||||
#define m68k_read_memory_16(A) cpu_read_word(A)
 | 
			
		||||
#define m68k_read_memory_32(A) cpu_read_long(A)
 | 
			
		||||
 | 
			
		||||
#define m68k_read_disassembler_16(A) cpu_read_word_dasm(A)
 | 
			
		||||
#define m68k_read_disassembler_32(A) cpu_read_long_dasm(A)
 | 
			
		||||
 | 
			
		||||
#define m68k_write_memory_8(A, V) cpu_write_byte(A, V)
 | 
			
		||||
#define m68k_write_memory_16(A, V) cpu_write_word(A, V)
 | 
			
		||||
#define m68k_write_memory_32(A, V) cpu_write_long(A, V)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* ======================================================================== */
 | 
			
		||||
/* ============================== END OF FILE ============================= */
 | 
			
		||||
/* ======================================================================== */
 | 
			
		||||
 | 
			
		||||
#endif /* M68KCONF__HEADER */
 | 
			
		||||
							
								
								
									
										42
									
								
								plat/linux68k/emu/musashi/example/makefile
									
										
									
									
									
										Executable file
									
								
							
							
						
						
									
										42
									
								
								plat/linux68k/emu/musashi/example/makefile
									
										
									
									
									
										Executable file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,42 @@
 | 
			
		|||
EXENAME          = sim
 | 
			
		||||
 | 
			
		||||
OSD_DOS          = osd_dos.c
 | 
			
		||||
 | 
			
		||||
OSDFILES         = $(OSD_DOS)
 | 
			
		||||
MAINFILES        = sim.c
 | 
			
		||||
MUSASHIFILES     = m68kcpu.c m68kdasm.c
 | 
			
		||||
MUSASHIGENCFILES = m68kops.c m68kopac.c m68kopdm.c m68kopnz.c
 | 
			
		||||
MUSASHIGENHFILES = m68kops.h
 | 
			
		||||
MUSASHIGENERATOR = m68kmake
 | 
			
		||||
 | 
			
		||||
EXE = .exe
 | 
			
		||||
EXEPATH = .\\
 | 
			
		||||
# EXE =
 | 
			
		||||
# EXEPATH = ./
 | 
			
		||||
 | 
			
		||||
.CFILES   = $(MAINFILES) $(OSDFILES) $(MUSASHIFILES) $(MUSASHIGENCFILES)
 | 
			
		||||
.OFILES   = $(.CFILES:%.c=%.o)
 | 
			
		||||
 | 
			
		||||
CC        = gcc
 | 
			
		||||
WARNINGS  = -Wall -pedantic
 | 
			
		||||
CFLAGS    = $(WARNINGS)
 | 
			
		||||
LFLAGS    = $(WARNINGS)
 | 
			
		||||
 | 
			
		||||
TARGET = $(EXENAME)$(EXE)
 | 
			
		||||
 | 
			
		||||
DELETEFILES = $(MUSASHIGENCFILES) $(MUSASHIGENHFILES) $(.OFILES) $(TARGET) $(MUSASHIGENERATOR)$(EXE)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
all: $(TARGET)
 | 
			
		||||
 | 
			
		||||
clean:
 | 
			
		||||
	rm -f $(DELETEFILES)
 | 
			
		||||
 | 
			
		||||
$(TARGET): $(MUSASHIGENHFILES) $(.OFILES) makefile
 | 
			
		||||
	$(CC) -o $@ $(.OFILES) $(LFLAGS)
 | 
			
		||||
 | 
			
		||||
$(MUSASHIGENCFILES) $(MUSASHIGENHFILES): $(MUSASHIGENERATOR)$(EXE)
 | 
			
		||||
	$(EXEPATH)$(MUSASHIGENERATOR)$(EXE)
 | 
			
		||||
 | 
			
		||||
$(MUSASHIGENERATOR)$(EXE):  $(MUSASHIGENERATOR).c
 | 
			
		||||
	$(CC) -o  $(MUSASHIGENERATOR)$(EXE)  $(MUSASHIGENERATOR).c
 | 
			
		||||
							
								
								
									
										6
									
								
								plat/linux68k/emu/musashi/example/osd.h
									
										
									
									
									
										Executable file
									
								
							
							
						
						
									
										6
									
								
								plat/linux68k/emu/musashi/example/osd.h
									
										
									
									
									
										Executable file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,6 @@
 | 
			
		|||
#ifndef HEADER__OSD
 | 
			
		||||
#define HEADER__OSD
 | 
			
		||||
 | 
			
		||||
int osd_get_char(void);
 | 
			
		||||
 | 
			
		||||
#endif /* HEADER__OSD */
 | 
			
		||||
							
								
								
									
										16
									
								
								plat/linux68k/emu/musashi/example/osd_dos.c
									
										
									
									
									
										Executable file
									
								
							
							
						
						
									
										16
									
								
								plat/linux68k/emu/musashi/example/osd_dos.c
									
										
									
									
									
										Executable file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,16 @@
 | 
			
		|||
#include "osd.h"
 | 
			
		||||
 | 
			
		||||
/* OS-dependant code to get a character from the user.
 | 
			
		||||
 * This function must not block, and must either return an ASCII code or -1.
 | 
			
		||||
 */
 | 
			
		||||
#include <conio.h>
 | 
			
		||||
int osd_get_char(void)
 | 
			
		||||
{
 | 
			
		||||
	int ch = -1;
 | 
			
		||||
	if(kbhit())
 | 
			
		||||
	{
 | 
			
		||||
		while(kbhit())
 | 
			
		||||
			ch = getch();
 | 
			
		||||
	}
 | 
			
		||||
	return ch;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										
											BIN
										
									
								
								plat/linux68k/emu/musashi/example/program.bin
									
										
									
									
									
										Executable file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								plat/linux68k/emu/musashi/example/program.bin
									
										
									
									
									
										Executable file
									
								
							
										
											Binary file not shown.
										
									
								
							| 
		 After Width: | Height: | Size: 348 B  | 
							
								
								
									
										561
									
								
								plat/linux68k/emu/musashi/example/sim.c
									
										
									
									
									
										Executable file
									
								
							
							
						
						
									
										561
									
								
								plat/linux68k/emu/musashi/example/sim.c
									
										
									
									
									
										Executable file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,561 @@
 | 
			
		|||
#include <stdio.h>
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include <stdarg.h>
 | 
			
		||||
#include <time.h>
 | 
			
		||||
#include "sim.h"
 | 
			
		||||
#include "m68k.h"
 | 
			
		||||
#include "osd.h"
 | 
			
		||||
 | 
			
		||||
void disassemble_program();
 | 
			
		||||
 | 
			
		||||
/* Memory-mapped IO ports */
 | 
			
		||||
#define INPUT_ADDRESS 0x800000
 | 
			
		||||
#define OUTPUT_ADDRESS 0x400000
 | 
			
		||||
 | 
			
		||||
/* IRQ connections */
 | 
			
		||||
#define IRQ_NMI_DEVICE 7
 | 
			
		||||
#define IRQ_INPUT_DEVICE 2
 | 
			
		||||
#define IRQ_OUTPUT_DEVICE 1
 | 
			
		||||
 | 
			
		||||
/* Time between characters sent to output device (seconds) */
 | 
			
		||||
#define OUTPUT_DEVICE_PERIOD 1
 | 
			
		||||
 | 
			
		||||
/* ROM and RAM sizes */
 | 
			
		||||
#define MAX_ROM 0xfff
 | 
			
		||||
#define MAX_RAM 0xff
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* Read/write macros */
 | 
			
		||||
#define READ_BYTE(BASE, ADDR) (BASE)[ADDR]
 | 
			
		||||
#define READ_WORD(BASE, ADDR) (((BASE)[ADDR]<<8) |			\
 | 
			
		||||
							  (BASE)[(ADDR)+1])
 | 
			
		||||
#define READ_LONG(BASE, ADDR) (((BASE)[ADDR]<<24) |			\
 | 
			
		||||
							  ((BASE)[(ADDR)+1]<<16) |		\
 | 
			
		||||
							  ((BASE)[(ADDR)+2]<<8) |		\
 | 
			
		||||
							  (BASE)[(ADDR)+3])
 | 
			
		||||
 | 
			
		||||
#define WRITE_BYTE(BASE, ADDR, VAL) (BASE)[ADDR] = (VAL)&0xff
 | 
			
		||||
#define WRITE_WORD(BASE, ADDR, VAL) (BASE)[ADDR] = ((VAL)>>8) & 0xff;		\
 | 
			
		||||
									(BASE)[(ADDR)+1] = (VAL)&0xff
 | 
			
		||||
#define WRITE_LONG(BASE, ADDR, VAL) (BASE)[ADDR] = ((VAL)>>24) & 0xff;		\
 | 
			
		||||
									(BASE)[(ADDR)+1] = ((VAL)>>16)&0xff;	\
 | 
			
		||||
									(BASE)[(ADDR)+2] = ((VAL)>>8)&0xff;		\
 | 
			
		||||
									(BASE)[(ADDR)+3] = (VAL)&0xff
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* Prototypes */
 | 
			
		||||
void exit_error(char* fmt, ...);
 | 
			
		||||
 | 
			
		||||
unsigned int cpu_read_byte(unsigned int address);
 | 
			
		||||
unsigned int cpu_read_word(unsigned int address);
 | 
			
		||||
unsigned int cpu_read_long(unsigned int address);
 | 
			
		||||
void cpu_write_byte(unsigned int address, unsigned int value);
 | 
			
		||||
void cpu_write_word(unsigned int address, unsigned int value);
 | 
			
		||||
void cpu_write_long(unsigned int address, unsigned int value);
 | 
			
		||||
void cpu_pulse_reset(void);
 | 
			
		||||
void cpu_set_fc(unsigned int fc);
 | 
			
		||||
int cpu_irq_ack(int level);
 | 
			
		||||
 | 
			
		||||
void nmi_device_reset(void);
 | 
			
		||||
void nmi_device_update(void);
 | 
			
		||||
int nmi_device_ack(void);
 | 
			
		||||
 | 
			
		||||
void input_device_reset(void);
 | 
			
		||||
void input_device_update(void);
 | 
			
		||||
int input_device_ack(void);
 | 
			
		||||
unsigned int input_device_read(void);
 | 
			
		||||
void input_device_write(unsigned int value);
 | 
			
		||||
 | 
			
		||||
void output_device_reset(void);
 | 
			
		||||
void output_device_update(void);
 | 
			
		||||
int output_device_ack(void);
 | 
			
		||||
unsigned int output_device_read(void);
 | 
			
		||||
void output_device_write(unsigned int value);
 | 
			
		||||
 | 
			
		||||
void int_controller_set(unsigned int value);
 | 
			
		||||
void int_controller_clear(unsigned int value);
 | 
			
		||||
 | 
			
		||||
void get_user_input(void);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* Data */
 | 
			
		||||
unsigned int g_quit = 0;                        /* 1 if we want to quit */
 | 
			
		||||
unsigned int g_nmi = 0;                         /* 1 if nmi pending */
 | 
			
		||||
 | 
			
		||||
int          g_input_device_value = -1;         /* Current value in input device */
 | 
			
		||||
 | 
			
		||||
unsigned int g_output_device_ready = 0;         /* 1 if output device is ready */
 | 
			
		||||
time_t       g_output_device_last_output;       /* Time of last char output */
 | 
			
		||||
 | 
			
		||||
unsigned int g_int_controller_pending = 0;      /* list of pending interrupts */
 | 
			
		||||
unsigned int g_int_controller_highest_int = 0;  /* Highest pending interrupt */
 | 
			
		||||
 | 
			
		||||
unsigned char g_rom[MAX_ROM+1];                 /* ROM */
 | 
			
		||||
unsigned char g_ram[MAX_RAM+1];                 /* RAM */
 | 
			
		||||
unsigned int  g_fc;                             /* Current function code from CPU */
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* Exit with an error message.  Use printf syntax. */
 | 
			
		||||
void exit_error(char* fmt, ...)
 | 
			
		||||
{
 | 
			
		||||
	static int guard_val = 0;
 | 
			
		||||
	char buff[100];
 | 
			
		||||
	unsigned int pc;
 | 
			
		||||
	va_list args;
 | 
			
		||||
 | 
			
		||||
	if(guard_val)
 | 
			
		||||
		return;
 | 
			
		||||
	else
 | 
			
		||||
		guard_val = 1;
 | 
			
		||||
 | 
			
		||||
	va_start(args, fmt);
 | 
			
		||||
	vfprintf(stderr, fmt, args);
 | 
			
		||||
	va_end(args);
 | 
			
		||||
	fprintf(stderr, "\n");
 | 
			
		||||
	pc = m68k_get_reg(NULL, M68K_REG_PPC);
 | 
			
		||||
	m68k_disassemble(buff, pc, M68K_CPU_TYPE_68000);
 | 
			
		||||
	fprintf(stderr, "At %04x: %s\n", pc, buff);
 | 
			
		||||
 | 
			
		||||
	exit(EXIT_FAILURE);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* Read data from RAM, ROM, or a device */
 | 
			
		||||
unsigned int cpu_read_byte(unsigned int address)
 | 
			
		||||
{
 | 
			
		||||
	if(g_fc & 2)	/* Program */
 | 
			
		||||
	{
 | 
			
		||||
		if(address > MAX_ROM)
 | 
			
		||||
			exit_error("Attempted to read byte from ROM address %08x", address);
 | 
			
		||||
		return READ_BYTE(g_rom, address);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Otherwise it's data space */
 | 
			
		||||
	switch(address)
 | 
			
		||||
	{
 | 
			
		||||
		case INPUT_ADDRESS:
 | 
			
		||||
			return input_device_read();
 | 
			
		||||
		case OUTPUT_ADDRESS:
 | 
			
		||||
			return output_device_read();
 | 
			
		||||
		default:
 | 
			
		||||
			break;
 | 
			
		||||
	}
 | 
			
		||||
	if(address > MAX_RAM)
 | 
			
		||||
		exit_error("Attempted to read byte from RAM address %08x", address);
 | 
			
		||||
		return READ_BYTE(g_ram, address);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
unsigned int cpu_read_word(unsigned int address)
 | 
			
		||||
{
 | 
			
		||||
	if(g_fc & 2)	/* Program */
 | 
			
		||||
	{
 | 
			
		||||
		if(address > MAX_ROM)
 | 
			
		||||
			exit_error("Attempted to read word from ROM address %08x", address);
 | 
			
		||||
		return READ_WORD(g_rom, address);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Otherwise it's data space */
 | 
			
		||||
	switch(address)
 | 
			
		||||
	{
 | 
			
		||||
		case INPUT_ADDRESS:
 | 
			
		||||
			return input_device_read();
 | 
			
		||||
		case OUTPUT_ADDRESS:
 | 
			
		||||
			return output_device_read();
 | 
			
		||||
		default:
 | 
			
		||||
			break;
 | 
			
		||||
	}
 | 
			
		||||
	if(address > MAX_RAM)
 | 
			
		||||
		exit_error("Attempted to read word from RAM address %08x", address);
 | 
			
		||||
		return READ_WORD(g_ram, address);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
unsigned int cpu_read_long(unsigned int address)
 | 
			
		||||
{
 | 
			
		||||
	if(g_fc & 2)	/* Program */
 | 
			
		||||
	{
 | 
			
		||||
		if(address > MAX_ROM)
 | 
			
		||||
			exit_error("Attempted to read long from ROM address %08x", address);
 | 
			
		||||
		return READ_LONG(g_rom, address);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Otherwise it's data space */
 | 
			
		||||
	switch(address)
 | 
			
		||||
	{
 | 
			
		||||
		case INPUT_ADDRESS:
 | 
			
		||||
			return input_device_read();
 | 
			
		||||
		case OUTPUT_ADDRESS:
 | 
			
		||||
			return output_device_read();
 | 
			
		||||
		default:
 | 
			
		||||
			break;
 | 
			
		||||
	}
 | 
			
		||||
	if(address > MAX_RAM)
 | 
			
		||||
		exit_error("Attempted to read long from RAM address %08x", address);
 | 
			
		||||
		return READ_LONG(g_ram, address);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
unsigned int cpu_read_word_dasm(unsigned int address)
 | 
			
		||||
{
 | 
			
		||||
	if(address > MAX_ROM)
 | 
			
		||||
		exit_error("Disassembler attempted to read word from ROM address %08x", address);
 | 
			
		||||
	return READ_WORD(g_rom, address);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
unsigned int cpu_read_long_dasm(unsigned int address)
 | 
			
		||||
{
 | 
			
		||||
	if(address > MAX_ROM)
 | 
			
		||||
		exit_error("Dasm attempted to read long from ROM address %08x", address);
 | 
			
		||||
	return READ_LONG(g_rom, address);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* Write data to RAM or a device */
 | 
			
		||||
void cpu_write_byte(unsigned int address, unsigned int value)
 | 
			
		||||
{
 | 
			
		||||
	if(g_fc & 2)	/* Program */
 | 
			
		||||
		exit_error("Attempted to write %02x to ROM address %08x", value&0xff, address);
 | 
			
		||||
 | 
			
		||||
	/* Otherwise it's data space */
 | 
			
		||||
	switch(address)
 | 
			
		||||
	{
 | 
			
		||||
		case INPUT_ADDRESS:
 | 
			
		||||
			input_device_write(value&0xff);
 | 
			
		||||
			return;
 | 
			
		||||
		case OUTPUT_ADDRESS:
 | 
			
		||||
			output_device_write(value&0xff);
 | 
			
		||||
			return;
 | 
			
		||||
		default:
 | 
			
		||||
			break;
 | 
			
		||||
	}
 | 
			
		||||
	if(address > MAX_RAM)
 | 
			
		||||
		exit_error("Attempted to write %02x to RAM address %08x", value&0xff, address);
 | 
			
		||||
	WRITE_BYTE(g_ram, address, value);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void cpu_write_word(unsigned int address, unsigned int value)
 | 
			
		||||
{
 | 
			
		||||
	if(g_fc & 2)	/* Program */
 | 
			
		||||
		exit_error("Attempted to write %04x to ROM address %08x", value&0xffff, address);
 | 
			
		||||
 | 
			
		||||
	/* Otherwise it's data space */
 | 
			
		||||
	switch(address)
 | 
			
		||||
	{
 | 
			
		||||
		case INPUT_ADDRESS:
 | 
			
		||||
			input_device_write(value&0xffff);
 | 
			
		||||
			return;
 | 
			
		||||
		case OUTPUT_ADDRESS:
 | 
			
		||||
			output_device_write(value&0xffff);
 | 
			
		||||
			return;
 | 
			
		||||
		default:
 | 
			
		||||
			break;
 | 
			
		||||
	}
 | 
			
		||||
	if(address > MAX_RAM)
 | 
			
		||||
		exit_error("Attempted to write %04x to RAM address %08x", value&0xffff, address);
 | 
			
		||||
	WRITE_WORD(g_ram, address, value);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void cpu_write_long(unsigned int address, unsigned int value)
 | 
			
		||||
{
 | 
			
		||||
	if(g_fc & 2)	/* Program */
 | 
			
		||||
		exit_error("Attempted to write %08x to ROM address %08x", value, address);
 | 
			
		||||
 | 
			
		||||
	/* Otherwise it's data space */
 | 
			
		||||
	switch(address)
 | 
			
		||||
	{
 | 
			
		||||
		case INPUT_ADDRESS:
 | 
			
		||||
			input_device_write(value);
 | 
			
		||||
			return;
 | 
			
		||||
		case OUTPUT_ADDRESS:
 | 
			
		||||
			output_device_write(value);
 | 
			
		||||
			return;
 | 
			
		||||
		default:
 | 
			
		||||
			break;
 | 
			
		||||
	}
 | 
			
		||||
	if(address > MAX_RAM)
 | 
			
		||||
		exit_error("Attempted to write %08x to RAM address %08x", value, address);
 | 
			
		||||
	WRITE_LONG(g_ram, address, value);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Called when the CPU pulses the RESET line */
 | 
			
		||||
void cpu_pulse_reset(void)
 | 
			
		||||
{
 | 
			
		||||
	nmi_device_reset();
 | 
			
		||||
	output_device_reset();
 | 
			
		||||
	input_device_reset();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Called when the CPU changes the function code pins */
 | 
			
		||||
void cpu_set_fc(unsigned int fc)
 | 
			
		||||
{
 | 
			
		||||
	g_fc = fc;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Called when the CPU acknowledges an interrupt */
 | 
			
		||||
int cpu_irq_ack(int level)
 | 
			
		||||
{
 | 
			
		||||
	switch(level)
 | 
			
		||||
	{
 | 
			
		||||
		case IRQ_NMI_DEVICE:
 | 
			
		||||
			return nmi_device_ack();
 | 
			
		||||
		case IRQ_INPUT_DEVICE:
 | 
			
		||||
			return input_device_ack();
 | 
			
		||||
		case IRQ_OUTPUT_DEVICE:
 | 
			
		||||
			return output_device_ack();
 | 
			
		||||
	}
 | 
			
		||||
	return M68K_INT_ACK_SPURIOUS;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* Implementation for the NMI device */
 | 
			
		||||
void nmi_device_reset(void)
 | 
			
		||||
{
 | 
			
		||||
	g_nmi = 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void nmi_device_update(void)
 | 
			
		||||
{
 | 
			
		||||
	if(g_nmi)
 | 
			
		||||
	{
 | 
			
		||||
		g_nmi = 0;
 | 
			
		||||
		int_controller_set(IRQ_NMI_DEVICE);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int nmi_device_ack(void)
 | 
			
		||||
{
 | 
			
		||||
	printf("\nNMI\n");fflush(stdout);
 | 
			
		||||
	int_controller_clear(IRQ_NMI_DEVICE);
 | 
			
		||||
	return M68K_INT_ACK_AUTOVECTOR;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* Implementation for the input device */
 | 
			
		||||
void input_device_reset(void)
 | 
			
		||||
{
 | 
			
		||||
	g_input_device_value = -1;
 | 
			
		||||
	int_controller_clear(IRQ_INPUT_DEVICE);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void input_device_update(void)
 | 
			
		||||
{
 | 
			
		||||
	if(g_input_device_value >= 0)
 | 
			
		||||
		int_controller_set(IRQ_INPUT_DEVICE);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int input_device_ack(void)
 | 
			
		||||
{
 | 
			
		||||
	return M68K_INT_ACK_AUTOVECTOR;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
unsigned int input_device_read(void)
 | 
			
		||||
{
 | 
			
		||||
	int value = g_input_device_value > 0 ? g_input_device_value : 0;
 | 
			
		||||
	int_controller_clear(IRQ_INPUT_DEVICE);
 | 
			
		||||
	g_input_device_value = -1;
 | 
			
		||||
	return value;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void input_device_write(unsigned int value)
 | 
			
		||||
{
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* Implementation for the output device */
 | 
			
		||||
void output_device_reset(void)
 | 
			
		||||
{
 | 
			
		||||
	g_output_device_last_output = time(NULL);
 | 
			
		||||
	g_output_device_ready = 0;
 | 
			
		||||
	int_controller_clear(IRQ_OUTPUT_DEVICE);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void output_device_update(void)
 | 
			
		||||
{
 | 
			
		||||
	if(!g_output_device_ready)
 | 
			
		||||
	{
 | 
			
		||||
		if((time(NULL) - g_output_device_last_output) >= OUTPUT_DEVICE_PERIOD)
 | 
			
		||||
		{
 | 
			
		||||
			g_output_device_ready = 1;
 | 
			
		||||
			int_controller_set(IRQ_OUTPUT_DEVICE);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int output_device_ack(void)
 | 
			
		||||
{
 | 
			
		||||
	return M68K_INT_ACK_AUTOVECTOR;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
unsigned int output_device_read(void)
 | 
			
		||||
{
 | 
			
		||||
	int_controller_clear(IRQ_OUTPUT_DEVICE);
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void output_device_write(unsigned int value)
 | 
			
		||||
{
 | 
			
		||||
	char ch;
 | 
			
		||||
	if(g_output_device_ready)
 | 
			
		||||
	{
 | 
			
		||||
		ch = value & 0xff;
 | 
			
		||||
		printf("%c", ch);
 | 
			
		||||
		g_output_device_last_output = time(NULL);
 | 
			
		||||
		g_output_device_ready = 0;
 | 
			
		||||
		int_controller_clear(IRQ_OUTPUT_DEVICE);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* Implementation for the interrupt controller */
 | 
			
		||||
void int_controller_set(unsigned int value)
 | 
			
		||||
{
 | 
			
		||||
	unsigned int old_pending = g_int_controller_pending;
 | 
			
		||||
 | 
			
		||||
	g_int_controller_pending |= (1<<value);
 | 
			
		||||
 | 
			
		||||
	if(old_pending != g_int_controller_pending && value > g_int_controller_highest_int)
 | 
			
		||||
	{
 | 
			
		||||
		g_int_controller_highest_int = value;
 | 
			
		||||
		m68k_set_irq(g_int_controller_highest_int);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void int_controller_clear(unsigned int value)
 | 
			
		||||
{
 | 
			
		||||
	g_int_controller_pending &= ~(1<<value);
 | 
			
		||||
 | 
			
		||||
	for(g_int_controller_highest_int = 7;g_int_controller_highest_int > 0;g_int_controller_highest_int--)
 | 
			
		||||
		if(g_int_controller_pending & (1<<g_int_controller_highest_int))
 | 
			
		||||
			break;
 | 
			
		||||
 | 
			
		||||
	m68k_set_irq(g_int_controller_highest_int);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* Parse user input and update any devices that need user input */
 | 
			
		||||
void get_user_input(void)
 | 
			
		||||
{
 | 
			
		||||
	static int last_ch = -1;
 | 
			
		||||
	int ch = osd_get_char();
 | 
			
		||||
 | 
			
		||||
	if(ch >= 0)
 | 
			
		||||
	{
 | 
			
		||||
		switch(ch)
 | 
			
		||||
		{
 | 
			
		||||
			case 0x1b:
 | 
			
		||||
				g_quit = 1;
 | 
			
		||||
				break;
 | 
			
		||||
			case '~':
 | 
			
		||||
				if(last_ch != ch)
 | 
			
		||||
					g_nmi = 1;
 | 
			
		||||
				break;
 | 
			
		||||
			default:
 | 
			
		||||
				g_input_device_value = ch;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	last_ch = ch;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Disassembler */
 | 
			
		||||
void make_hex(char* buff, unsigned int pc, unsigned int length)
 | 
			
		||||
{
 | 
			
		||||
	char* ptr = buff;
 | 
			
		||||
 | 
			
		||||
	for(;length>0;length -= 2)
 | 
			
		||||
	{
 | 
			
		||||
		sprintf(ptr, "%04x", cpu_read_word_dasm(pc));
 | 
			
		||||
		pc += 2;
 | 
			
		||||
		ptr += 4;
 | 
			
		||||
		if(length > 2)
 | 
			
		||||
			*ptr++ = ' ';
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void disassemble_program()
 | 
			
		||||
{
 | 
			
		||||
	unsigned int pc;
 | 
			
		||||
	unsigned int instr_size;
 | 
			
		||||
	char buff[100];
 | 
			
		||||
	char buff2[100];
 | 
			
		||||
 | 
			
		||||
	pc = cpu_read_long_dasm(4);
 | 
			
		||||
 | 
			
		||||
	while(pc <= 0x16e)
 | 
			
		||||
	{
 | 
			
		||||
		instr_size = m68k_disassemble(buff, pc, M68K_CPU_TYPE_68000);
 | 
			
		||||
		make_hex(buff2, pc, instr_size);
 | 
			
		||||
		printf("%03x: %-20s: %s\n", pc, buff2, buff);
 | 
			
		||||
		pc += instr_size;
 | 
			
		||||
	}
 | 
			
		||||
	fflush(stdout);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void cpu_instr_callback()
 | 
			
		||||
{
 | 
			
		||||
/* The following code would print out instructions as they are executed */
 | 
			
		||||
/*
 | 
			
		||||
	static char buff[100];
 | 
			
		||||
	static char buff2[100];
 | 
			
		||||
	static unsigned int pc;
 | 
			
		||||
	static unsigned int instr_size;
 | 
			
		||||
 | 
			
		||||
	pc = m68k_get_reg(NULL, M68K_REG_PC);
 | 
			
		||||
	instr_size = m68k_disassemble(buff, pc, M68K_CPU_TYPE_68000);
 | 
			
		||||
	make_hex(buff2, pc, instr_size);
 | 
			
		||||
	printf("E %03x: %-20s: %s\n", pc, buff2, buff);
 | 
			
		||||
	fflush(stdout);
 | 
			
		||||
*/
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* The main loop */
 | 
			
		||||
int main(int argc, char* argv[])
 | 
			
		||||
{
 | 
			
		||||
	FILE* fhandle;
 | 
			
		||||
 | 
			
		||||
	if(argc != 2)
 | 
			
		||||
	{
 | 
			
		||||
		printf("Usage: sim <program file>\n");
 | 
			
		||||
		exit(-1);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if((fhandle = fopen(argv[1], "rb")) == NULL)
 | 
			
		||||
		exit_error("Unable to open %s", argv[1]);
 | 
			
		||||
 | 
			
		||||
	if(fread(g_rom, 1, MAX_ROM+1, fhandle) <= 0)
 | 
			
		||||
		exit_error("Error reading %s", argv[1]);
 | 
			
		||||
 | 
			
		||||
//	disassemble_program();
 | 
			
		||||
 | 
			
		||||
	m68k_init();
 | 
			
		||||
	m68k_set_cpu_type(M68K_CPU_TYPE_68000);
 | 
			
		||||
	m68k_pulse_reset();
 | 
			
		||||
	input_device_reset();
 | 
			
		||||
	output_device_reset();
 | 
			
		||||
	nmi_device_reset();
 | 
			
		||||
 | 
			
		||||
	g_quit = 0;
 | 
			
		||||
	while(!g_quit)
 | 
			
		||||
	{
 | 
			
		||||
		// Our loop requires some interleaving to allow us to update the
 | 
			
		||||
		// input, output, and nmi devices.
 | 
			
		||||
 | 
			
		||||
		get_user_input();
 | 
			
		||||
 | 
			
		||||
		// Values to execute determine the interleave rate.
 | 
			
		||||
		// Smaller values allow for more accurate interleaving with multiple
 | 
			
		||||
		// devices/CPUs but is more processor intensive.
 | 
			
		||||
		// 100000 is usually a good value to start at, then work from there.
 | 
			
		||||
 | 
			
		||||
		// Note that I am not emulating the correct clock speed!
 | 
			
		||||
		m68k_execute(100000);
 | 
			
		||||
		output_device_update();
 | 
			
		||||
		input_device_update();
 | 
			
		||||
		nmi_device_update();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										15
									
								
								plat/linux68k/emu/musashi/example/sim.h
									
										
									
									
									
										Executable file
									
								
							
							
						
						
									
										15
									
								
								plat/linux68k/emu/musashi/example/sim.h
									
										
									
									
									
										Executable file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,15 @@
 | 
			
		|||
#ifndef SIM__HEADER
 | 
			
		||||
#define SIM__HEADER
 | 
			
		||||
 | 
			
		||||
unsigned int cpu_read_byte(unsigned int address);
 | 
			
		||||
unsigned int cpu_read_word(unsigned int address);
 | 
			
		||||
unsigned int cpu_read_long(unsigned int address);
 | 
			
		||||
void cpu_write_byte(unsigned int address, unsigned int value);
 | 
			
		||||
void cpu_write_word(unsigned int address, unsigned int value);
 | 
			
		||||
void cpu_write_long(unsigned int address, unsigned int value);
 | 
			
		||||
void cpu_pulse_reset(void);
 | 
			
		||||
void cpu_set_fc(unsigned int fc);
 | 
			
		||||
int  cpu_irq_ack(int level);
 | 
			
		||||
void cpu_instr_callback();
 | 
			
		||||
 | 
			
		||||
#endif /* SIM__HEADER */
 | 
			
		||||
							
								
								
									
										115
									
								
								plat/linux68k/emu/musashi/history.txt
									
										
									
									
									
										Executable file
									
								
							
							
						
						
									
										115
									
								
								plat/linux68k/emu/musashi/history.txt
									
										
									
									
									
										Executable file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,115 @@
 | 
			
		|||
The history of Musashi for anyone who might be interested:
 | 
			
		||||
---------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
Musashi was born out of sheer boredom.
 | 
			
		||||
I needed something to code, and so having had fun with a few of the emulators
 | 
			
		||||
around, I decided to try my hand at CPU emulation.
 | 
			
		||||
I had owned an Amiga for many years and had done some assembly coding on it so
 | 
			
		||||
I figured it would be the ideal chip to cut my teeth on.
 | 
			
		||||
Had I known then how much work was involved in emulating a chip like this, I
 | 
			
		||||
may not have even started ;-)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
15-Jul-2013: Musashi license changed to MIT.
 | 
			
		||||
 | 
			
		||||
10-Jun-2002: Musashi 3.4 released
 | 
			
		||||
             - Added various undocumented m68k features thanks to Bart
 | 
			
		||||
               Trzynadlowski's experiments.
 | 
			
		||||
               See http://dynarec.com/~bart/files/68knotes.txt for details.
 | 
			
		||||
             - Fixed a bug that caused privilege violation and illegal
 | 
			
		||||
               instruction exceptions to stack the wrong PC value.
 | 
			
		||||
             - Added emulation of address errors (Note: this only works
 | 
			
		||||
               in 68000 mode.  All other CPUs require a LOT of overhead
 | 
			
		||||
               to emulate this.  I'm not sure if I'll implement them or not.
 | 
			
		||||
 | 
			
		||||
27-Jan-2001: Musashi 3.3 released
 | 
			
		||||
             - Fixed problem when displaying negative numbers in disassembler
 | 
			
		||||
             - Fixed cpu type selector - was allowing 020 instructions to be
 | 
			
		||||
               disassembled when in 000 mode.
 | 
			
		||||
             - Fixed opcode jumptable generator (ambiguous operators in the
 | 
			
		||||
               test for f-line ops)
 | 
			
		||||
             - Fixed signed/unsigned problem in divl and mull opcodes (not
 | 
			
		||||
               sure if this was causing an error but best to be sure)
 | 
			
		||||
             - Cleaned up the naming scheme for the opcode handlers
 | 
			
		||||
 | 
			
		||||
14-Aug-2000: Musashi 3.2 released
 | 
			
		||||
             - Fixed RTE bug that killed the program counter when in m68020
 | 
			
		||||
               mode.
 | 
			
		||||
             - Minor fixes in negx and nbcd.
 | 
			
		||||
             - renamed d68k.c to m68kdasm.c and merged d68k.h into m68k.h.
 | 
			
		||||
               d68k_read_xxx() instructions have been renamed to
 | 
			
		||||
               m68k_read_xxx_disassembler().
 | 
			
		||||
             - Rewrote exception processing and fixed 68020 stack frame
 | 
			
		||||
               problems.
 | 
			
		||||
             - FINALLY fixed the mull and divl instructions.
 | 
			
		||||
             - Added 64-bit safe code fixes.
 | 
			
		||||
             - Added 64-bit optimizations (these will only  be ANSI compliant
 | 
			
		||||
               under c9x, and so to use them you must turn on M68K_USE_64_BIT
 | 
			
		||||
               in m68kconf.h).
 | 
			
		||||
 | 
			
		||||
28-May-2000: Musashi 3.1 released
 | 
			
		||||
             - Fixed bug in m68k_get_reg() that retrieved the wrong value for
 | 
			
		||||
               the status register.
 | 
			
		||||
             - Fixed register bug in movec.
 | 
			
		||||
             - Fixed cpu type comparison problem that caused indexed
 | 
			
		||||
               addressing modes to be incorrectly interpreted when in m68ec020
 | 
			
		||||
               mode.
 | 
			
		||||
             - Added code to speed up busy waiting on some branch instructions.
 | 
			
		||||
             - Fixed some bfxxx opcode bugs.
 | 
			
		||||
 | 
			
		||||
05-Apr-2000: Musashi 3.0 released
 | 
			
		||||
             - Major code overhaul.
 | 
			
		||||
             - Rewrote code generator program and changed the format of
 | 
			
		||||
               m68k_in.c.
 | 
			
		||||
             - Added support for m68ec020.
 | 
			
		||||
             - Removed timing from the opcode handlers.
 | 
			
		||||
             - Added correct timing for m68000, m68010, and m68020.
 | 
			
		||||
               Note: 68020 timing is the cache timing from the manual.
 | 
			
		||||
             - Removed the m68k_peek_xxx() and m68k_poke_xxx() instructions and
 | 
			
		||||
               replaced them with m68k_get_reg() and m68k_set_reg().
 | 
			
		||||
             - Added support for function codes.
 | 
			
		||||
             - Revamped m68kconf.h to be easier to configure and more powerful.
 | 
			
		||||
             - Added option to separate immediate and normal reads.
 | 
			
		||||
             - Added support for (undocumented) m68000 instruction prefetch.
 | 
			
		||||
             - Rewrote indexed addressing mode handling.
 | 
			
		||||
             - Rewrote interrupt handling.
 | 
			
		||||
             - Fixed a masking bug for m68k_get_reg() when requesting the PC.
 | 
			
		||||
             - Moved the instruction table sorting routine to m68kmake.c so
 | 
			
		||||
               that it is invoked at compile time rather than at runtime.
 | 
			
		||||
             - Rewrote the exception handling routines to support different
 | 
			
		||||
               stack frames (needed for m68020 emulation).
 | 
			
		||||
             - Rewrote faster status register and condition code flag handling
 | 
			
		||||
               functions / macros.
 | 
			
		||||
             - Fixed function code handling to fetch from program space when
 | 
			
		||||
               using pc-relative addressing.
 | 
			
		||||
             - Fixed initial program counter and stack pointer fetching on
 | 
			
		||||
               reset (loads from program space now).
 | 
			
		||||
             - A lot of code cleanup.
 | 
			
		||||
             - LOTS of bugfixes (especially in the m68020 code).
 | 
			
		||||
 | 
			
		||||
13-May-1999: Musashi 2.2 released
 | 
			
		||||
             - Added support for m68020.
 | 
			
		||||
             - Lots of bugfixes.
 | 
			
		||||
 | 
			
		||||
25-Mar-1999: Musashi 2.1 released
 | 
			
		||||
             - Added support for m68010.
 | 
			
		||||
             - Many bugfixes.
 | 
			
		||||
 | 
			
		||||
17-Mar-1999: Musashi 2.0 released
 | 
			
		||||
             - Major code overhaul.
 | 
			
		||||
             - Replaced monolithic codebase with a code generator program.
 | 
			
		||||
             - Added correct m68000 timing.
 | 
			
		||||
             - Moved timing into the opcode handlers.
 | 
			
		||||
 | 
			
		||||
06-Jan-1999: Musashi 1.0 released
 | 
			
		||||
 | 
			
		||||
20-Dec-1998: Beta release of Musashi v0.5 that could run Rastan Saga under MAME
 | 
			
		||||
             (barely).
 | 
			
		||||
 | 
			
		||||
04-Dec-1998: Final prototype v0.4
 | 
			
		||||
 | 
			
		||||
20-Nov-1998: First prototype v0.1
 | 
			
		||||
 | 
			
		||||
11-Jun-1998: Early disassembler
 | 
			
		||||
 | 
			
		||||
12-May-1998: First outline
 | 
			
		||||
							
								
								
									
										358
									
								
								plat/linux68k/emu/musashi/m68k.h
									
										
									
									
									
										Executable file
									
								
							
							
						
						
									
										358
									
								
								plat/linux68k/emu/musashi/m68k.h
									
										
									
									
									
										Executable file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,358 @@
 | 
			
		|||
/* ======================================================================== */
 | 
			
		||||
/* ========================= LICENSING & COPYRIGHT ======================== */
 | 
			
		||||
/* ======================================================================== */
 | 
			
		||||
/*
 | 
			
		||||
 *                                  MUSASHI
 | 
			
		||||
 *                                Version 3.4
 | 
			
		||||
 *
 | 
			
		||||
 * A portable Motorola M680x0 processor emulation engine.
 | 
			
		||||
 * Copyright 1998-2001 Karl Stenerud.  All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 | 
			
		||||
 * of this software and associated documentation files (the "Software"), to deal
 | 
			
		||||
 * in the Software without restriction, including without limitation the rights
 | 
			
		||||
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 | 
			
		||||
 * copies of the Software, and to permit persons to whom the Software is
 | 
			
		||||
 * furnished to do so, subject to the following conditions:
 | 
			
		||||
 *
 | 
			
		||||
 * The above copyright notice and this permission notice shall be included in
 | 
			
		||||
 * all copies or substantial portions of the Software.
 | 
			
		||||
 | 
			
		||||
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 | 
			
		||||
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 | 
			
		||||
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 | 
			
		||||
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 | 
			
		||||
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 | 
			
		||||
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 | 
			
		||||
 * THE SOFTWARE.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef M68K__HEADER
 | 
			
		||||
#define M68K__HEADER
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* ======================================================================== */
 | 
			
		||||
/* ============================= CONFIGURATION ============================ */
 | 
			
		||||
/* ======================================================================== */
 | 
			
		||||
 | 
			
		||||
/* Import the configuration for this build */
 | 
			
		||||
#include "m68kconf.h"
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* ======================================================================== */
 | 
			
		||||
/* ============================ GENERAL DEFINES =========================== */
 | 
			
		||||
 | 
			
		||||
/* ======================================================================== */
 | 
			
		||||
 | 
			
		||||
/* There are 7 levels of interrupt to the 68K.
 | 
			
		||||
 * A transition from < 7 to 7 will cause a non-maskable interrupt (NMI).
 | 
			
		||||
 */
 | 
			
		||||
#define M68K_IRQ_NONE 0
 | 
			
		||||
#define M68K_IRQ_1    1
 | 
			
		||||
#define M68K_IRQ_2    2
 | 
			
		||||
#define M68K_IRQ_3    3
 | 
			
		||||
#define M68K_IRQ_4    4
 | 
			
		||||
#define M68K_IRQ_5    5
 | 
			
		||||
#define M68K_IRQ_6    6
 | 
			
		||||
#define M68K_IRQ_7    7
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* Special interrupt acknowledge values.
 | 
			
		||||
 * Use these as special returns from the interrupt acknowledge callback
 | 
			
		||||
 * (specified later in this header).
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
/* Causes an interrupt autovector (0x18 + interrupt level) to be taken.
 | 
			
		||||
 * This happens in a real 68K if VPA or AVEC is asserted during an interrupt
 | 
			
		||||
 * acknowledge cycle instead of DTACK.
 | 
			
		||||
 */
 | 
			
		||||
#define M68K_INT_ACK_AUTOVECTOR    0xffffffff
 | 
			
		||||
 | 
			
		||||
/* Causes the spurious interrupt vector (0x18) to be taken
 | 
			
		||||
 * This happens in a real 68K if BERR is asserted during the interrupt
 | 
			
		||||
 * acknowledge cycle (i.e. no devices responded to the acknowledge).
 | 
			
		||||
 */
 | 
			
		||||
#define M68K_INT_ACK_SPURIOUS      0xfffffffe
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* CPU types for use in m68k_set_cpu_type() */
 | 
			
		||||
enum
 | 
			
		||||
{
 | 
			
		||||
	M68K_CPU_TYPE_INVALID,
 | 
			
		||||
	M68K_CPU_TYPE_68000,
 | 
			
		||||
	M68K_CPU_TYPE_68010,
 | 
			
		||||
	M68K_CPU_TYPE_68EC020,
 | 
			
		||||
	M68K_CPU_TYPE_68020,
 | 
			
		||||
	M68K_CPU_TYPE_68030,	/* Supported by disassembler ONLY */
 | 
			
		||||
	M68K_CPU_TYPE_68040		/* Supported by disassembler ONLY */
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/* Registers used by m68k_get_reg() and m68k_set_reg() */
 | 
			
		||||
typedef enum
 | 
			
		||||
{
 | 
			
		||||
	/* Real registers */
 | 
			
		||||
	M68K_REG_D0,		/* Data registers */
 | 
			
		||||
	M68K_REG_D1,
 | 
			
		||||
	M68K_REG_D2,
 | 
			
		||||
	M68K_REG_D3,
 | 
			
		||||
	M68K_REG_D4,
 | 
			
		||||
	M68K_REG_D5,
 | 
			
		||||
	M68K_REG_D6,
 | 
			
		||||
	M68K_REG_D7,
 | 
			
		||||
	M68K_REG_A0,		/* Address registers */
 | 
			
		||||
	M68K_REG_A1,
 | 
			
		||||
	M68K_REG_A2,
 | 
			
		||||
	M68K_REG_A3,
 | 
			
		||||
	M68K_REG_A4,
 | 
			
		||||
	M68K_REG_A5,
 | 
			
		||||
	M68K_REG_A6,
 | 
			
		||||
	M68K_REG_A7,
 | 
			
		||||
	M68K_REG_PC,		/* Program Counter */
 | 
			
		||||
	M68K_REG_SR,		/* Status Register */
 | 
			
		||||
	M68K_REG_SP,		/* The current Stack Pointer (located in A7) */
 | 
			
		||||
	M68K_REG_USP,		/* User Stack Pointer */
 | 
			
		||||
	M68K_REG_ISP,		/* Interrupt Stack Pointer */
 | 
			
		||||
	M68K_REG_MSP,		/* Master Stack Pointer */
 | 
			
		||||
	M68K_REG_SFC,		/* Source Function Code */
 | 
			
		||||
	M68K_REG_DFC,		/* Destination Function Code */
 | 
			
		||||
	M68K_REG_VBR,		/* Vector Base Register */
 | 
			
		||||
	M68K_REG_CACR,		/* Cache Control Register */
 | 
			
		||||
	M68K_REG_CAAR,		/* Cache Address Register */
 | 
			
		||||
 | 
			
		||||
	/* Assumed registers */
 | 
			
		||||
	/* These are cheat registers which emulate the 1-longword prefetch
 | 
			
		||||
	 * present in the 68000 and 68010.
 | 
			
		||||
	 */
 | 
			
		||||
	M68K_REG_PREF_ADDR,	/* Last prefetch address */
 | 
			
		||||
	M68K_REG_PREF_DATA,	/* Last prefetch data */
 | 
			
		||||
 | 
			
		||||
	/* Convenience registers */
 | 
			
		||||
	M68K_REG_PPC,		/* Previous value in the program counter */
 | 
			
		||||
	M68K_REG_IR,		/* Instruction register */
 | 
			
		||||
	M68K_REG_CPU_TYPE	/* Type of CPU being run */
 | 
			
		||||
} m68k_register_t;
 | 
			
		||||
 | 
			
		||||
/* ======================================================================== */
 | 
			
		||||
/* ====================== FUNCTIONS CALLED BY THE CPU ===================== */
 | 
			
		||||
/* ======================================================================== */
 | 
			
		||||
 | 
			
		||||
/* You will have to implement these functions */
 | 
			
		||||
 | 
			
		||||
/* read/write functions called by the CPU to access memory.
 | 
			
		||||
 * while values used are 32 bits, only the appropriate number
 | 
			
		||||
 * of bits are relevant (i.e. in write_memory_8, only the lower 8 bits
 | 
			
		||||
 * of value should be written to memory).
 | 
			
		||||
 *
 | 
			
		||||
 * NOTE: I have separated the immediate and PC-relative memory fetches
 | 
			
		||||
 *       from the other memory fetches because some systems require
 | 
			
		||||
 *       differentiation between PROGRAM and DATA fetches (usually
 | 
			
		||||
 *       for security setups such as encryption).
 | 
			
		||||
 *       This separation can either be achieved by setting
 | 
			
		||||
 *       M68K_SEPARATE_READS in m68kconf.h and defining
 | 
			
		||||
 *       the read functions, or by setting M68K_EMULATE_FC and
 | 
			
		||||
 *       making a function code callback function.
 | 
			
		||||
 *       Using the callback offers better emulation coverage
 | 
			
		||||
 *       because you can also monitor whether the CPU is in SYSTEM or
 | 
			
		||||
 *       USER mode, but it is also slower.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
/* Read from anywhere */
 | 
			
		||||
unsigned int  m68k_read_memory_8(unsigned int address);
 | 
			
		||||
unsigned int  m68k_read_memory_16(unsigned int address);
 | 
			
		||||
unsigned int  m68k_read_memory_32(unsigned int address);
 | 
			
		||||
 | 
			
		||||
/* Read data immediately following the PC */
 | 
			
		||||
unsigned int  m68k_read_immediate_16(unsigned int address);
 | 
			
		||||
unsigned int  m68k_read_immediate_32(unsigned int address);
 | 
			
		||||
 | 
			
		||||
/* Read data relative to the PC */
 | 
			
		||||
unsigned int  m68k_read_pcrelative_8(unsigned int address);
 | 
			
		||||
unsigned int  m68k_read_pcrelative_16(unsigned int address);
 | 
			
		||||
unsigned int  m68k_read_pcrelative_32(unsigned int address);
 | 
			
		||||
 | 
			
		||||
/* Memory access for the disassembler */
 | 
			
		||||
unsigned int m68k_read_disassembler_8  (unsigned int address);
 | 
			
		||||
unsigned int m68k_read_disassembler_16 (unsigned int address);
 | 
			
		||||
unsigned int m68k_read_disassembler_32 (unsigned int address);
 | 
			
		||||
 | 
			
		||||
/* Write to anywhere */
 | 
			
		||||
void m68k_write_memory_8(unsigned int address, unsigned int value);
 | 
			
		||||
void m68k_write_memory_16(unsigned int address, unsigned int value);
 | 
			
		||||
void m68k_write_memory_32(unsigned int address, unsigned int value);
 | 
			
		||||
 | 
			
		||||
/* Special call to simulate undocumented 68k behavior when move.l with a
 | 
			
		||||
 * predecrement destination mode is executed.
 | 
			
		||||
 * To simulate real 68k behavior, first write the high word to
 | 
			
		||||
 * [address+2], and then write the low word to [address].
 | 
			
		||||
 *
 | 
			
		||||
 * Enable this functionality with M68K_SIMULATE_PD_WRITES in m68kconf.h.
 | 
			
		||||
 */
 | 
			
		||||
void m68k_write_memory_32_pd(unsigned int address, unsigned int value);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* ======================================================================== */
 | 
			
		||||
/* ============================== CALLBACKS =============================== */
 | 
			
		||||
/* ======================================================================== */
 | 
			
		||||
 | 
			
		||||
/* These functions allow you to set callbacks to the host when specific events
 | 
			
		||||
 * occur.  Note that you must enable the corresponding value in m68kconf.h
 | 
			
		||||
 * in order for these to do anything useful.
 | 
			
		||||
 * Note: I have defined default callbacks which are used if you have enabled
 | 
			
		||||
 * the corresponding #define in m68kconf.h but either haven't assigned a
 | 
			
		||||
 * callback or have assigned a callback of NULL.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
/* Set the callback for an interrupt acknowledge.
 | 
			
		||||
 * You must enable M68K_EMULATE_INT_ACK in m68kconf.h.
 | 
			
		||||
 * The CPU will call the callback with the interrupt level being acknowledged.
 | 
			
		||||
 * The host program must return either a vector from 0x02-0xff, or one of the
 | 
			
		||||
 * special interrupt acknowledge values specified earlier in this header.
 | 
			
		||||
 * If this is not implemented, the CPU will always assume an autovectored
 | 
			
		||||
 * interrupt, and will automatically clear the interrupt request when it
 | 
			
		||||
 * services the interrupt.
 | 
			
		||||
 * Default behavior: return M68K_INT_ACK_AUTOVECTOR.
 | 
			
		||||
 */
 | 
			
		||||
void m68k_set_int_ack_callback(int  (*callback)(int int_level));
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* Set the callback for a breakpoint acknowledge (68010+).
 | 
			
		||||
 * You must enable M68K_EMULATE_BKPT_ACK in m68kconf.h.
 | 
			
		||||
 * The CPU will call the callback with whatever was in the data field of the
 | 
			
		||||
 * BKPT instruction for 68020+, or 0 for 68010.
 | 
			
		||||
 * Default behavior: do nothing.
 | 
			
		||||
 */
 | 
			
		||||
void m68k_set_bkpt_ack_callback(void (*callback)(unsigned int data));
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* Set the callback for the RESET instruction.
 | 
			
		||||
 * You must enable M68K_EMULATE_RESET in m68kconf.h.
 | 
			
		||||
 * The CPU calls this callback every time it encounters a RESET instruction.
 | 
			
		||||
 * Default behavior: do nothing.
 | 
			
		||||
 */
 | 
			
		||||
void m68k_set_reset_instr_callback(void  (*callback)(void));
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* Set the callback for informing of a large PC change.
 | 
			
		||||
 * You must enable M68K_MONITOR_PC in m68kconf.h.
 | 
			
		||||
 * The CPU calls this callback with the new PC value every time the PC changes
 | 
			
		||||
 * by a large value (currently set for changes by longwords).
 | 
			
		||||
 * Default behavior: do nothing.
 | 
			
		||||
 */
 | 
			
		||||
void m68k_set_pc_changed_callback(void  (*callback)(unsigned int new_pc));
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* Set the callback for CPU function code changes.
 | 
			
		||||
 * You must enable M68K_EMULATE_FC in m68kconf.h.
 | 
			
		||||
 * The CPU calls this callback with the function code before every memory
 | 
			
		||||
 * access to set the CPU's function code according to what kind of memory
 | 
			
		||||
 * access it is (supervisor/user, program/data and such).
 | 
			
		||||
 * Default behavior: do nothing.
 | 
			
		||||
 */
 | 
			
		||||
void m68k_set_fc_callback(void  (*callback)(unsigned int new_fc));
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* Set a callback for the instruction cycle of the CPU.
 | 
			
		||||
 * You must enable M68K_INSTRUCTION_HOOK in m68kconf.h.
 | 
			
		||||
 * The CPU calls this callback just before fetching the opcode in the
 | 
			
		||||
 * instruction cycle.
 | 
			
		||||
 * Default behavior: do nothing.
 | 
			
		||||
 */
 | 
			
		||||
void m68k_set_instr_hook_callback(void  (*callback)(void));
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* ======================================================================== */
 | 
			
		||||
/* ====================== FUNCTIONS TO ACCESS THE CPU ===================== */
 | 
			
		||||
/* ======================================================================== */
 | 
			
		||||
 | 
			
		||||
/* Use this function to set the CPU type you want to emulate.
 | 
			
		||||
 * Currently supported types are: M68K_CPU_TYPE_68000, M68K_CPU_TYPE_68010,
 | 
			
		||||
 * M68K_CPU_TYPE_EC020, and M68K_CPU_TYPE_68020.
 | 
			
		||||
 */
 | 
			
		||||
void m68k_set_cpu_type(unsigned int cpu_type);
 | 
			
		||||
 | 
			
		||||
/* Do whatever initialisations the core requires.  Should be called
 | 
			
		||||
 * at least once at init time.
 | 
			
		||||
 */
 | 
			
		||||
void m68k_init(void);
 | 
			
		||||
 | 
			
		||||
/* Pulse the RESET pin on the CPU.
 | 
			
		||||
 * You *MUST* reset the CPU at least once to initialize the emulation
 | 
			
		||||
 * Note: If you didn't call m68k_set_cpu_type() before resetting
 | 
			
		||||
 *       the CPU for the first time, the CPU will be set to
 | 
			
		||||
 *       M68K_CPU_TYPE_68000.
 | 
			
		||||
 */
 | 
			
		||||
void m68k_pulse_reset(void);
 | 
			
		||||
 | 
			
		||||
/* execute num_cycles worth of instructions.  returns number of cycles used */
 | 
			
		||||
int m68k_execute(int num_cycles);
 | 
			
		||||
 | 
			
		||||
/* These functions let you read/write/modify the number of cycles left to run
 | 
			
		||||
 * while m68k_execute() is running.
 | 
			
		||||
 * These are useful if the 68k accesses a memory-mapped port on another device
 | 
			
		||||
 * that requires immediate processing by another CPU.
 | 
			
		||||
 */
 | 
			
		||||
int m68k_cycles_run(void);              /* Number of cycles run so far */
 | 
			
		||||
int m68k_cycles_remaining(void);        /* Number of cycles left */
 | 
			
		||||
void m68k_modify_timeslice(int cycles); /* Modify cycles left */
 | 
			
		||||
void m68k_end_timeslice(void);          /* End timeslice now */
 | 
			
		||||
 | 
			
		||||
/* Set the IPL0-IPL2 pins on the CPU (IRQ).
 | 
			
		||||
 * A transition from < 7 to 7 will cause a non-maskable interrupt (NMI).
 | 
			
		||||
 * Setting IRQ to 0 will clear an interrupt request.
 | 
			
		||||
 */
 | 
			
		||||
void m68k_set_irq(unsigned int int_level);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* Halt the CPU as if you pulsed the HALT pin. */
 | 
			
		||||
void m68k_pulse_halt(void);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* Context switching to allow multiple CPUs */
 | 
			
		||||
 | 
			
		||||
/* Get the size of the cpu context in bytes */
 | 
			
		||||
unsigned int m68k_context_size(void);
 | 
			
		||||
 | 
			
		||||
/* Get a cpu context */
 | 
			
		||||
unsigned int m68k_get_context(void* dst);
 | 
			
		||||
 | 
			
		||||
/* set the current cpu context */
 | 
			
		||||
void m68k_set_context(void* dst);
 | 
			
		||||
 | 
			
		||||
/* Register the CPU state information */
 | 
			
		||||
void m68k_state_register(const char *type);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* Peek at the internals of a CPU context.  This can either be a context
 | 
			
		||||
 * retrieved using m68k_get_context() or the currently running context.
 | 
			
		||||
 * If context is NULL, the currently running CPU context will be used.
 | 
			
		||||
 */
 | 
			
		||||
unsigned int m68k_get_reg(void* context, m68k_register_t reg);
 | 
			
		||||
 | 
			
		||||
/* Poke values into the internals of the currently running CPU context */
 | 
			
		||||
void m68k_set_reg(m68k_register_t reg, unsigned int value);
 | 
			
		||||
 | 
			
		||||
/* Check if an instruction is valid for the specified CPU type */
 | 
			
		||||
unsigned int m68k_is_valid_instruction(unsigned int instruction, unsigned int cpu_type);
 | 
			
		||||
 | 
			
		||||
/* Disassemble 1 instruction using the epecified CPU type at pc.  Stores
 | 
			
		||||
 * disassembly in str_buff and returns the size of the instruction in bytes.
 | 
			
		||||
 */
 | 
			
		||||
unsigned int m68k_disassemble(char* str_buff, unsigned int pc, unsigned int cpu_type);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* ======================================================================== */
 | 
			
		||||
/* ============================== MAME STUFF ============================== */
 | 
			
		||||
/* ======================================================================== */
 | 
			
		||||
 | 
			
		||||
#if M68K_COMPILE_FOR_MAME == OPT_ON
 | 
			
		||||
#include "m68kmame.h"
 | 
			
		||||
#endif /* M68K_COMPILE_FOR_MAME */
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* ======================================================================== */
 | 
			
		||||
/* ============================== END OF FILE ============================= */
 | 
			
		||||
/* ======================================================================== */
 | 
			
		||||
 | 
			
		||||
#endif /* M68K__HEADER */
 | 
			
		||||
							
								
								
									
										10375
									
								
								plat/linux68k/emu/musashi/m68k_in.c
									
										
									
									
									
										Executable file
									
								
							
							
						
						
									
										10375
									
								
								plat/linux68k/emu/musashi/m68k_in.c
									
										
									
									
									
										Executable file
									
								
							
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							
							
								
								
									
										187
									
								
								plat/linux68k/emu/musashi/m68kconf.h
									
										
									
									
									
										Executable file
									
								
							
							
						
						
									
										187
									
								
								plat/linux68k/emu/musashi/m68kconf.h
									
										
									
									
									
										Executable file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,187 @@
 | 
			
		|||
/* ======================================================================== */
 | 
			
		||||
/* ========================= LICENSING & COPYRIGHT ======================== */
 | 
			
		||||
/* ======================================================================== */
 | 
			
		||||
/*
 | 
			
		||||
 *                                  MUSASHI
 | 
			
		||||
 *                                Version 3.4
 | 
			
		||||
 *
 | 
			
		||||
 * A portable Motorola M680x0 processor emulation engine.
 | 
			
		||||
 * Copyright 1998-2001 Karl Stenerud.  All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 | 
			
		||||
 * of this software and associated documentation files (the "Software"), to deal
 | 
			
		||||
 * in the Software without restriction, including without limitation the rights
 | 
			
		||||
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 | 
			
		||||
 * copies of the Software, and to permit persons to whom the Software is
 | 
			
		||||
 * furnished to do so, subject to the following conditions:
 | 
			
		||||
 *
 | 
			
		||||
 * The above copyright notice and this permission notice shall be included in
 | 
			
		||||
 * all copies or substantial portions of the Software.
 | 
			
		||||
 | 
			
		||||
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 | 
			
		||||
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 | 
			
		||||
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 | 
			
		||||
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 | 
			
		||||
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 | 
			
		||||
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 | 
			
		||||
 * THE SOFTWARE.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#ifndef M68KCONF__HEADER
 | 
			
		||||
#define M68KCONF__HEADER
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* Configuration switches.
 | 
			
		||||
 * Use OPT_SPECIFY_HANDLER for configuration options that allow callbacks.
 | 
			
		||||
 * OPT_SPECIFY_HANDLER causes the core to link directly to the function
 | 
			
		||||
 * or macro you specify, rather than using callback functions whose pointer
 | 
			
		||||
 * must be passed in using m68k_set_xxx_callback().
 | 
			
		||||
 */
 | 
			
		||||
#define OPT_OFF             0
 | 
			
		||||
#define OPT_ON              1
 | 
			
		||||
#define OPT_SPECIFY_HANDLER 2
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* ======================================================================== */
 | 
			
		||||
/* ============================== MAME STUFF ============================== */
 | 
			
		||||
/* ======================================================================== */
 | 
			
		||||
 | 
			
		||||
/* If you're compiling this for MAME, only change M68K_COMPILE_FOR_MAME
 | 
			
		||||
 * to OPT_ON and use m68kmame.h to configure the 68k core.
 | 
			
		||||
 */
 | 
			
		||||
#ifndef M68K_COMPILE_FOR_MAME
 | 
			
		||||
#define M68K_COMPILE_FOR_MAME      OPT_ON
 | 
			
		||||
#endif /* M68K_COMPILE_FOR_MAME */
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#if M68K_COMPILE_FOR_MAME == OPT_OFF
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* ======================================================================== */
 | 
			
		||||
/* ============================= CONFIGURATION ============================ */
 | 
			
		||||
/* ======================================================================== */
 | 
			
		||||
 | 
			
		||||
/* Turn ON if you want to use the following M68K variants */
 | 
			
		||||
#define M68K_EMULATE_010            OPT_ON
 | 
			
		||||
#define M68K_EMULATE_EC020          OPT_ON
 | 
			
		||||
#define M68K_EMULATE_020            OPT_ON
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* If ON, the CPU will call m68k_read_immediate_xx() for immediate addressing
 | 
			
		||||
 * and m68k_read_pcrelative_xx() for PC-relative addressing.
 | 
			
		||||
 * If off, all read requests from the CPU will be redirected to m68k_read_xx()
 | 
			
		||||
 */
 | 
			
		||||
#define M68K_SEPARATE_READS         OPT_OFF
 | 
			
		||||
 | 
			
		||||
/* If ON, the CPU will call m68k_write_32_pd() when it executes move.l with a
 | 
			
		||||
 * predecrement destination EA mode instead of m68k_write_32().
 | 
			
		||||
 * To simulate real 68k behavior, m68k_write_32_pd() must first write the high
 | 
			
		||||
 * word to [address+2], and then write the low word to [address].
 | 
			
		||||
 */
 | 
			
		||||
#define M68K_SIMULATE_PD_WRITES     OPT_OFF
 | 
			
		||||
 | 
			
		||||
/* If ON, CPU will call the interrupt acknowledge callback when it services an
 | 
			
		||||
 * interrupt.
 | 
			
		||||
 * If off, all interrupts will be autovectored and all interrupt requests will
 | 
			
		||||
 * auto-clear when the interrupt is serviced.
 | 
			
		||||
 */
 | 
			
		||||
#define M68K_EMULATE_INT_ACK        OPT_OFF
 | 
			
		||||
#define M68K_INT_ACK_CALLBACK(A)    your_int_ack_handler_function(A)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* If ON, CPU will call the breakpoint acknowledge callback when it encounters
 | 
			
		||||
 * a breakpoint instruction and it is running a 68010+.
 | 
			
		||||
 */
 | 
			
		||||
#define M68K_EMULATE_BKPT_ACK       OPT_OFF
 | 
			
		||||
#define M68K_BKPT_ACK_CALLBACK()    your_bkpt_ack_handler_function()
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* If ON, the CPU will monitor the trace flags and take trace exceptions
 | 
			
		||||
 */
 | 
			
		||||
#define M68K_EMULATE_TRACE          OPT_OFF
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* If ON, CPU will call the output reset callback when it encounters a reset
 | 
			
		||||
 * instruction.
 | 
			
		||||
 */
 | 
			
		||||
#define M68K_EMULATE_RESET          OPT_OFF
 | 
			
		||||
#define M68K_RESET_CALLBACK()       your_reset_handler_function()
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* If ON, CPU will call the set fc callback on every memory access to
 | 
			
		||||
 * differentiate between user/supervisor, program/data access like a real
 | 
			
		||||
 * 68000 would.  This should be enabled and the callback should be set if you
 | 
			
		||||
 * want to properly emulate the m68010 or higher. (moves uses function codes
 | 
			
		||||
 * to read/write data from different address spaces)
 | 
			
		||||
 */
 | 
			
		||||
#define M68K_EMULATE_FC             OPT_OFF
 | 
			
		||||
#define M68K_SET_FC_CALLBACK(A)     your_set_fc_handler_function(A)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* If ON, CPU will call the pc changed callback when it changes the PC by a
 | 
			
		||||
 * large value.  This allows host programs to be nicer when it comes to
 | 
			
		||||
 * fetching immediate data and instructions on a banked memory system.
 | 
			
		||||
 */
 | 
			
		||||
#define M68K_MONITOR_PC             OPT_OFF
 | 
			
		||||
#define M68K_SET_PC_CALLBACK(A)     your_pc_changed_handler_function(A)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* If ON, CPU will call the instruction hook callback before every
 | 
			
		||||
 * instruction.
 | 
			
		||||
 */
 | 
			
		||||
#define M68K_INSTRUCTION_HOOK       OPT_OFF
 | 
			
		||||
#define M68K_INSTRUCTION_CALLBACK() your_instruction_hook_function()
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* If ON, the CPU will emulate the 4-byte prefetch queue of a real 68000 */
 | 
			
		||||
#define M68K_EMULATE_PREFETCH       OPT_OFF
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* If ON, the CPU will generate address error exceptions if it tries to
 | 
			
		||||
 * access a word or longword at an odd address.
 | 
			
		||||
 * NOTE: This is only emulated properly for 68000 mode.
 | 
			
		||||
 */
 | 
			
		||||
#define M68K_EMULATE_ADDRESS_ERROR  OPT_OFF
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* Turn ON to enable logging of illegal instruction calls.
 | 
			
		||||
 * M68K_LOG_FILEHANDLE must be #defined to a stdio file stream.
 | 
			
		||||
 * Turn on M68K_LOG_1010_1111 to log all 1010 and 1111 calls.
 | 
			
		||||
 */
 | 
			
		||||
#define M68K_LOG_ENABLE             OPT_OFF
 | 
			
		||||
#define M68K_LOG_1010_1111          OPT_OFF
 | 
			
		||||
#define M68K_LOG_FILEHANDLE         some_file_handle
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* ----------------------------- COMPATIBILITY ---------------------------- */
 | 
			
		||||
 | 
			
		||||
/* The following options set optimizations that violate the current ANSI
 | 
			
		||||
 * standard, but will be compliant under the forthcoming C9X standard.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* If ON, the enulation core will use 64-bit integers to speed up some
 | 
			
		||||
 * operations.
 | 
			
		||||
*/
 | 
			
		||||
#define M68K_USE_64_BIT  OPT_OFF
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* Set to your compiler's static inline keyword to enable it, or
 | 
			
		||||
 * set it to blank to disable it.
 | 
			
		||||
 * If you define INLINE in the makefile, it will override this value.
 | 
			
		||||
 * NOTE: not enabling inline functions will SEVERELY slow down emulation.
 | 
			
		||||
 */
 | 
			
		||||
#ifndef INLINE
 | 
			
		||||
#define INLINE static __inline__
 | 
			
		||||
#endif /* INLINE */
 | 
			
		||||
 | 
			
		||||
#endif /* M68K_COMPILE_FOR_MAME */
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* ======================================================================== */
 | 
			
		||||
/* ============================== END OF FILE ============================= */
 | 
			
		||||
/* ======================================================================== */
 | 
			
		||||
 | 
			
		||||
#endif /* M68KCONF__HEADER */
 | 
			
		||||
							
								
								
									
										882
									
								
								plat/linux68k/emu/musashi/m68kcpu.c
									
										
									
									
									
										Executable file
									
								
							
							
						
						
									
										882
									
								
								plat/linux68k/emu/musashi/m68kcpu.c
									
										
									
									
									
										Executable file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,882 @@
 | 
			
		|||
/* ======================================================================== */
 | 
			
		||||
/* ========================= LICENSING & COPYRIGHT ======================== */
 | 
			
		||||
/* ======================================================================== */
 | 
			
		||||
/*
 | 
			
		||||
 *                                  MUSASHI
 | 
			
		||||
 *                                Version 3.4
 | 
			
		||||
 *
 | 
			
		||||
 * A portable Motorola M680x0 processor emulation engine.
 | 
			
		||||
 * Copyright 1998-2001 Karl Stenerud.  All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 | 
			
		||||
 * of this software and associated documentation files (the "Software"), to deal
 | 
			
		||||
 * in the Software without restriction, including without limitation the rights
 | 
			
		||||
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 | 
			
		||||
 * copies of the Software, and to permit persons to whom the Software is
 | 
			
		||||
 * furnished to do so, subject to the following conditions:
 | 
			
		||||
 *
 | 
			
		||||
 * The above copyright notice and this permission notice shall be included in
 | 
			
		||||
 * all copies or substantial portions of the Software.
 | 
			
		||||
 | 
			
		||||
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 | 
			
		||||
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 | 
			
		||||
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 | 
			
		||||
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 | 
			
		||||
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 | 
			
		||||
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 | 
			
		||||
 * THE SOFTWARE.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* ======================================================================== */
 | 
			
		||||
/* ================================= NOTES ================================ */
 | 
			
		||||
/* ======================================================================== */
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* ======================================================================== */
 | 
			
		||||
/* ================================ INCLUDES ============================== */
 | 
			
		||||
/* ======================================================================== */
 | 
			
		||||
 | 
			
		||||
#include "m68kops.h"
 | 
			
		||||
#include "m68kcpu.h"
 | 
			
		||||
 | 
			
		||||
/* ======================================================================== */
 | 
			
		||||
/* ================================= DATA ================================= */
 | 
			
		||||
/* ======================================================================== */
 | 
			
		||||
 | 
			
		||||
int  m68ki_initial_cycles;
 | 
			
		||||
int  m68ki_remaining_cycles = 0;                     /* Number of clocks remaining */
 | 
			
		||||
uint m68ki_tracing = 0;
 | 
			
		||||
uint m68ki_address_space;
 | 
			
		||||
 | 
			
		||||
#ifdef M68K_LOG_ENABLE
 | 
			
		||||
char* m68ki_cpu_names[9] =
 | 
			
		||||
{
 | 
			
		||||
	"Invalid CPU",
 | 
			
		||||
	"M68000",
 | 
			
		||||
	"M68010",
 | 
			
		||||
	"Invalid CPU",
 | 
			
		||||
	"M68EC020"
 | 
			
		||||
	"Invalid CPU",
 | 
			
		||||
	"Invalid CPU",
 | 
			
		||||
	"Invalid CPU",
 | 
			
		||||
	"M68020"
 | 
			
		||||
};
 | 
			
		||||
#endif /* M68K_LOG_ENABLE */
 | 
			
		||||
 | 
			
		||||
/* The CPU core */
 | 
			
		||||
m68ki_cpu_core m68ki_cpu = {0};
 | 
			
		||||
 | 
			
		||||
#if M68K_EMULATE_ADDRESS_ERROR
 | 
			
		||||
jmp_buf m68ki_aerr_trap;
 | 
			
		||||
#endif /* M68K_EMULATE_ADDRESS_ERROR */
 | 
			
		||||
 | 
			
		||||
uint    m68ki_aerr_address;
 | 
			
		||||
uint    m68ki_aerr_write_mode;
 | 
			
		||||
uint    m68ki_aerr_fc;
 | 
			
		||||
 | 
			
		||||
/* Used by shift & rotate instructions */
 | 
			
		||||
uint8 m68ki_shift_8_table[65] =
 | 
			
		||||
{
 | 
			
		||||
	0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff, 0xff, 0xff, 0xff,
 | 
			
		||||
	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
 | 
			
		||||
	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
 | 
			
		||||
	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
 | 
			
		||||
	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
 | 
			
		||||
	0xff, 0xff, 0xff, 0xff, 0xff
 | 
			
		||||
};
 | 
			
		||||
uint16 m68ki_shift_16_table[65] =
 | 
			
		||||
{
 | 
			
		||||
	0x0000, 0x8000, 0xc000, 0xe000, 0xf000, 0xf800, 0xfc00, 0xfe00, 0xff00,
 | 
			
		||||
	0xff80, 0xffc0, 0xffe0, 0xfff0, 0xfff8, 0xfffc, 0xfffe, 0xffff, 0xffff,
 | 
			
		||||
	0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
 | 
			
		||||
	0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
 | 
			
		||||
	0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
 | 
			
		||||
	0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
 | 
			
		||||
	0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
 | 
			
		||||
	0xffff, 0xffff
 | 
			
		||||
};
 | 
			
		||||
uint m68ki_shift_32_table[65] =
 | 
			
		||||
{
 | 
			
		||||
	0x00000000, 0x80000000, 0xc0000000, 0xe0000000, 0xf0000000, 0xf8000000,
 | 
			
		||||
	0xfc000000, 0xfe000000, 0xff000000, 0xff800000, 0xffc00000, 0xffe00000,
 | 
			
		||||
	0xfff00000, 0xfff80000, 0xfffc0000, 0xfffe0000, 0xffff0000, 0xffff8000,
 | 
			
		||||
	0xffffc000, 0xffffe000, 0xfffff000, 0xfffff800, 0xfffffc00, 0xfffffe00,
 | 
			
		||||
	0xffffff00, 0xffffff80, 0xffffffc0, 0xffffffe0, 0xfffffff0, 0xfffffff8,
 | 
			
		||||
	0xfffffffc, 0xfffffffe, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
 | 
			
		||||
	0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
 | 
			
		||||
	0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
 | 
			
		||||
	0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
 | 
			
		||||
	0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
 | 
			
		||||
	0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* Number of clock cycles to use for exception processing.
 | 
			
		||||
 * I used 4 for any vectors that are undocumented for processing times.
 | 
			
		||||
 */
 | 
			
		||||
uint8 m68ki_exception_cycle_table[3][256] =
 | 
			
		||||
{
 | 
			
		||||
	{ /* 000 */
 | 
			
		||||
		  4, /*  0: Reset - Initial Stack Pointer                      */
 | 
			
		||||
		  4, /*  1: Reset - Initial Program Counter                    */
 | 
			
		||||
		 50, /*  2: Bus Error                             (unemulated) */
 | 
			
		||||
		 50, /*  3: Address Error                         (unemulated) */
 | 
			
		||||
		 34, /*  4: Illegal Instruction                                */
 | 
			
		||||
		 38, /*  5: Divide by Zero -- ASG: changed from 42             */
 | 
			
		||||
		 40, /*  6: CHK -- ASG: chanaged from 44                       */
 | 
			
		||||
		 34, /*  7: TRAPV                                              */
 | 
			
		||||
		 34, /*  8: Privilege Violation                                */
 | 
			
		||||
		 34, /*  9: Trace                                              */
 | 
			
		||||
		 34, /* 10: 1010                                               */
 | 
			
		||||
		 34, /* 11: 1111                                               */
 | 
			
		||||
		  4, /* 12: RESERVED                                           */
 | 
			
		||||
		  4, /* 13: Coprocessor Protocol Violation        (unemulated) */
 | 
			
		||||
		  4, /* 14: Format Error                                       */
 | 
			
		||||
		 44, /* 15: Uninitialized Interrupt                            */
 | 
			
		||||
		  4, /* 16: RESERVED                                           */
 | 
			
		||||
		  4, /* 17: RESERVED                                           */
 | 
			
		||||
		  4, /* 18: RESERVED                                           */
 | 
			
		||||
		  4, /* 19: RESERVED                                           */
 | 
			
		||||
		  4, /* 20: RESERVED                                           */
 | 
			
		||||
		  4, /* 21: RESERVED                                           */
 | 
			
		||||
		  4, /* 22: RESERVED                                           */
 | 
			
		||||
		  4, /* 23: RESERVED                                           */
 | 
			
		||||
		 44, /* 24: Spurious Interrupt                                 */
 | 
			
		||||
		 44, /* 25: Level 1 Interrupt Autovector                       */
 | 
			
		||||
		 44, /* 26: Level 2 Interrupt Autovector                       */
 | 
			
		||||
		 44, /* 27: Level 3 Interrupt Autovector                       */
 | 
			
		||||
		 44, /* 28: Level 4 Interrupt Autovector                       */
 | 
			
		||||
		 44, /* 29: Level 5 Interrupt Autovector                       */
 | 
			
		||||
		 44, /* 30: Level 6 Interrupt Autovector                       */
 | 
			
		||||
		 44, /* 31: Level 7 Interrupt Autovector                       */
 | 
			
		||||
		 34, /* 32: TRAP #0 -- ASG: chanaged from 38                   */
 | 
			
		||||
		 34, /* 33: TRAP #1                                            */
 | 
			
		||||
		 34, /* 34: TRAP #2                                            */
 | 
			
		||||
		 34, /* 35: TRAP #3                                            */
 | 
			
		||||
		 34, /* 36: TRAP #4                                            */
 | 
			
		||||
		 34, /* 37: TRAP #5                                            */
 | 
			
		||||
		 34, /* 38: TRAP #6                                            */
 | 
			
		||||
		 34, /* 39: TRAP #7                                            */
 | 
			
		||||
		 34, /* 40: TRAP #8                                            */
 | 
			
		||||
		 34, /* 41: TRAP #9                                            */
 | 
			
		||||
		 34, /* 42: TRAP #10                                           */
 | 
			
		||||
		 34, /* 43: TRAP #11                                           */
 | 
			
		||||
		 34, /* 44: TRAP #12                                           */
 | 
			
		||||
		 34, /* 45: TRAP #13                                           */
 | 
			
		||||
		 34, /* 46: TRAP #14                                           */
 | 
			
		||||
		 34, /* 47: TRAP #15                                           */
 | 
			
		||||
		  4, /* 48: FP Branch or Set on Unknown Condition (unemulated) */
 | 
			
		||||
		  4, /* 49: FP Inexact Result                     (unemulated) */
 | 
			
		||||
		  4, /* 50: FP Divide by Zero                     (unemulated) */
 | 
			
		||||
		  4, /* 51: FP Underflow                          (unemulated) */
 | 
			
		||||
		  4, /* 52: FP Operand Error                      (unemulated) */
 | 
			
		||||
		  4, /* 53: FP Overflow                           (unemulated) */
 | 
			
		||||
		  4, /* 54: FP Signaling NAN                      (unemulated) */
 | 
			
		||||
		  4, /* 55: FP Unimplemented Data Type            (unemulated) */
 | 
			
		||||
		  4, /* 56: MMU Configuration Error               (unemulated) */
 | 
			
		||||
		  4, /* 57: MMU Illegal Operation Error           (unemulated) */
 | 
			
		||||
		  4, /* 58: MMU Access Level Violation Error      (unemulated) */
 | 
			
		||||
		  4, /* 59: RESERVED                                           */
 | 
			
		||||
		  4, /* 60: RESERVED                                           */
 | 
			
		||||
		  4, /* 61: RESERVED                                           */
 | 
			
		||||
		  4, /* 62: RESERVED                                           */
 | 
			
		||||
		  4, /* 63: RESERVED                                           */
 | 
			
		||||
		     /* 64-255: User Defined                                   */
 | 
			
		||||
		  4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
 | 
			
		||||
		  4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
 | 
			
		||||
		  4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
 | 
			
		||||
		  4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
 | 
			
		||||
		  4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
 | 
			
		||||
		  4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4
 | 
			
		||||
	},
 | 
			
		||||
	{ /* 010 */
 | 
			
		||||
		  4, /*  0: Reset - Initial Stack Pointer                      */
 | 
			
		||||
		  4, /*  1: Reset - Initial Program Counter                    */
 | 
			
		||||
		126, /*  2: Bus Error                             (unemulated) */
 | 
			
		||||
		126, /*  3: Address Error                         (unemulated) */
 | 
			
		||||
		 38, /*  4: Illegal Instruction                                */
 | 
			
		||||
		 44, /*  5: Divide by Zero                                     */
 | 
			
		||||
		 44, /*  6: CHK                                                */
 | 
			
		||||
		 34, /*  7: TRAPV                                              */
 | 
			
		||||
		 38, /*  8: Privilege Violation                                */
 | 
			
		||||
		 38, /*  9: Trace                                              */
 | 
			
		||||
		  4, /* 10: 1010                                               */
 | 
			
		||||
		  4, /* 11: 1111                                               */
 | 
			
		||||
		  4, /* 12: RESERVED                                           */
 | 
			
		||||
		  4, /* 13: Coprocessor Protocol Violation        (unemulated) */
 | 
			
		||||
		  4, /* 14: Format Error                                       */
 | 
			
		||||
		 44, /* 15: Uninitialized Interrupt                            */
 | 
			
		||||
		  4, /* 16: RESERVED                                           */
 | 
			
		||||
		  4, /* 17: RESERVED                                           */
 | 
			
		||||
		  4, /* 18: RESERVED                                           */
 | 
			
		||||
		  4, /* 19: RESERVED                                           */
 | 
			
		||||
		  4, /* 20: RESERVED                                           */
 | 
			
		||||
		  4, /* 21: RESERVED                                           */
 | 
			
		||||
		  4, /* 22: RESERVED                                           */
 | 
			
		||||
		  4, /* 23: RESERVED                                           */
 | 
			
		||||
		 46, /* 24: Spurious Interrupt                                 */
 | 
			
		||||
		 46, /* 25: Level 1 Interrupt Autovector                       */
 | 
			
		||||
		 46, /* 26: Level 2 Interrupt Autovector                       */
 | 
			
		||||
		 46, /* 27: Level 3 Interrupt Autovector                       */
 | 
			
		||||
		 46, /* 28: Level 4 Interrupt Autovector                       */
 | 
			
		||||
		 46, /* 29: Level 5 Interrupt Autovector                       */
 | 
			
		||||
		 46, /* 30: Level 6 Interrupt Autovector                       */
 | 
			
		||||
		 46, /* 31: Level 7 Interrupt Autovector                       */
 | 
			
		||||
		 38, /* 32: TRAP #0                                            */
 | 
			
		||||
		 38, /* 33: TRAP #1                                            */
 | 
			
		||||
		 38, /* 34: TRAP #2                                            */
 | 
			
		||||
		 38, /* 35: TRAP #3                                            */
 | 
			
		||||
		 38, /* 36: TRAP #4                                            */
 | 
			
		||||
		 38, /* 37: TRAP #5                                            */
 | 
			
		||||
		 38, /* 38: TRAP #6                                            */
 | 
			
		||||
		 38, /* 39: TRAP #7                                            */
 | 
			
		||||
		 38, /* 40: TRAP #8                                            */
 | 
			
		||||
		 38, /* 41: TRAP #9                                            */
 | 
			
		||||
		 38, /* 42: TRAP #10                                           */
 | 
			
		||||
		 38, /* 43: TRAP #11                                           */
 | 
			
		||||
		 38, /* 44: TRAP #12                                           */
 | 
			
		||||
		 38, /* 45: TRAP #13                                           */
 | 
			
		||||
		 38, /* 46: TRAP #14                                           */
 | 
			
		||||
		 38, /* 47: TRAP #15                                           */
 | 
			
		||||
		  4, /* 48: FP Branch or Set on Unknown Condition (unemulated) */
 | 
			
		||||
		  4, /* 49: FP Inexact Result                     (unemulated) */
 | 
			
		||||
		  4, /* 50: FP Divide by Zero                     (unemulated) */
 | 
			
		||||
		  4, /* 51: FP Underflow                          (unemulated) */
 | 
			
		||||
		  4, /* 52: FP Operand Error                      (unemulated) */
 | 
			
		||||
		  4, /* 53: FP Overflow                           (unemulated) */
 | 
			
		||||
		  4, /* 54: FP Signaling NAN                      (unemulated) */
 | 
			
		||||
		  4, /* 55: FP Unimplemented Data Type            (unemulated) */
 | 
			
		||||
		  4, /* 56: MMU Configuration Error               (unemulated) */
 | 
			
		||||
		  4, /* 57: MMU Illegal Operation Error           (unemulated) */
 | 
			
		||||
		  4, /* 58: MMU Access Level Violation Error      (unemulated) */
 | 
			
		||||
		  4, /* 59: RESERVED                                           */
 | 
			
		||||
		  4, /* 60: RESERVED                                           */
 | 
			
		||||
		  4, /* 61: RESERVED                                           */
 | 
			
		||||
		  4, /* 62: RESERVED                                           */
 | 
			
		||||
		  4, /* 63: RESERVED                                           */
 | 
			
		||||
		     /* 64-255: User Defined                                   */
 | 
			
		||||
		  4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
 | 
			
		||||
		  4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
 | 
			
		||||
		  4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
 | 
			
		||||
		  4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
 | 
			
		||||
		  4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
 | 
			
		||||
		  4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4
 | 
			
		||||
	},
 | 
			
		||||
	{ /* 020 */
 | 
			
		||||
		  4, /*  0: Reset - Initial Stack Pointer                      */
 | 
			
		||||
		  4, /*  1: Reset - Initial Program Counter                    */
 | 
			
		||||
		 50, /*  2: Bus Error                             (unemulated) */
 | 
			
		||||
		 50, /*  3: Address Error                         (unemulated) */
 | 
			
		||||
		 20, /*  4: Illegal Instruction                                */
 | 
			
		||||
		 38, /*  5: Divide by Zero                                     */
 | 
			
		||||
		 40, /*  6: CHK                                                */
 | 
			
		||||
		 20, /*  7: TRAPV                                              */
 | 
			
		||||
		 34, /*  8: Privilege Violation                                */
 | 
			
		||||
		 25, /*  9: Trace                                              */
 | 
			
		||||
		 20, /* 10: 1010                                               */
 | 
			
		||||
		 20, /* 11: 1111                                               */
 | 
			
		||||
		  4, /* 12: RESERVED                                           */
 | 
			
		||||
		  4, /* 13: Coprocessor Protocol Violation        (unemulated) */
 | 
			
		||||
		  4, /* 14: Format Error                                       */
 | 
			
		||||
		 30, /* 15: Uninitialized Interrupt                            */
 | 
			
		||||
		  4, /* 16: RESERVED                                           */
 | 
			
		||||
		  4, /* 17: RESERVED                                           */
 | 
			
		||||
		  4, /* 18: RESERVED                                           */
 | 
			
		||||
		  4, /* 19: RESERVED                                           */
 | 
			
		||||
		  4, /* 20: RESERVED                                           */
 | 
			
		||||
		  4, /* 21: RESERVED                                           */
 | 
			
		||||
		  4, /* 22: RESERVED                                           */
 | 
			
		||||
		  4, /* 23: RESERVED                                           */
 | 
			
		||||
		 30, /* 24: Spurious Interrupt                                 */
 | 
			
		||||
		 30, /* 25: Level 1 Interrupt Autovector                       */
 | 
			
		||||
		 30, /* 26: Level 2 Interrupt Autovector                       */
 | 
			
		||||
		 30, /* 27: Level 3 Interrupt Autovector                       */
 | 
			
		||||
		 30, /* 28: Level 4 Interrupt Autovector                       */
 | 
			
		||||
		 30, /* 29: Level 5 Interrupt Autovector                       */
 | 
			
		||||
		 30, /* 30: Level 6 Interrupt Autovector                       */
 | 
			
		||||
		 30, /* 31: Level 7 Interrupt Autovector                       */
 | 
			
		||||
		 20, /* 32: TRAP #0                                            */
 | 
			
		||||
		 20, /* 33: TRAP #1                                            */
 | 
			
		||||
		 20, /* 34: TRAP #2                                            */
 | 
			
		||||
		 20, /* 35: TRAP #3                                            */
 | 
			
		||||
		 20, /* 36: TRAP #4                                            */
 | 
			
		||||
		 20, /* 37: TRAP #5                                            */
 | 
			
		||||
		 20, /* 38: TRAP #6                                            */
 | 
			
		||||
		 20, /* 39: TRAP #7                                            */
 | 
			
		||||
		 20, /* 40: TRAP #8                                            */
 | 
			
		||||
		 20, /* 41: TRAP #9                                            */
 | 
			
		||||
		 20, /* 42: TRAP #10                                           */
 | 
			
		||||
		 20, /* 43: TRAP #11                                           */
 | 
			
		||||
		 20, /* 44: TRAP #12                                           */
 | 
			
		||||
		 20, /* 45: TRAP #13                                           */
 | 
			
		||||
		 20, /* 46: TRAP #14                                           */
 | 
			
		||||
		 20, /* 47: TRAP #15                                           */
 | 
			
		||||
		  4, /* 48: FP Branch or Set on Unknown Condition (unemulated) */
 | 
			
		||||
		  4, /* 49: FP Inexact Result                     (unemulated) */
 | 
			
		||||
		  4, /* 50: FP Divide by Zero                     (unemulated) */
 | 
			
		||||
		  4, /* 51: FP Underflow                          (unemulated) */
 | 
			
		||||
		  4, /* 52: FP Operand Error                      (unemulated) */
 | 
			
		||||
		  4, /* 53: FP Overflow                           (unemulated) */
 | 
			
		||||
		  4, /* 54: FP Signaling NAN                      (unemulated) */
 | 
			
		||||
		  4, /* 55: FP Unimplemented Data Type            (unemulated) */
 | 
			
		||||
		  4, /* 56: MMU Configuration Error               (unemulated) */
 | 
			
		||||
		  4, /* 57: MMU Illegal Operation Error           (unemulated) */
 | 
			
		||||
		  4, /* 58: MMU Access Level Violation Error      (unemulated) */
 | 
			
		||||
		  4, /* 59: RESERVED                                           */
 | 
			
		||||
		  4, /* 60: RESERVED                                           */
 | 
			
		||||
		  4, /* 61: RESERVED                                           */
 | 
			
		||||
		  4, /* 62: RESERVED                                           */
 | 
			
		||||
		  4, /* 63: RESERVED                                           */
 | 
			
		||||
		     /* 64-255: User Defined                                   */
 | 
			
		||||
		  4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
 | 
			
		||||
		  4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
 | 
			
		||||
		  4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
 | 
			
		||||
		  4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
 | 
			
		||||
		  4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
 | 
			
		||||
		  4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4
 | 
			
		||||
	}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
uint8 m68ki_ea_idx_cycle_table[64] =
 | 
			
		||||
{
 | 
			
		||||
	 0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
 | 
			
		||||
	 0, /* ..01.000 no memory indirect, base NULL             */
 | 
			
		||||
	 5, /* ..01..01 memory indirect,    base NULL, outer NULL */
 | 
			
		||||
	 7, /* ..01..10 memory indirect,    base NULL, outer 16   */
 | 
			
		||||
	 7, /* ..01..11 memory indirect,    base NULL, outer 32   */
 | 
			
		||||
	 0,  5,  7,  7,  0,  5,  7,  7,  0,  5,  7,  7,
 | 
			
		||||
	 2, /* ..10.000 no memory indirect, base 16               */
 | 
			
		||||
	 7, /* ..10..01 memory indirect,    base 16,   outer NULL */
 | 
			
		||||
	 9, /* ..10..10 memory indirect,    base 16,   outer 16   */
 | 
			
		||||
	 9, /* ..10..11 memory indirect,    base 16,   outer 32   */
 | 
			
		||||
	 0,  7,  9,  9,  0,  7,  9,  9,  0,  7,  9,  9,
 | 
			
		||||
	 6, /* ..11.000 no memory indirect, base 32               */
 | 
			
		||||
	11, /* ..11..01 memory indirect,    base 32,   outer NULL */
 | 
			
		||||
	13, /* ..11..10 memory indirect,    base 32,   outer 16   */
 | 
			
		||||
	13, /* ..11..11 memory indirect,    base 32,   outer 32   */
 | 
			
		||||
	 0, 11, 13, 13,  0, 11, 13, 13,  0, 11, 13, 13
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* ======================================================================== */
 | 
			
		||||
/* =============================== CALLBACKS ============================== */
 | 
			
		||||
/* ======================================================================== */
 | 
			
		||||
 | 
			
		||||
/* Default callbacks used if the callback hasn't been set yet, or if the
 | 
			
		||||
 * callback is set to NULL
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
/* Interrupt acknowledge */
 | 
			
		||||
static int default_int_ack_callback_data;
 | 
			
		||||
static int default_int_ack_callback(int int_level)
 | 
			
		||||
{
 | 
			
		||||
	default_int_ack_callback_data = int_level;
 | 
			
		||||
	CPU_INT_LEVEL = 0;
 | 
			
		||||
	return M68K_INT_ACK_AUTOVECTOR;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Breakpoint acknowledge */
 | 
			
		||||
static unsigned int default_bkpt_ack_callback_data;
 | 
			
		||||
static void default_bkpt_ack_callback(unsigned int data)
 | 
			
		||||
{
 | 
			
		||||
	default_bkpt_ack_callback_data = data;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Called when a reset instruction is executed */
 | 
			
		||||
static void default_reset_instr_callback(void)
 | 
			
		||||
{
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Called when the program counter changed by a large value */
 | 
			
		||||
static unsigned int default_pc_changed_callback_data;
 | 
			
		||||
static void default_pc_changed_callback(unsigned int new_pc)
 | 
			
		||||
{
 | 
			
		||||
	default_pc_changed_callback_data = new_pc;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Called every time there's bus activity (read/write to/from memory */
 | 
			
		||||
static unsigned int default_set_fc_callback_data;
 | 
			
		||||
static void default_set_fc_callback(unsigned int new_fc)
 | 
			
		||||
{
 | 
			
		||||
	default_set_fc_callback_data = new_fc;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Called every instruction cycle prior to execution */
 | 
			
		||||
static void default_instr_hook_callback(void)
 | 
			
		||||
{
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#if M68K_EMULATE_ADDRESS_ERROR
 | 
			
		||||
	#include <setjmp.h>
 | 
			
		||||
	jmp_buf m68ki_aerr_trap;
 | 
			
		||||
#endif /* M68K_EMULATE_ADDRESS_ERROR */
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* ======================================================================== */
 | 
			
		||||
/* ================================= API ================================== */
 | 
			
		||||
/* ======================================================================== */
 | 
			
		||||
 | 
			
		||||
/* Access the internals of the CPU */
 | 
			
		||||
unsigned int m68k_get_reg(void* context, m68k_register_t regnum)
 | 
			
		||||
{
 | 
			
		||||
	m68ki_cpu_core* cpu = context != NULL ?(m68ki_cpu_core*)context : &m68ki_cpu;
 | 
			
		||||
 | 
			
		||||
	switch(regnum)
 | 
			
		||||
	{
 | 
			
		||||
		case M68K_REG_D0:	return cpu->dar[0];
 | 
			
		||||
		case M68K_REG_D1:	return cpu->dar[1];
 | 
			
		||||
		case M68K_REG_D2:	return cpu->dar[2];
 | 
			
		||||
		case M68K_REG_D3:	return cpu->dar[3];
 | 
			
		||||
		case M68K_REG_D4:	return cpu->dar[4];
 | 
			
		||||
		case M68K_REG_D5:	return cpu->dar[5];
 | 
			
		||||
		case M68K_REG_D6:	return cpu->dar[6];
 | 
			
		||||
		case M68K_REG_D7:	return cpu->dar[7];
 | 
			
		||||
		case M68K_REG_A0:	return cpu->dar[8];
 | 
			
		||||
		case M68K_REG_A1:	return cpu->dar[9];
 | 
			
		||||
		case M68K_REG_A2:	return cpu->dar[10];
 | 
			
		||||
		case M68K_REG_A3:	return cpu->dar[11];
 | 
			
		||||
		case M68K_REG_A4:	return cpu->dar[12];
 | 
			
		||||
		case M68K_REG_A5:	return cpu->dar[13];
 | 
			
		||||
		case M68K_REG_A6:	return cpu->dar[14];
 | 
			
		||||
		case M68K_REG_A7:	return cpu->dar[15];
 | 
			
		||||
		case M68K_REG_PC:	return MASK_OUT_ABOVE_32(cpu->pc);
 | 
			
		||||
		case M68K_REG_SR:	return	cpu->t1_flag						|
 | 
			
		||||
									cpu->t0_flag						|
 | 
			
		||||
									(cpu->s_flag << 11)					|
 | 
			
		||||
									(cpu->m_flag << 11)					|
 | 
			
		||||
									cpu->int_mask						|
 | 
			
		||||
									((cpu->x_flag & XFLAG_SET) >> 4)	|
 | 
			
		||||
									((cpu->n_flag & NFLAG_SET) >> 4)	|
 | 
			
		||||
									((!cpu->not_z_flag) << 2)			|
 | 
			
		||||
									((cpu->v_flag & VFLAG_SET) >> 6)	|
 | 
			
		||||
									((cpu->c_flag & CFLAG_SET) >> 8);
 | 
			
		||||
		case M68K_REG_SP:	return cpu->dar[15];
 | 
			
		||||
		case M68K_REG_USP:	return cpu->s_flag ? cpu->sp[0] : cpu->dar[15];
 | 
			
		||||
		case M68K_REG_ISP:	return cpu->s_flag && !cpu->m_flag ? cpu->dar[15] : cpu->sp[4];
 | 
			
		||||
		case M68K_REG_MSP:	return cpu->s_flag && cpu->m_flag ? cpu->dar[15] : cpu->sp[6];
 | 
			
		||||
		case M68K_REG_SFC:	return cpu->sfc;
 | 
			
		||||
		case M68K_REG_DFC:	return cpu->dfc;
 | 
			
		||||
		case M68K_REG_VBR:	return cpu->vbr;
 | 
			
		||||
		case M68K_REG_CACR:	return cpu->cacr;
 | 
			
		||||
		case M68K_REG_CAAR:	return cpu->caar;
 | 
			
		||||
		case M68K_REG_PREF_ADDR:	return cpu->pref_addr;
 | 
			
		||||
		case M68K_REG_PREF_DATA:	return cpu->pref_data;
 | 
			
		||||
		case M68K_REG_PPC:	return MASK_OUT_ABOVE_32(cpu->ppc);
 | 
			
		||||
		case M68K_REG_IR:	return cpu->ir;
 | 
			
		||||
		case M68K_REG_CPU_TYPE:
 | 
			
		||||
			switch(cpu->cpu_type)
 | 
			
		||||
			{
 | 
			
		||||
				case CPU_TYPE_000:		return (unsigned int)M68K_CPU_TYPE_68000;
 | 
			
		||||
				case CPU_TYPE_010:		return (unsigned int)M68K_CPU_TYPE_68010;
 | 
			
		||||
				case CPU_TYPE_EC020:	return (unsigned int)M68K_CPU_TYPE_68EC020;
 | 
			
		||||
				case CPU_TYPE_020:		return (unsigned int)M68K_CPU_TYPE_68020;
 | 
			
		||||
			}
 | 
			
		||||
			return M68K_CPU_TYPE_INVALID;
 | 
			
		||||
		default:			return 0;
 | 
			
		||||
	}
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void m68k_set_reg(m68k_register_t regnum, unsigned int value)
 | 
			
		||||
{
 | 
			
		||||
	switch(regnum)
 | 
			
		||||
	{
 | 
			
		||||
		case M68K_REG_D0:	REG_D[0] = MASK_OUT_ABOVE_32(value); return;
 | 
			
		||||
		case M68K_REG_D1:	REG_D[1] = MASK_OUT_ABOVE_32(value); return;
 | 
			
		||||
		case M68K_REG_D2:	REG_D[2] = MASK_OUT_ABOVE_32(value); return;
 | 
			
		||||
		case M68K_REG_D3:	REG_D[3] = MASK_OUT_ABOVE_32(value); return;
 | 
			
		||||
		case M68K_REG_D4:	REG_D[4] = MASK_OUT_ABOVE_32(value); return;
 | 
			
		||||
		case M68K_REG_D5:	REG_D[5] = MASK_OUT_ABOVE_32(value); return;
 | 
			
		||||
		case M68K_REG_D6:	REG_D[6] = MASK_OUT_ABOVE_32(value); return;
 | 
			
		||||
		case M68K_REG_D7:	REG_D[7] = MASK_OUT_ABOVE_32(value); return;
 | 
			
		||||
		case M68K_REG_A0:	REG_A[0] = MASK_OUT_ABOVE_32(value); return;
 | 
			
		||||
		case M68K_REG_A1:	REG_A[1] = MASK_OUT_ABOVE_32(value); return;
 | 
			
		||||
		case M68K_REG_A2:	REG_A[2] = MASK_OUT_ABOVE_32(value); return;
 | 
			
		||||
		case M68K_REG_A3:	REG_A[3] = MASK_OUT_ABOVE_32(value); return;
 | 
			
		||||
		case M68K_REG_A4:	REG_A[4] = MASK_OUT_ABOVE_32(value); return;
 | 
			
		||||
		case M68K_REG_A5:	REG_A[5] = MASK_OUT_ABOVE_32(value); return;
 | 
			
		||||
		case M68K_REG_A6:	REG_A[6] = MASK_OUT_ABOVE_32(value); return;
 | 
			
		||||
		case M68K_REG_A7:	REG_A[7] = MASK_OUT_ABOVE_32(value); return;
 | 
			
		||||
		case M68K_REG_PC:	m68ki_jump(MASK_OUT_ABOVE_32(value)); return;
 | 
			
		||||
		case M68K_REG_SR:	m68ki_set_sr(value); return;
 | 
			
		||||
		case M68K_REG_SP:	REG_SP = MASK_OUT_ABOVE_32(value); return;
 | 
			
		||||
		case M68K_REG_USP:	if(FLAG_S)
 | 
			
		||||
								REG_USP = MASK_OUT_ABOVE_32(value);
 | 
			
		||||
							else
 | 
			
		||||
								REG_SP = MASK_OUT_ABOVE_32(value);
 | 
			
		||||
							return;
 | 
			
		||||
		case M68K_REG_ISP:	if(FLAG_S && !FLAG_M)
 | 
			
		||||
								REG_SP = MASK_OUT_ABOVE_32(value);
 | 
			
		||||
							else
 | 
			
		||||
								REG_ISP = MASK_OUT_ABOVE_32(value);
 | 
			
		||||
							return;
 | 
			
		||||
		case M68K_REG_MSP:	if(FLAG_S && FLAG_M)
 | 
			
		||||
								REG_SP = MASK_OUT_ABOVE_32(value);
 | 
			
		||||
							else
 | 
			
		||||
								REG_MSP = MASK_OUT_ABOVE_32(value);
 | 
			
		||||
							return;
 | 
			
		||||
		case M68K_REG_VBR:	REG_VBR = MASK_OUT_ABOVE_32(value); return;
 | 
			
		||||
		case M68K_REG_SFC:	REG_SFC = value & 7; return;
 | 
			
		||||
		case M68K_REG_DFC:	REG_DFC = value & 7; return;
 | 
			
		||||
		case M68K_REG_CACR:	REG_CACR = MASK_OUT_ABOVE_32(value); return;
 | 
			
		||||
		case M68K_REG_CAAR:	REG_CAAR = MASK_OUT_ABOVE_32(value); return;
 | 
			
		||||
		case M68K_REG_PPC:	REG_PPC = MASK_OUT_ABOVE_32(value); return;
 | 
			
		||||
		case M68K_REG_IR:	REG_IR = MASK_OUT_ABOVE_16(value); return;
 | 
			
		||||
		case M68K_REG_CPU_TYPE: m68k_set_cpu_type(value); return;
 | 
			
		||||
		default:			return;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Set the callbacks */
 | 
			
		||||
void m68k_set_int_ack_callback(int  (*callback)(int int_level))
 | 
			
		||||
{
 | 
			
		||||
	CALLBACK_INT_ACK = callback ? callback : default_int_ack_callback;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void m68k_set_bkpt_ack_callback(void  (*callback)(unsigned int data))
 | 
			
		||||
{
 | 
			
		||||
	CALLBACK_BKPT_ACK = callback ? callback : default_bkpt_ack_callback;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void m68k_set_reset_instr_callback(void  (*callback)(void))
 | 
			
		||||
{
 | 
			
		||||
	CALLBACK_RESET_INSTR = callback ? callback : default_reset_instr_callback;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void m68k_set_pc_changed_callback(void  (*callback)(unsigned int new_pc))
 | 
			
		||||
{
 | 
			
		||||
	CALLBACK_PC_CHANGED = callback ? callback : default_pc_changed_callback;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void m68k_set_fc_callback(void  (*callback)(unsigned int new_fc))
 | 
			
		||||
{
 | 
			
		||||
	CALLBACK_SET_FC = callback ? callback : default_set_fc_callback;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void m68k_set_instr_hook_callback(void  (*callback)(void))
 | 
			
		||||
{
 | 
			
		||||
	CALLBACK_INSTR_HOOK = callback ? callback : default_instr_hook_callback;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
/* Set the CPU type. */
 | 
			
		||||
void m68k_set_cpu_type(unsigned int cpu_type)
 | 
			
		||||
{
 | 
			
		||||
	switch(cpu_type)
 | 
			
		||||
	{
 | 
			
		||||
		case M68K_CPU_TYPE_68000:
 | 
			
		||||
			CPU_TYPE         = CPU_TYPE_000;
 | 
			
		||||
			CPU_ADDRESS_MASK = 0x00ffffff;
 | 
			
		||||
			CPU_SR_MASK      = 0xa71f; /* T1 -- S  -- -- I2 I1 I0 -- -- -- X  N  Z  V  C  */
 | 
			
		||||
			CYC_INSTRUCTION  = m68ki_cycles[0];
 | 
			
		||||
			CYC_EXCEPTION    = m68ki_exception_cycle_table[0];
 | 
			
		||||
			CYC_BCC_NOTAKE_B = -2;
 | 
			
		||||
			CYC_BCC_NOTAKE_W = 2;
 | 
			
		||||
			CYC_DBCC_F_NOEXP = -2;
 | 
			
		||||
			CYC_DBCC_F_EXP   = 2;
 | 
			
		||||
			CYC_SCC_R_TRUE   = 2;
 | 
			
		||||
			CYC_MOVEM_W      = 2;
 | 
			
		||||
			CYC_MOVEM_L      = 3;
 | 
			
		||||
			CYC_SHIFT        = 1;
 | 
			
		||||
			CYC_RESET        = 132;
 | 
			
		||||
			return;
 | 
			
		||||
		case M68K_CPU_TYPE_68010:
 | 
			
		||||
			CPU_TYPE         = CPU_TYPE_010;
 | 
			
		||||
			CPU_ADDRESS_MASK = 0x00ffffff;
 | 
			
		||||
			CPU_SR_MASK      = 0xa71f; /* T1 -- S  -- -- I2 I1 I0 -- -- -- X  N  Z  V  C  */
 | 
			
		||||
			CYC_INSTRUCTION  = m68ki_cycles[1];
 | 
			
		||||
			CYC_EXCEPTION    = m68ki_exception_cycle_table[1];
 | 
			
		||||
			CYC_BCC_NOTAKE_B = -4;
 | 
			
		||||
			CYC_BCC_NOTAKE_W = 0;
 | 
			
		||||
			CYC_DBCC_F_NOEXP = 0;
 | 
			
		||||
			CYC_DBCC_F_EXP   = 6;
 | 
			
		||||
			CYC_SCC_R_TRUE   = 0;
 | 
			
		||||
			CYC_MOVEM_W      = 2;
 | 
			
		||||
			CYC_MOVEM_L      = 3;
 | 
			
		||||
			CYC_SHIFT        = 1;
 | 
			
		||||
			CYC_RESET        = 130;
 | 
			
		||||
			return;
 | 
			
		||||
		case M68K_CPU_TYPE_68EC020:
 | 
			
		||||
			CPU_TYPE         = CPU_TYPE_EC020;
 | 
			
		||||
			CPU_ADDRESS_MASK = 0x00ffffff;
 | 
			
		||||
			CPU_SR_MASK      = 0xf71f; /* T1 T0 S  M  -- I2 I1 I0 -- -- -- X  N  Z  V  C  */
 | 
			
		||||
			CYC_INSTRUCTION  = m68ki_cycles[2];
 | 
			
		||||
			CYC_EXCEPTION    = m68ki_exception_cycle_table[2];
 | 
			
		||||
			CYC_BCC_NOTAKE_B = -2;
 | 
			
		||||
			CYC_BCC_NOTAKE_W = 0;
 | 
			
		||||
			CYC_DBCC_F_NOEXP = 0;
 | 
			
		||||
			CYC_DBCC_F_EXP   = 4;
 | 
			
		||||
			CYC_SCC_R_TRUE   = 0;
 | 
			
		||||
			CYC_MOVEM_W      = 2;
 | 
			
		||||
			CYC_MOVEM_L      = 2;
 | 
			
		||||
			CYC_SHIFT        = 0;
 | 
			
		||||
			CYC_RESET        = 518;
 | 
			
		||||
			return;
 | 
			
		||||
		case M68K_CPU_TYPE_68020:
 | 
			
		||||
			CPU_TYPE         = CPU_TYPE_020;
 | 
			
		||||
			CPU_ADDRESS_MASK = 0xffffffff;
 | 
			
		||||
			CPU_SR_MASK      = 0xf71f; /* T1 T0 S  M  -- I2 I1 I0 -- -- -- X  N  Z  V  C  */
 | 
			
		||||
			CYC_INSTRUCTION  = m68ki_cycles[2];
 | 
			
		||||
			CYC_EXCEPTION    = m68ki_exception_cycle_table[2];
 | 
			
		||||
			CYC_BCC_NOTAKE_B = -2;
 | 
			
		||||
			CYC_BCC_NOTAKE_W = 0;
 | 
			
		||||
			CYC_DBCC_F_NOEXP = 0;
 | 
			
		||||
			CYC_DBCC_F_EXP   = 4;
 | 
			
		||||
			CYC_SCC_R_TRUE   = 0;
 | 
			
		||||
			CYC_MOVEM_W      = 2;
 | 
			
		||||
			CYC_MOVEM_L      = 2;
 | 
			
		||||
			CYC_SHIFT        = 0;
 | 
			
		||||
			CYC_RESET        = 518;
 | 
			
		||||
			return;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Execute some instructions until we use up num_cycles clock cycles */
 | 
			
		||||
/* ASG: removed per-instruction interrupt checks */
 | 
			
		||||
int m68k_execute(int num_cycles)
 | 
			
		||||
{
 | 
			
		||||
	/* Make sure we're not stopped */
 | 
			
		||||
	if(!CPU_STOPPED)
 | 
			
		||||
	{
 | 
			
		||||
		/* Set our pool of clock cycles available */
 | 
			
		||||
		SET_CYCLES(num_cycles);
 | 
			
		||||
		m68ki_initial_cycles = num_cycles;
 | 
			
		||||
 | 
			
		||||
		/* ASG: update cycles */
 | 
			
		||||
		USE_CYCLES(CPU_INT_CYCLES);
 | 
			
		||||
		CPU_INT_CYCLES = 0;
 | 
			
		||||
 | 
			
		||||
		/* Return point if we had an address error */
 | 
			
		||||
		m68ki_set_address_error_trap(); /* auto-disable (see m68kcpu.h) */
 | 
			
		||||
 | 
			
		||||
		/* Main loop.  Keep going until we run out of clock cycles */
 | 
			
		||||
		do
 | 
			
		||||
		{
 | 
			
		||||
			/* Set tracing accodring to T1. (T0 is done inside instruction) */
 | 
			
		||||
			m68ki_trace_t1(); /* auto-disable (see m68kcpu.h) */
 | 
			
		||||
 | 
			
		||||
			/* Set the address space for reads */
 | 
			
		||||
			m68ki_use_data_space(); /* auto-disable (see m68kcpu.h) */
 | 
			
		||||
 | 
			
		||||
			/* Call external hook to peek at CPU */
 | 
			
		||||
			m68ki_instr_hook(); /* auto-disable (see m68kcpu.h) */
 | 
			
		||||
 | 
			
		||||
			/* Record previous program counter */
 | 
			
		||||
			REG_PPC = REG_PC;
 | 
			
		||||
 | 
			
		||||
			/* Read an instruction and call its handler */
 | 
			
		||||
			REG_IR = m68ki_read_imm_16();
 | 
			
		||||
			m68ki_instruction_jump_table[REG_IR]();
 | 
			
		||||
			USE_CYCLES(CYC_INSTRUCTION[REG_IR]);
 | 
			
		||||
 | 
			
		||||
			/* Trace m68k_exception, if necessary */
 | 
			
		||||
			m68ki_exception_if_trace(); /* auto-disable (see m68kcpu.h) */
 | 
			
		||||
		} while(GET_CYCLES() > 0);
 | 
			
		||||
 | 
			
		||||
		/* set previous PC to current PC for the next entry into the loop */
 | 
			
		||||
		REG_PPC = REG_PC;
 | 
			
		||||
 | 
			
		||||
		/* ASG: update cycles */
 | 
			
		||||
		USE_CYCLES(CPU_INT_CYCLES);
 | 
			
		||||
		CPU_INT_CYCLES = 0;
 | 
			
		||||
 | 
			
		||||
		/* return how many clocks we used */
 | 
			
		||||
		return m68ki_initial_cycles - GET_CYCLES();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* We get here if the CPU is stopped or halted */
 | 
			
		||||
	SET_CYCLES(0);
 | 
			
		||||
	CPU_INT_CYCLES = 0;
 | 
			
		||||
 | 
			
		||||
	return num_cycles;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
int m68k_cycles_run(void)
 | 
			
		||||
{
 | 
			
		||||
	return m68ki_initial_cycles - GET_CYCLES();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int m68k_cycles_remaining(void)
 | 
			
		||||
{
 | 
			
		||||
	return GET_CYCLES();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Change the timeslice */
 | 
			
		||||
void m68k_modify_timeslice(int cycles)
 | 
			
		||||
{
 | 
			
		||||
	m68ki_initial_cycles += cycles;
 | 
			
		||||
	ADD_CYCLES(cycles);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
void m68k_end_timeslice(void)
 | 
			
		||||
{
 | 
			
		||||
	m68ki_initial_cycles = GET_CYCLES();
 | 
			
		||||
	SET_CYCLES(0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* ASG: rewrote so that the int_level is a mask of the IPL0/IPL1/IPL2 bits */
 | 
			
		||||
/* KS: Modified so that IPL* bits match with mask positions in the SR
 | 
			
		||||
 *     and cleaned out remenants of the interrupt controller.
 | 
			
		||||
 */
 | 
			
		||||
void m68k_set_irq(unsigned int int_level)
 | 
			
		||||
{
 | 
			
		||||
	uint old_level = CPU_INT_LEVEL;
 | 
			
		||||
	CPU_INT_LEVEL = int_level << 8;
 | 
			
		||||
 | 
			
		||||
	/* A transition from < 7 to 7 always interrupts (NMI) */
 | 
			
		||||
	/* Note: Level 7 can also level trigger like a normal IRQ */
 | 
			
		||||
	if(old_level != 0x0700 && CPU_INT_LEVEL == 0x0700)
 | 
			
		||||
		m68ki_exception_interrupt(7); /* Edge triggered level 7 (NMI) */
 | 
			
		||||
	else
 | 
			
		||||
		m68ki_check_interrupts(); /* Level triggered (IRQ) */
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void m68k_init(void)
 | 
			
		||||
{
 | 
			
		||||
	static uint emulation_initialized = 0;
 | 
			
		||||
 | 
			
		||||
	/* The first call to this function initializes the opcode handler jump table */
 | 
			
		||||
	if(!emulation_initialized)
 | 
			
		||||
		{
 | 
			
		||||
		m68ki_build_opcode_table();
 | 
			
		||||
		emulation_initialized = 1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	m68k_set_int_ack_callback(NULL);
 | 
			
		||||
	m68k_set_bkpt_ack_callback(NULL);
 | 
			
		||||
	m68k_set_reset_instr_callback(NULL);
 | 
			
		||||
	m68k_set_pc_changed_callback(NULL);
 | 
			
		||||
	m68k_set_fc_callback(NULL);
 | 
			
		||||
	m68k_set_instr_hook_callback(NULL);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Pulse the RESET line on the CPU */
 | 
			
		||||
void m68k_pulse_reset(void)
 | 
			
		||||
{
 | 
			
		||||
	/* Clear all stop levels and eat up all remaining cycles */
 | 
			
		||||
	CPU_STOPPED = 0;
 | 
			
		||||
	SET_CYCLES(0);
 | 
			
		||||
 | 
			
		||||
	CPU_RUN_MODE = RUN_MODE_BERR_AERR_RESET;
 | 
			
		||||
	CPU_INSTR_MODE = INSTRUCTION_YES;
 | 
			
		||||
 | 
			
		||||
	/* Turn off tracing */
 | 
			
		||||
	FLAG_T1 = FLAG_T0 = 0;
 | 
			
		||||
	m68ki_clear_trace();
 | 
			
		||||
	/* Interrupt mask to level 7 */
 | 
			
		||||
	FLAG_INT_MASK = 0x0700;
 | 
			
		||||
	/* Reset VBR */
 | 
			
		||||
	REG_VBR = 0;
 | 
			
		||||
	/* Go to supervisor mode */
 | 
			
		||||
	m68ki_set_sm_flag(SFLAG_SET | MFLAG_CLEAR);
 | 
			
		||||
 | 
			
		||||
	/* Invalidate the prefetch queue */
 | 
			
		||||
#if M68K_EMULATE_PREFETCH
 | 
			
		||||
	/* Set to arbitrary number since our first fetch is from 0 */
 | 
			
		||||
	CPU_PREF_ADDR = 0x1000;
 | 
			
		||||
#endif /* M68K_EMULATE_PREFETCH */
 | 
			
		||||
 | 
			
		||||
	/* Read the initial stack pointer and program counter */
 | 
			
		||||
	m68ki_jump(0);
 | 
			
		||||
	REG_SP = m68ki_read_imm_32();
 | 
			
		||||
	REG_PC = m68ki_read_imm_32();
 | 
			
		||||
	m68ki_jump(REG_PC);
 | 
			
		||||
 | 
			
		||||
	CPU_RUN_MODE = RUN_MODE_NORMAL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Pulse the HALT line on the CPU */
 | 
			
		||||
void m68k_pulse_halt(void)
 | 
			
		||||
{
 | 
			
		||||
	CPU_STOPPED |= STOP_LEVEL_HALT;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* Get and set the current CPU context */
 | 
			
		||||
/* This is to allow for multiple CPUs */
 | 
			
		||||
unsigned int m68k_context_size()
 | 
			
		||||
{
 | 
			
		||||
	return sizeof(m68ki_cpu_core);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
unsigned int m68k_get_context(void* dst)
 | 
			
		||||
{
 | 
			
		||||
	if(dst) *(m68ki_cpu_core*)dst = m68ki_cpu;
 | 
			
		||||
	return sizeof(m68ki_cpu_core);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void m68k_set_context(void* src)
 | 
			
		||||
{
 | 
			
		||||
	if(src) m68ki_cpu = *(m68ki_cpu_core*)src;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* ======================================================================== */
 | 
			
		||||
/* ============================== MAME STUFF ============================== */
 | 
			
		||||
/* ======================================================================== */
 | 
			
		||||
 | 
			
		||||
#if M68K_COMPILE_FOR_MAME == OPT_ON
 | 
			
		||||
 | 
			
		||||
#include "state.h"
 | 
			
		||||
 | 
			
		||||
static struct {
 | 
			
		||||
	UINT16 sr;
 | 
			
		||||
	int stopped;
 | 
			
		||||
	int halted;
 | 
			
		||||
} m68k_substate;
 | 
			
		||||
 | 
			
		||||
static void m68k_prepare_substate(void)
 | 
			
		||||
{
 | 
			
		||||
	m68k_substate.sr = m68ki_get_sr();
 | 
			
		||||
	m68k_substate.stopped = (CPU_STOPPED & STOP_LEVEL_STOP) != 0;
 | 
			
		||||
	m68k_substate.halted  = (CPU_STOPPED & STOP_LEVEL_HALT) != 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void m68k_post_load(void)
 | 
			
		||||
{
 | 
			
		||||
	m68ki_set_sr_noint_nosp(m68k_substate.sr);
 | 
			
		||||
	CPU_STOPPED = m68k_substate.stopped ? STOP_LEVEL_STOP : 0
 | 
			
		||||
		        | m68k_substate.halted  ? STOP_LEVEL_HALT : 0;
 | 
			
		||||
	m68ki_jump(REG_PC);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void m68k_state_register(const char *type)
 | 
			
		||||
{
 | 
			
		||||
	int cpu = cpu_getactivecpu();
 | 
			
		||||
 | 
			
		||||
	state_save_register_UINT32(type, cpu, "D"         , REG_D, 8);
 | 
			
		||||
	state_save_register_UINT32(type, cpu, "A"         , REG_A, 8);
 | 
			
		||||
	state_save_register_UINT32(type, cpu, "PPC"       , ®_PPC, 1);
 | 
			
		||||
	state_save_register_UINT32(type, cpu, "PC"        , ®_PC, 1);
 | 
			
		||||
	state_save_register_UINT32(type, cpu, "USP"       , ®_USP, 1);
 | 
			
		||||
	state_save_register_UINT32(type, cpu, "ISP"       , ®_ISP, 1);
 | 
			
		||||
	state_save_register_UINT32(type, cpu, "MSP"       , ®_MSP, 1);
 | 
			
		||||
	state_save_register_UINT32(type, cpu, "VBR"       , ®_VBR, 1);
 | 
			
		||||
	state_save_register_UINT32(type, cpu, "SFC"       , ®_SFC, 1);
 | 
			
		||||
	state_save_register_UINT32(type, cpu, "DFC"       , ®_DFC, 1);
 | 
			
		||||
	state_save_register_UINT32(type, cpu, "CACR"      , ®_CACR, 1);
 | 
			
		||||
	state_save_register_UINT32(type, cpu, "CAAR"      , ®_CAAR, 1);
 | 
			
		||||
	state_save_register_UINT16(type, cpu, "SR"        , &m68k_substate.sr, 1);
 | 
			
		||||
	state_save_register_UINT32(type, cpu, "INT_LEVEL" , &CPU_INT_LEVEL, 1);
 | 
			
		||||
	state_save_register_UINT32(type, cpu, "INT_CYCLES", &CPU_INT_CYCLES, 1);
 | 
			
		||||
	state_save_register_int   (type, cpu, "STOPPED"   , &m68k_substate.stopped);
 | 
			
		||||
	state_save_register_int   (type, cpu, "HALTED"    , &m68k_substate.halted);
 | 
			
		||||
	state_save_register_UINT32(type, cpu, "PREF_ADDR" , &CPU_PREF_ADDR, 1);
 | 
			
		||||
	state_save_register_UINT32(type, cpu, "PREF_DATA" , &CPU_PREF_DATA, 1);
 | 
			
		||||
	state_save_register_func_presave(m68k_prepare_substate);
 | 
			
		||||
	state_save_register_func_postload(m68k_post_load);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#endif /* M68K_COMPILE_FOR_MAME */
 | 
			
		||||
 | 
			
		||||
/* ======================================================================== */
 | 
			
		||||
/* ============================== END OF FILE ============================= */
 | 
			
		||||
/* ======================================================================== */
 | 
			
		||||
							
								
								
									
										1985
									
								
								plat/linux68k/emu/musashi/m68kcpu.h
									
										
									
									
									
										Executable file
									
								
							
							
						
						
									
										1985
									
								
								plat/linux68k/emu/musashi/m68kcpu.h
									
										
									
									
									
										Executable file
									
								
							
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							
							
								
								
									
										3477
									
								
								plat/linux68k/emu/musashi/m68kdasm.c
									
										
									
									
									
										Executable file
									
								
							
							
						
						
									
										3477
									
								
								plat/linux68k/emu/musashi/m68kdasm.c
									
										
									
									
									
										Executable file
									
								
							
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							
							
								
								
									
										1429
									
								
								plat/linux68k/emu/musashi/m68kmake.c
									
										
									
									
									
										Executable file
									
								
							
							
						
						
									
										1429
									
								
								plat/linux68k/emu/musashi/m68kmake.c
									
										
									
									
									
										Executable file
									
								
							
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							
							
								
								
									
										305
									
								
								plat/linux68k/emu/musashi/readme.txt
									
										
									
									
									
										Executable file
									
								
							
							
						
						
									
										305
									
								
								plat/linux68k/emu/musashi/readme.txt
									
										
									
									
									
										Executable file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,305 @@
 | 
			
		|||
                                    MUSASHI
 | 
			
		||||
                                    =======
 | 
			
		||||
 | 
			
		||||
                                  Version 3.4
 | 
			
		||||
 | 
			
		||||
             A portable Motorola M680x0 processor emulation engine.
 | 
			
		||||
            Copyright 1998-2002 Karl Stenerud.  All rights reserved.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
INTRODUCTION:
 | 
			
		||||
------------
 | 
			
		||||
 | 
			
		||||
Musashi is a Motorola 68000, 68010, 68EC020, and 68020 emulator written in C.
 | 
			
		||||
This emulator was written with two goals in mind: portability and speed.
 | 
			
		||||
 | 
			
		||||
The emulator is written to ANSI C89 specifications.  It also uses inline
 | 
			
		||||
functions, which are C9X compliant.
 | 
			
		||||
 | 
			
		||||
It has been successfully running in the MAME project (www.mame.net) for years
 | 
			
		||||
and so has had time to mature.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
LICENSE AND COPYRIGHT:
 | 
			
		||||
---------------------
 | 
			
		||||
 | 
			
		||||
Copyright © 1998-2001 Karl Stenerud
 | 
			
		||||
 | 
			
		||||
Permission is hereby granted, free of charge, to any person obtaining a copy
 | 
			
		||||
of this software and associated documentation files (the "Software"), to deal
 | 
			
		||||
in the Software without restriction, including without limitation the rights
 | 
			
		||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 | 
			
		||||
copies of the Software, and to permit persons to whom the Software is
 | 
			
		||||
furnished to do so, subject to the following conditions:
 | 
			
		||||
 | 
			
		||||
The above copyright notice and this permission notice shall be included in
 | 
			
		||||
all copies or substantial portions of the Software.
 | 
			
		||||
 | 
			
		||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 | 
			
		||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 | 
			
		||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 | 
			
		||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 | 
			
		||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 | 
			
		||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 | 
			
		||||
THE SOFTWARE.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
AVAILABILITY:
 | 
			
		||||
------------
 | 
			
		||||
The latest version of this code can be obtained at:
 | 
			
		||||
https://github.com/kstenerud/Musashi
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
CONTACTING THE AUTHOR:
 | 
			
		||||
---------------------
 | 
			
		||||
I can be reached at kstenerud@gmail.com
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
BASIC CONFIGURATION:
 | 
			
		||||
-------------------
 | 
			
		||||
The basic configuration will give you a standard 68000 that has sufficient
 | 
			
		||||
functionality to work in a primitive environment.
 | 
			
		||||
 | 
			
		||||
This setup assumes that you only have 1 device interrupting it, that the
 | 
			
		||||
device will always request an autovectored interrupt, and it will always clear
 | 
			
		||||
the interrupt before the interrupt service routine finishes (but could
 | 
			
		||||
possibly re-assert the interrupt).
 | 
			
		||||
You will have only one address space, no tracing, and no instruction prefetch.
 | 
			
		||||
 | 
			
		||||
To implement the basic configuration:
 | 
			
		||||
 | 
			
		||||
- Open m68kconf.h and verify that the settings for INLINE will work with your
 | 
			
		||||
  compiler. (Currently set to "static __inline__", which works in gcc 2.9.
 | 
			
		||||
  For C9X compliance, it should be "inline")
 | 
			
		||||
 | 
			
		||||
- In your host program, implement the following functions:
 | 
			
		||||
    unsigned int  m68k_read_memory_8(unsigned int address);
 | 
			
		||||
    unsigned int  m68k_read_memory_16(unsigned int address);
 | 
			
		||||
    unsigned int  m68k_read_memory_32(unsigned int address);
 | 
			
		||||
    void m68k_write_memory_8(unsigned int address, unsigned int value);
 | 
			
		||||
    void m68k_write_memory_16(unsigned int address, unsigned int value);
 | 
			
		||||
    void m68k_write_memory_32(unsigned int address, unsigned int value);
 | 
			
		||||
 | 
			
		||||
- In your host program, be sure to call m68k_pulse_reset() once before calling
 | 
			
		||||
  any of the other functions as this initializes the core.
 | 
			
		||||
 | 
			
		||||
- Use m68k_execute() to execute instructions and m68k_set_irq() to cause an
 | 
			
		||||
  interrupt.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
ADDING PROPER INTERRUPT HANDLING:
 | 
			
		||||
--------------------------------
 | 
			
		||||
The interrupt handling in the basic configuration doesn't emulate the
 | 
			
		||||
interrupt acknowledge phase of the CPU and automatically clears an interrupt
 | 
			
		||||
request during interrupt processing.
 | 
			
		||||
While this works for most systems, you may need more accurate interrupt
 | 
			
		||||
handling.
 | 
			
		||||
 | 
			
		||||
To add proper interrupt handling:
 | 
			
		||||
 | 
			
		||||
- In m68kconf.h, set M68K_EMULATE_INT_ACK to OPT_SPECIFY_HANDLER
 | 
			
		||||
 | 
			
		||||
- In m68kconf.h, set M68K_INT_ACK_CALLBACK(A) to your interrupt acknowledge
 | 
			
		||||
  routine
 | 
			
		||||
 | 
			
		||||
- Your interrupt acknowledge routine must return an interrupt vector,
 | 
			
		||||
  M68K_INT_ACK_AUTOVECTOR, or M68K_INT_ACK_SPURIOUS.  most m68k
 | 
			
		||||
  implementations just use autovectored interrupts.
 | 
			
		||||
 | 
			
		||||
- When the interrupting device is satisfied, you must call m68k_set_irq(0) to
 | 
			
		||||
  remove the interrupt request.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
MULTIPLE INTERRUPTS:
 | 
			
		||||
-------------------
 | 
			
		||||
The above system will work if you have only one device interrupting the CPU,
 | 
			
		||||
but if you have more than one device, you must do a bit more.
 | 
			
		||||
 | 
			
		||||
To add multiple interrupts:
 | 
			
		||||
 | 
			
		||||
- You must make an interrupt arbitration device that will take the highest
 | 
			
		||||
  priority interrupt and encode it onto the IRQ pins on the CPU.
 | 
			
		||||
 | 
			
		||||
- The interrupt arbitration device should use m68k_set_irq() to set the
 | 
			
		||||
  highest pending interrupt, or 0 for no interrupts pending.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
SEPARATE IMMEDIATE READS:
 | 
			
		||||
------------------------
 | 
			
		||||
You can write faster memory access functions if you know whether you are
 | 
			
		||||
fetching from ROM or RAM.  Immediate reads are always from the program space
 | 
			
		||||
(Always in ROM unless it is running self-modifying code).
 | 
			
		||||
 | 
			
		||||
To enable separate immediate reads:
 | 
			
		||||
 | 
			
		||||
- In m68kconf.h, turn on M68K_SEPARATE_READ_IMM.
 | 
			
		||||
 | 
			
		||||
- In your host program, implement the following functions:
 | 
			
		||||
    unsigned int  m68k_read_immediate_16(unsigned int address);
 | 
			
		||||
    unsigned int  m68k_read_immediate_32(unsigned int address);
 | 
			
		||||
 | 
			
		||||
- If you need to know the current PC (for banking and such), set
 | 
			
		||||
  M68K_MONITOR_PC to OPT_SPECIFY_HANDLER, and set M68K_SET_PC_CALLBACK(A) to
 | 
			
		||||
  your routine.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
ADDRESS SPACES:
 | 
			
		||||
--------------
 | 
			
		||||
Most systems will only implement one address space, placing ROM at the lower
 | 
			
		||||
addresses and RAM at the higher.  However, there is the possibility that a
 | 
			
		||||
system will implement ROM and RAM in the same address range, but in different
 | 
			
		||||
address spaces.
 | 
			
		||||
 | 
			
		||||
In this case, you might get away with assuming that immediate reads are in the
 | 
			
		||||
program space and all other reads are in the data space, if it weren't for the
 | 
			
		||||
fact that the exception vectors are fetched from the data space.  As a result,
 | 
			
		||||
anyone implementing this kind of system will have to copy the vector table
 | 
			
		||||
from ROM to RAM using pc-relative instructions.
 | 
			
		||||
 | 
			
		||||
This makes things bad for emulation, because this means that a non-immediate
 | 
			
		||||
read is not necessarily in the data space.
 | 
			
		||||
The m68k deals with this by encoding the requested address space on the
 | 
			
		||||
function code pins:
 | 
			
		||||
 | 
			
		||||
                       FC
 | 
			
		||||
    Address Space      210
 | 
			
		||||
    ------------------ ---
 | 
			
		||||
    USER DATA          001
 | 
			
		||||
    USER PROGRAM       010
 | 
			
		||||
    SUPERVISOR DATA    101
 | 
			
		||||
    SUPERVISOR PROGRAM 110
 | 
			
		||||
    CPU SPACE          111 <-- not emulated in this core since we emulate
 | 
			
		||||
                               interrupt acknowledge in another way.
 | 
			
		||||
 | 
			
		||||
To emulate the function code pins:
 | 
			
		||||
 | 
			
		||||
- In m68kconf.h, set M68K_EMULATE_FC to OPT_SPECIFY_HANDLER and set
 | 
			
		||||
  M68K_SET_FC_CALLBACK(A) to your function code handler function.
 | 
			
		||||
 | 
			
		||||
- Your function code handler should select the proper address space for
 | 
			
		||||
  subsequent calls to m68k_read_xx (and m68k_write_xx for 68010+).
 | 
			
		||||
 | 
			
		||||
Note: immediate reads are always done from program space, so technically you
 | 
			
		||||
      don't need to implement the separate immediate reads, although you could
 | 
			
		||||
      gain more speed improvements leaving them in and doing some clever
 | 
			
		||||
      programming.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
USING DIFFERENT CPU TYPES:
 | 
			
		||||
-------------------------
 | 
			
		||||
The default is to enable only the 68000 cpu type.  To change this, change the
 | 
			
		||||
settings for M68K_EMULATE_010 etc in m68kconf.h.
 | 
			
		||||
 | 
			
		||||
To set the CPU type you want to use:
 | 
			
		||||
 | 
			
		||||
- Make sure it is enabled in m68kconf.h.  Current switches are:
 | 
			
		||||
    M68K_EMULATE_010
 | 
			
		||||
    M68K_EMULATE_EC020
 | 
			
		||||
    M68K_EMULATE_020
 | 
			
		||||
 | 
			
		||||
- In your host program, call m68k_set_cpu_type() and then call
 | 
			
		||||
  m68k_pulse_reset().  Valid CPU types are:
 | 
			
		||||
    M68K_CPU_TYPE_68000,
 | 
			
		||||
    M68K_CPU_TYPE_68010,
 | 
			
		||||
    M68K_CPU_TYPE_68EC020,
 | 
			
		||||
    M68K_CPU_TYPE_68020
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
CLOCK FREQUENCY:
 | 
			
		||||
---------------
 | 
			
		||||
In order to emulate the correct clock frequency, you will have to calculate
 | 
			
		||||
how long it takes the emulation to execute a certain number of "cycles" and
 | 
			
		||||
vary your calls to m68k_execute() accordingly.
 | 
			
		||||
As well, it is a good idea to take away the CPU's timeslice when it writes to
 | 
			
		||||
a memory-mapped port in order to give the device it wrote to a chance to
 | 
			
		||||
react.
 | 
			
		||||
 | 
			
		||||
You can use the functions m68k_cycles_run(), m68k_cycles_remaining(),
 | 
			
		||||
m68k_modify_timeslice(), and m68k_end_timeslice() to do this.
 | 
			
		||||
Try to use large cycle values in your calls to m68k_execute() since it will
 | 
			
		||||
increase throughput.  You can always take away the timeslice later.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
MORE CORRECT EMULATION:
 | 
			
		||||
----------------------
 | 
			
		||||
You may need to enable these in order to properly emulate some of the more
 | 
			
		||||
obscure functions of the m68k:
 | 
			
		||||
 | 
			
		||||
- M68K_EMULATE_BKPT_ACK causes the CPU to call a breakpoint handler on a BKPT
 | 
			
		||||
  instruction
 | 
			
		||||
 | 
			
		||||
- M68K_EMULATE_TRACE causes the CPU to generate trace exceptions when the
 | 
			
		||||
  trace bits are set
 | 
			
		||||
 | 
			
		||||
- M68K_EMULATE_RESET causes the CPU to call a reset handler on a RESET
 | 
			
		||||
  instruction.
 | 
			
		||||
 | 
			
		||||
- M68K_EMULATE_PREFETCH emulates the 4-word instruction prefetch that is part
 | 
			
		||||
  of the 68000/68010 (needed for Amiga emulation).
 | 
			
		||||
  NOTE: if the CPU fetches a word or longword at an odd address when this
 | 
			
		||||
  option is on, it will yield unpredictable results, which is why a real
 | 
			
		||||
  68000 will generate an address error exception.
 | 
			
		||||
 | 
			
		||||
- M68K_EMULATE_ADDRESS_ERROR will cause the CPU to generate address error
 | 
			
		||||
  exceptions if it attempts to read a word or longword at an odd address.
 | 
			
		||||
 | 
			
		||||
- call m68k_pulse_halt() to emulate the HALT pin.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
CONVENIENCE FUNCTIONS:
 | 
			
		||||
---------------------
 | 
			
		||||
These are in here for programmer convenience:
 | 
			
		||||
 | 
			
		||||
- M68K_INSTRUCTION_HOOK lets you call a handler before each instruction.
 | 
			
		||||
 | 
			
		||||
- M68K_LOG_ENABLE and M68K_LOG_1010_1111 lets you log illegal and A/F-line
 | 
			
		||||
  instructions.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
MULTIPLE CPU EMULATION:
 | 
			
		||||
----------------------
 | 
			
		||||
The default is to use only one CPU.  To use more than one CPU in this core,
 | 
			
		||||
there are some things to keep in mind:
 | 
			
		||||
 | 
			
		||||
- To have different cpus call different functions, use OPT_ON instead of
 | 
			
		||||
  OPT_SPECIFY_HANDLER, and use the m68k_set_xxx_callback() functions to set
 | 
			
		||||
  your callback handlers on a per-cpu basis.
 | 
			
		||||
 | 
			
		||||
- Be sure to call set_cpu_type() for each CPU you use.
 | 
			
		||||
 | 
			
		||||
- Use m68k_set_context() and m68k_get_context() to switch to another CPU.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
LOAD AND SAVE CPU CONTEXTS FROM DISK:
 | 
			
		||||
------------------------------------
 | 
			
		||||
You can use them68k_load_context() and m68k_save_context() functions to load
 | 
			
		||||
and save the CPU state to disk.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
GET/SET INFORMATION FROM THE CPU:
 | 
			
		||||
--------------------------------
 | 
			
		||||
You can use m68k_get_reg() and m68k_set_reg() to gain access to the internals
 | 
			
		||||
of the CPU.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
EXAMPLE:
 | 
			
		||||
-------
 | 
			
		||||
 | 
			
		||||
The subdir example contains a full example (currently DOS only).
 | 
			
		||||
							
								
								
									
										348
									
								
								plat/linux68k/emu/sim.c
									
										
									
									
									
										Executable file
									
								
							
							
						
						
									
										348
									
								
								plat/linux68k/emu/sim.c
									
										
									
									
									
										Executable file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,348 @@
 | 
			
		|||
#include <stdio.h>
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include <stdarg.h>
 | 
			
		||||
#include <stdint.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#include <time.h>
 | 
			
		||||
#include <unistd.h>
 | 
			
		||||
#include <errno.h>
 | 
			
		||||
#include "sim.h"
 | 
			
		||||
#include "m68k.h"
 | 
			
		||||
 | 
			
		||||
void disassemble_program();
 | 
			
		||||
 | 
			
		||||
#define ADDRESS_MASK 0xffffffff
 | 
			
		||||
#define RAM_BASE 0x08000000
 | 
			
		||||
#define RAM_TOP  0x08100000
 | 
			
		||||
 | 
			
		||||
#define BRK_TOP (RAM_TOP - 0x1000)
 | 
			
		||||
 | 
			
		||||
#define INIT_SP RAM_TOP
 | 
			
		||||
#define INIT_PC 0x08000054
 | 
			
		||||
 | 
			
		||||
/* Read/write macros */
 | 
			
		||||
#define READ_BYTE(BASE, ADDR) (BASE)[ADDR]
 | 
			
		||||
#define READ_WORD(BASE, ADDR) (((BASE)[ADDR]<<8) |			\
 | 
			
		||||
							  (BASE)[(ADDR)+1])
 | 
			
		||||
#define READ_LONG(BASE, ADDR) (((BASE)[ADDR]<<24) |			\
 | 
			
		||||
							  ((BASE)[(ADDR)+1]<<16) |		\
 | 
			
		||||
							  ((BASE)[(ADDR)+2]<<8) |		\
 | 
			
		||||
							  (BASE)[(ADDR)+3])
 | 
			
		||||
 | 
			
		||||
#define WRITE_BYTE(BASE, ADDR, VAL) (BASE)[ADDR] = (VAL)&0xff
 | 
			
		||||
#define WRITE_WORD(BASE, ADDR, VAL) (BASE)[ADDR] = ((VAL)>>8) & 0xff;		\
 | 
			
		||||
									(BASE)[(ADDR)+1] = (VAL)&0xff
 | 
			
		||||
#define WRITE_LONG(BASE, ADDR, VAL) (BASE)[ADDR] = ((VAL)>>24) & 0xff;		\
 | 
			
		||||
									(BASE)[(ADDR)+1] = ((VAL)>>16)&0xff;	\
 | 
			
		||||
									(BASE)[(ADDR)+2] = ((VAL)>>8)&0xff;		\
 | 
			
		||||
									(BASE)[(ADDR)+3] = (VAL)&0xff
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
static void exit_error(char* fmt, ...);
 | 
			
		||||
static void emulated_syscall(void);
 | 
			
		||||
 | 
			
		||||
uint32_t cpu_read_byte(uint32_t address);
 | 
			
		||||
uint32_t cpu_read_word(uint32_t address);
 | 
			
		||||
uint32_t cpu_read_long(uint32_t address);
 | 
			
		||||
void cpu_write_byte(uint32_t address, uint32_t value);
 | 
			
		||||
void cpu_write_word(uint32_t address, uint32_t value);
 | 
			
		||||
void cpu_write_long(uint32_t address, uint32_t value);
 | 
			
		||||
 | 
			
		||||
unsigned char g_ram[RAM_TOP - RAM_BASE];
 | 
			
		||||
uint32_t brkbase = RAM_BASE;
 | 
			
		||||
uint32_t brkpos = RAM_BASE;
 | 
			
		||||
uint32_t entrypoint = RAM_BASE;
 | 
			
		||||
 | 
			
		||||
/* Exit with an error message.  Use printf syntax. */
 | 
			
		||||
void exit_error(char* fmt, ...)
 | 
			
		||||
{
 | 
			
		||||
	static int guard_val = 0;
 | 
			
		||||
	char buff[100];
 | 
			
		||||
	uint32_t pc;
 | 
			
		||||
	va_list args;
 | 
			
		||||
 | 
			
		||||
	if(guard_val)
 | 
			
		||||
		return;
 | 
			
		||||
	else
 | 
			
		||||
		guard_val = 1;
 | 
			
		||||
 | 
			
		||||
	va_start(args, fmt);
 | 
			
		||||
	vfprintf(stderr, fmt, args);
 | 
			
		||||
	va_end(args);
 | 
			
		||||
	fprintf(stderr, "\n");
 | 
			
		||||
	pc = m68k_get_reg(NULL, M68K_REG_PPC);
 | 
			
		||||
	m68k_disassemble(buff, pc, M68K_CPU_TYPE_68020);
 | 
			
		||||
	fprintf(stderr, "At %04x: %s\n", pc, buff);
 | 
			
		||||
 | 
			
		||||
	exit(EXIT_FAILURE);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline uint32_t transform_address(uint32_t address)
 | 
			
		||||
{
 | 
			
		||||
	uint32_t i = (address & ADDRESS_MASK) - RAM_BASE;
 | 
			
		||||
	if (i >= (uint32_t)(RAM_TOP - RAM_BASE))
 | 
			
		||||
		exit_error("Attempted to read from RAM address %08x", address);
 | 
			
		||||
	return i;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
uint32_t cpu_read_long(uint32_t address)
 | 
			
		||||
{
 | 
			
		||||
	switch (address)
 | 
			
		||||
	{
 | 
			
		||||
		case 0x00: return INIT_SP;
 | 
			
		||||
		case 0x04: return entrypoint;
 | 
			
		||||
		case 0x80: emulated_syscall(); return 0x10000;
 | 
			
		||||
		case 0x10000: return 0x4e734e73; /* rte; rte */
 | 
			
		||||
		case 0x10004: return 0;
 | 
			
		||||
		default:
 | 
			
		||||
		{
 | 
			
		||||
			uint32_t value = READ_LONG(g_ram, transform_address(address));
 | 
			
		||||
			#if 0
 | 
			
		||||
			printf("read %08x from %08x\n", value, address);
 | 
			
		||||
			#endif
 | 
			
		||||
			return value;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
uint32_t cpu_read_word(uint32_t address)
 | 
			
		||||
{
 | 
			
		||||
	uint32_t l = cpu_read_long(address & ~3);
 | 
			
		||||
	l >>= 16 - (address & 2)*8;
 | 
			
		||||
	return l & 0xffff;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
uint32_t cpu_read_byte(uint32_t address)
 | 
			
		||||
{
 | 
			
		||||
	uint32_t l = cpu_read_long(address & ~3);
 | 
			
		||||
	l >>= 24 - (address & 3)*8;
 | 
			
		||||
	return l & 0xff;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
uint32_t cpu_read_word_dasm(uint32_t address)
 | 
			
		||||
{
 | 
			
		||||
	return cpu_read_word(address);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
uint32_t cpu_read_long_dasm(uint32_t address)
 | 
			
		||||
{
 | 
			
		||||
	return cpu_read_long(address);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* Write data to RAM or a device */
 | 
			
		||||
void cpu_write_byte(uint32_t address, uint32_t value)
 | 
			
		||||
{
 | 
			
		||||
	WRITE_BYTE(g_ram, transform_address(address), value);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void cpu_write_word(uint32_t address, uint32_t value)
 | 
			
		||||
{
 | 
			
		||||
	WRITE_WORD(g_ram, transform_address(address), value);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void cpu_write_long(uint32_t address, uint32_t value)
 | 
			
		||||
{
 | 
			
		||||
	WRITE_LONG(g_ram, transform_address(address), value);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Disassembler */
 | 
			
		||||
void make_hex(char* buff, uint32_t pc, uint32_t length)
 | 
			
		||||
{
 | 
			
		||||
	char* ptr = buff;
 | 
			
		||||
 | 
			
		||||
	for(;length>0;length -= 2)
 | 
			
		||||
	{
 | 
			
		||||
		sprintf(ptr, "%04x", cpu_read_word_dasm(pc));
 | 
			
		||||
		pc += 2;
 | 
			
		||||
		ptr += 4;
 | 
			
		||||
		if(length > 2)
 | 
			
		||||
			*ptr++ = ' ';
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void disassemble_program()
 | 
			
		||||
{
 | 
			
		||||
	uint32_t pc;
 | 
			
		||||
	uint32_t instr_size;
 | 
			
		||||
	char buff[100];
 | 
			
		||||
	char buff2[100];
 | 
			
		||||
 | 
			
		||||
	pc = cpu_read_long_dasm(4);
 | 
			
		||||
 | 
			
		||||
	while(pc <= 0x16e)
 | 
			
		||||
	{
 | 
			
		||||
		instr_size = m68k_disassemble(buff, pc, M68K_CPU_TYPE_68000);
 | 
			
		||||
		make_hex(buff2, pc, instr_size);
 | 
			
		||||
		printf("%03x: %-20s: %s\n", pc, buff2, buff);
 | 
			
		||||
		pc += instr_size;
 | 
			
		||||
	}
 | 
			
		||||
	fflush(stdout);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void cpu_instr_callback()
 | 
			
		||||
{
 | 
			
		||||
	uint32_t pc = m68k_get_reg(NULL, M68K_REG_PC);
 | 
			
		||||
	if (pc == 0xc)
 | 
			
		||||
		exit_error("address exception");
 | 
			
		||||
 | 
			
		||||
	/* The following code would print out instructions as they are executed */
 | 
			
		||||
 | 
			
		||||
#if 0
 | 
			
		||||
	static char buff[100];
 | 
			
		||||
	static char buff2[100];
 | 
			
		||||
	static uint32_t instr_size;
 | 
			
		||||
 | 
			
		||||
	instr_size = m68k_disassemble(buff, pc, M68K_CPU_TYPE_68020);
 | 
			
		||||
	make_hex(buff2, pc, instr_size);
 | 
			
		||||
	printf("E %03x: %-20s: %s\n", pc, buff2, buff);
 | 
			
		||||
	printf("  d0: %08x d1: %08x d2: %08x d3: %08x d4: %08x d5: %08x d6: %08x d7: %08x\n",
 | 
			
		||||
		m68k_get_reg(NULL, M68K_REG_D0),
 | 
			
		||||
		m68k_get_reg(NULL, M68K_REG_D1),
 | 
			
		||||
		m68k_get_reg(NULL, M68K_REG_D2),
 | 
			
		||||
		m68k_get_reg(NULL, M68K_REG_D3),
 | 
			
		||||
		m68k_get_reg(NULL, M68K_REG_D4),
 | 
			
		||||
		m68k_get_reg(NULL, M68K_REG_D5),
 | 
			
		||||
		m68k_get_reg(NULL, M68K_REG_D6),
 | 
			
		||||
		m68k_get_reg(NULL, M68K_REG_D7));
 | 
			
		||||
	printf("  a0: %08x a1: %08x a2: %08x a3: %08x a4: %08x a5: %08x a6: %08x a7: %08x\n",
 | 
			
		||||
		m68k_get_reg(NULL, M68K_REG_A0),
 | 
			
		||||
		m68k_get_reg(NULL, M68K_REG_A1),
 | 
			
		||||
		m68k_get_reg(NULL, M68K_REG_A2),
 | 
			
		||||
		m68k_get_reg(NULL, M68K_REG_A3),
 | 
			
		||||
		m68k_get_reg(NULL, M68K_REG_A4),
 | 
			
		||||
		m68k_get_reg(NULL, M68K_REG_A5),
 | 
			
		||||
		m68k_get_reg(NULL, M68K_REG_A6),
 | 
			
		||||
		m68k_get_reg(NULL, M68K_REG_A7));
 | 
			
		||||
	fflush(stdout);
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void emulated_syscall(void)
 | 
			
		||||
{
 | 
			
		||||
	int s = m68k_get_reg(NULL, M68K_REG_D0);
 | 
			
		||||
	switch (s)
 | 
			
		||||
	{
 | 
			
		||||
		case 1: /* exit */
 | 
			
		||||
			exit(m68k_get_reg(NULL, M68K_REG_D1));
 | 
			
		||||
			
 | 
			
		||||
		case 4: /* write */
 | 
			
		||||
		{
 | 
			
		||||
			uint32_t fd = m68k_get_reg(NULL, M68K_REG_D1);
 | 
			
		||||
			uint32_t ptr = m68k_get_reg(NULL, M68K_REG_D2);
 | 
			
		||||
			uint32_t len = m68k_get_reg(NULL, M68K_REG_D3);
 | 
			
		||||
			m68k_set_reg(M68K_REG_D0, write(fd, g_ram + transform_address(ptr), len));
 | 
			
		||||
			break;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		case 45: /* brk */
 | 
			
		||||
		{
 | 
			
		||||
			uint32_t newpos = m68k_get_reg(NULL, M68K_REG_D1);
 | 
			
		||||
			if (newpos == 0)
 | 
			
		||||
				m68k_set_reg(M68K_REG_D0, brkpos);
 | 
			
		||||
			else if ((newpos < brkbase) || (newpos >= BRK_TOP))
 | 
			
		||||
				m68k_set_reg(M68K_REG_D0, -ENOMEM);
 | 
			
		||||
			else
 | 
			
		||||
			{
 | 
			
		||||
				brkpos = newpos;
 | 
			
		||||
				m68k_set_reg(M68K_REG_D0, 0);
 | 
			
		||||
			}
 | 
			
		||||
			break;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		case 20: /* getpid */
 | 
			
		||||
		case 48: /* signal */
 | 
			
		||||
		case 54: /* ioctl */
 | 
			
		||||
		case 78: /* gettimeofday */
 | 
			
		||||
			m68k_set_reg(M68K_REG_D0, 0);
 | 
			
		||||
			break;
 | 
			
		||||
 | 
			
		||||
		default:
 | 
			
		||||
			exit_error("unknown system call %d", s);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void load_program(FILE* fd)
 | 
			
		||||
{
 | 
			
		||||
	fseek(fd, 0, SEEK_SET);
 | 
			
		||||
	if (fread(g_ram, 1, 0x34, fd) != 0x34)
 | 
			
		||||
		exit_error("couldn't read ELF header");
 | 
			
		||||
	
 | 
			
		||||
	uint32_t phoff = READ_LONG(g_ram, 0x1c);
 | 
			
		||||
	uint16_t phentsize = READ_WORD(g_ram, 0x2a);
 | 
			
		||||
	uint16_t phnum = READ_WORD(g_ram, 0x2c);
 | 
			
		||||
	entrypoint = READ_LONG(g_ram, 0x18);
 | 
			
		||||
	if ((phentsize != 0x20) || (phnum != 1))
 | 
			
		||||
		exit_error("unsupported ELF file");
 | 
			
		||||
 | 
			
		||||
	fseek(fd, phoff, SEEK_SET);
 | 
			
		||||
	if (fread(g_ram, 1, phentsize, fd) != phentsize)
 | 
			
		||||
		exit_error("couldn't read program header");
 | 
			
		||||
 | 
			
		||||
	uint32_t offset = READ_LONG(g_ram, 0x04);
 | 
			
		||||
	uint32_t vaddr = READ_LONG(g_ram, 0x08);
 | 
			
		||||
	uint32_t filesz = READ_LONG(g_ram, 0x10);
 | 
			
		||||
	uint32_t memsz = READ_LONG(g_ram, 0x14);
 | 
			
		||||
	brkbase = brkpos = vaddr + memsz;
 | 
			
		||||
 | 
			
		||||
	uint32_t vaddroffset = transform_address(vaddr);
 | 
			
		||||
	transform_address(vaddr + memsz); /* bounds check */
 | 
			
		||||
	memset(g_ram+vaddroffset, 0, memsz);
 | 
			
		||||
	fseek(fd, offset, SEEK_SET);
 | 
			
		||||
	if (fread(g_ram+vaddroffset, 1, filesz, fd) != filesz)
 | 
			
		||||
		exit_error("couldn't read program data");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* The main loop */
 | 
			
		||||
int main(int argc, char* argv[])
 | 
			
		||||
{
 | 
			
		||||
	FILE* fhandle;
 | 
			
		||||
 | 
			
		||||
	if(argc != 2)
 | 
			
		||||
	{
 | 
			
		||||
		printf("Usage: sim <program file>\n");
 | 
			
		||||
		exit(-1);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if((fhandle = fopen(argv[1], "rb")) == NULL)
 | 
			
		||||
		exit_error("Unable to open %s", argv[1]);
 | 
			
		||||
 | 
			
		||||
	load_program(fhandle);
 | 
			
		||||
 | 
			
		||||
//	disassemble_program();
 | 
			
		||||
 | 
			
		||||
	m68k_set_cpu_type(M68K_CPU_TYPE_68020);
 | 
			
		||||
	m68k_init();
 | 
			
		||||
	m68k_pulse_reset();
 | 
			
		||||
 | 
			
		||||
	/* On entry, the Linux stack looks like this.
 | 
			
		||||
	 * 
 | 
			
		||||
	 * sp+..           NULL
 | 
			
		||||
     * sp+8+(4*argc)   env (X quads)
 | 
			
		||||
     * sp+4+(4*argc)   NULL
 | 
			
		||||
     * sp+4            argv (argc quads)
 | 
			
		||||
     * sp              argc
 | 
			
		||||
	 *
 | 
			
		||||
	 * We'll set it up with a bodgy stack frame with argc=0 just to keep the
 | 
			
		||||
	 * startup code happy.
 | 
			
		||||
	 */
 | 
			
		||||
 | 
			
		||||
	{
 | 
			
		||||
		uint32_t sp = INIT_SP;
 | 
			
		||||
		cpu_write_long(sp -= 4, 0);
 | 
			
		||||
		uint32_t envp = sp;
 | 
			
		||||
		cpu_write_long(sp -= 4, envp);
 | 
			
		||||
		cpu_write_long(sp -= 4, 0);
 | 
			
		||||
		unsigned long argv = sp;
 | 
			
		||||
		cpu_write_long(sp -= 4, argv);
 | 
			
		||||
		cpu_write_long(sp -= 4, 0);
 | 
			
		||||
		m68k_set_reg(M68K_REG_SP, sp);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for (;;)
 | 
			
		||||
		m68k_execute(100000);
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										15
									
								
								plat/linux68k/emu/sim.h
									
										
									
									
									
										Executable file
									
								
							
							
						
						
									
										15
									
								
								plat/linux68k/emu/sim.h
									
										
									
									
									
										Executable file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,15 @@
 | 
			
		|||
#ifndef SIM__HEADER
 | 
			
		||||
#define SIM__HEADER
 | 
			
		||||
 | 
			
		||||
unsigned int cpu_read_byte(unsigned int address);
 | 
			
		||||
unsigned int cpu_read_word(unsigned int address);
 | 
			
		||||
unsigned int cpu_read_long(unsigned int address);
 | 
			
		||||
void cpu_write_byte(unsigned int address, unsigned int value);
 | 
			
		||||
void cpu_write_word(unsigned int address, unsigned int value);
 | 
			
		||||
void cpu_write_long(unsigned int address, unsigned int value);
 | 
			
		||||
void cpu_pulse_reset(void);
 | 
			
		||||
void cpu_set_fc(unsigned int fc);
 | 
			
		||||
int  cpu_irq_ack(int level);
 | 
			
		||||
void cpu_instr_callback();
 | 
			
		||||
 | 
			
		||||
#endif /* SIM__HEADER */
 | 
			
		||||
							
								
								
									
										7
									
								
								plat/linux68k/tests/build.lua
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								plat/linux68k/tests/build.lua
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,7 @@
 | 
			
		|||
include("tests/plat/build.lua")
 | 
			
		||||
 | 
			
		||||
plat_testsuite {
 | 
			
		||||
    name = "tests",
 | 
			
		||||
    plat = "linux68k",
 | 
			
		||||
    method = "plat/linux68k/emu+emu68k"
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -51,16 +51,23 @@ definerule("plat_testsuite",
 | 
			
		|||
				}
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			local methoddep = nil
 | 
			
		||||
			local methodpath = e.method
 | 
			
		||||
			if e.method:find("%+") then
 | 
			
		||||
				methoddep = e.method
 | 
			
		||||
				methodpath = "%{ins[4]}"
 | 
			
		||||
			end
 | 
			
		||||
			tests[#tests+1] = normalrule {
 | 
			
		||||
				name = fs,
 | 
			
		||||
				outleaves = { e.plat.."-"..fs.."-testlog.txt" },
 | 
			
		||||
				ins = {
 | 
			
		||||
					bin,
 | 
			
		||||
					"tests/plat/testdriver.sh",
 | 
			
		||||
					"util/build+testrunner"
 | 
			
		||||
					"util/build+testrunner",
 | 
			
		||||
					methoddep,
 | 
			
		||||
				},
 | 
			
		||||
				commands = {
 | 
			
		||||
					"%{ins[2]} "..e.method.." %{ins[1]} 15 %{ins[3]} > %{outs}; true",
 | 
			
		||||
					"%{ins[2]} "..methodpath.." %{ins[1]} 15 %{ins[3]} > %{outs}; true",
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		end
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -4,6 +4,8 @@ img=$2
 | 
			
		|||
timeout=$3
 | 
			
		||||
timeoutprog=$4
 | 
			
		||||
 | 
			
		||||
set -e
 | 
			
		||||
 | 
			
		||||
errcho() {
 | 
			
		||||
    >&2 echo "$*"
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -36,8 +38,7 @@ get_test_output() {
 | 
			
		|||
            ;;
 | 
			
		||||
 | 
			
		||||
        *)
 | 
			
		||||
            errcho "Error: $method not known by testdriver"
 | 
			
		||||
            exit 1
 | 
			
		||||
			$timeoutprog -t $timeout -- $method $img 2>&1
 | 
			
		||||
            ;;
 | 
			
		||||
    esac
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		
		Reference in a new issue