diff --git a/plat/linux68k/emu/m68kconf.h b/plat/linux68k/emu/m68kconf.h index 05cc6ade4..c5c9b1aef 100755 --- a/plat/linux68k/emu/m68kconf.h +++ b/plat/linux68k/emu/m68kconf.h @@ -1,192 +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_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 */ +/* ======================================================================== */ +/* ========================= 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 */ diff --git a/plat/linux68k/emu/sim.c b/plat/linux68k/emu/sim.c index 97ea5fd24..d15ca1ed9 100755 --- a/plat/linux68k/emu/sim.c +++ b/plat/linux68k/emu/sim.c @@ -1,561 +1,253 @@ -#include -#include -#include -#include -#include "sim.h" -#include "m68k.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< 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< 0;g_int_controller_highest_int--) - if(g_int_controller_pending & (1<= 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 \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; -} - +#include +#include +#include +#include +#include "sim.h" +#include "m68k.h" + +void disassemble_program(); + +#define ADDRESS_MASK 0xffffffff +#define RAM_BASE 0x08000000 +#define RAM_TOP 0x08100000 + +#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 syscall(void); + +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); + +unsigned char g_ram[RAM_TOP - RAM_BASE]; + + +/* 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); +} + +static inline unsigned int transform_address(unsigned int address) +{ + unsigned int i = (address & ADDRESS_MASK) - RAM_BASE; + if (i >= (unsigned int)(RAM_TOP - RAM_BASE)) + exit_error("Attempted to read from RAM address %08x %08x", address, i); + return i; +} + +unsigned int cpu_read_long(unsigned int address) +{ + switch (address) + { + case 0x00: return INIT_SP; + case 0x04: return INIT_PC; + case 0x80: syscall(); return 0x10000; + case 0x10000: return 0x4e73; /* rte */ + case 0x10004: return 0; + default: return READ_LONG(g_ram, transform_address(address)); + } +} + + +unsigned int cpu_read_word(unsigned int address) +{ + unsigned int l = cpu_read_long(address & ~3); + l >>= (address & 2) * 8; + return l & 0xffff; +} + +unsigned int cpu_read_byte(unsigned int address) +{ + unsigned int l = cpu_read_long(address & ~3); + l >>= (address & 3) * 8; + return l & 0xff; +} + +unsigned int cpu_read_word_dasm(unsigned int address) +{ + return cpu_read_word(address); +} + +unsigned int cpu_read_long_dasm(unsigned int address) +{ + return cpu_read_long(address); +} + + +/* Write data to RAM or a device */ +void cpu_write_byte(unsigned int address, unsigned int value) +{ + WRITE_BYTE(g_ram, transform_address(address), value); +} + +void cpu_write_word(unsigned int address, unsigned int value) +{ + WRITE_WORD(g_ram, transform_address(address), value); +} + +void cpu_write_long(unsigned int address, unsigned int value) +{ + WRITE_LONG(g_ram, transform_address(address), value); +} + +/* 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 */ + +#if 1 + 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_68020); + make_hex(buff2, pc, instr_size); + printf("E %03x: %-20s: %s\n", pc, buff2, buff); + fflush(stdout); +#endif +} + +static void syscall(void) +{ + int s = m68k_get_reg(NULL, M68K_REG_D0); + switch (s) + { + case 45: /* brk */ + m68k_set_reg(M68K_REG_D0, RAM_TOP-0x1000); + break; + + default: + exit_error("unknown system call %d", s); + } +} + +/* The main loop */ +int main(int argc, char* argv[]) +{ + FILE* fhandle; + + if(argc != 2) + { + printf("Usage: sim \n"); + exit(-1); + } + + if((fhandle = fopen(argv[1], "rb")) == NULL) + exit_error("Unable to open %s", argv[1]); + + if(fread(g_ram, 1, RAM_TOP - RAM_BASE, fhandle) <= 0) + exit_error("Error reading %s", argv[1]); + +// disassemble_program(); + + m68k_init(); + m68k_set_cpu_type(M68K_CPU_TYPE_68020); + 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. + */ + + { + unsigned int sp = INIT_SP; + cpu_write_long(sp -= 4, 0); + unsigned int 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; +} + diff --git a/plat/linux68k/tests/build.lua b/plat/linux68k/tests/build.lua new file mode 100644 index 000000000..a025310a9 --- /dev/null +++ b/plat/linux68k/tests/build.lua @@ -0,0 +1,7 @@ +include("tests/plat/build.lua") + +plat_testsuite { + name = "tests", + plat = "linux68k", + method = "plat/linux68k/emu+emu68k" +}