#include #include #include #include #include #include #include #include "musashi-m68k/m68k.h" #define ROM_START (0) #define ROM_SIZE (0x400000) #define RAM_START (0xFF0000) #define RAM_SIZE (0x10000) #define IO1_START (0xA10000) #define IO1_SIZE (0x4004) #define IO2_START (0xC00000) #define IO2_SIZE (0x20) /* Read/write macros */ #define READ_8(BASE, ADDR) ((BASE)[ADDR]) #define READ_16(BASE, ADDR) (((BASE)[ADDR]<<8) | (BASE)[(ADDR)+1]) #define READ_32(BASE, ADDR) (((BASE)[ADDR]<<24) | \ ((BASE)[(ADDR)+1]<<16) | \ ((BASE)[(ADDR)+2]<<8) | \ (BASE)[(ADDR)+3]) #define WRITE_8(BASE, ADDR, VAL) ((BASE)[ADDR] = (VAL)&0xff) #define WRITE_16(BASE, ADDR, VAL) (((BASE)[ADDR] = ((VAL)>>8) & 0xff), \ ((BASE)[(ADDR)+1] = (VAL)&0xff)) #define WRITE_32(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)) /* Data */ unsigned char g_rom[ROM_SIZE]; unsigned char g_ram[RAM_SIZE]; unsigned char g_io1[IO1_SIZE]; unsigned char g_io2[IO2_SIZE]; /* Exit with an error message. Use printf syntax. */ static 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, "%08x: %s\n", pc, buff); exit(EXIT_FAILURE); } static inline bool is_in_range(uint32_t value, uint32_t begin, uint32_t length) { return value >= begin && value <= begin + length; } #define MEMORY_READ(BITNESS, ADDR) \ do { \ if (is_in_range(ADDR, ROM_START, ROM_SIZE)) \ return READ_##BITNESS(g_rom, ADDR - ROM_START); \ else if (is_in_range(ADDR, RAM_START, RAM_SIZE)) \ return READ_##BITNESS(g_ram, ADDR - RAM_START); \ else if (is_in_range(ADDR, IO1_START, IO1_SIZE)) \ return READ_##BITNESS(g_io1, ADDR - IO1_START); \ else if (is_in_range(ADDR, IO2_START, IO2_SIZE)) \ return READ_##BITNESS(g_io2, ADDR - IO2_START); \ } while (0) #define MEMORY_WRITE(BITNESS, ADDR, VAL) \ do { \ if (is_in_range(ADDR, ROM_START, ROM_SIZE)) { \ WRITE_##BITNESS(g_rom, ADDR - ROM_START, VAL); return; \ } else if (is_in_range(ADDR, RAM_START, RAM_SIZE)) { \ WRITE_##BITNESS(g_ram, ADDR - RAM_START, VAL); return; \ } else if (is_in_range(ADDR, IO1_START, IO1_SIZE)) { \ WRITE_##BITNESS(g_io1, ADDR - IO1_START, VAL); return; \ } else if (is_in_range(ADDR, IO2_START, IO2_SIZE)) { \ WRITE_##BITNESS(g_io2, ADDR - IO2_START, VAL); return; \ } \ } while (0) #define MASK_24(X) ((X) & (0xFF << 24)) unsigned int m68k_read_memory_8(unsigned int address) { assert(MASK_24(address) == 0); // Just curious MEMORY_READ(8, address); exit_error("Attempted to read u8 from address %08x", address); return 0; } unsigned int m68k_read_memory_16(unsigned int address) { assert(MASK_24(address) == 0); // Just curious MEMORY_READ(16, address); exit_error("Attempted to read u16 from address %08x", address); return 0; } unsigned int m68k_read_memory_32(unsigned int address) { assert(MASK_24(address) == 0); // Just curious MEMORY_READ(32, address); exit_error("Attempted to read u32 from address %08x", address); return 0; } unsigned int m68k_read_disassembler_16(unsigned int address) { assert(MASK_24(address) == 0); // Just curious MEMORY_READ(16, address); exit_error("Disassembler attempted to read u16 from address %08x", address); return 0; } unsigned int m68k_read_disassembler_32(unsigned int address) { assert(MASK_24(address) == 0); // Just curious MEMORY_READ(32, address); exit_error("Disassembler attempted to read u32 from address %08x", address); return 0; } /* Write data to RAM or a device */ void m68k_write_memory_8(unsigned int address, unsigned int value) { assert(MASK_24(address) == 0); // Just curious MEMORY_WRITE(8, address, value); exit_error("Attempted to write %02x (u8) to address %08x", value&0xff, address); } void m68k_write_memory_16(unsigned int address, unsigned int value) { assert(MASK_24(address) == 0); // Just curious MEMORY_WRITE(16, address, value); exit_error("Attempted to write %04x (u16) to address %08x", value&0xffff, address); } void m68k_write_memory_32(unsigned int address, unsigned int value) { assert(MASK_24(address) == 0); // Just curious MEMORY_WRITE(16, address, value); exit_error("Attempted to write %08x (u32) to address %08x", value, address); } /* Called when the CPU pulses the RESET line */ void m68k_reset_callback(void) { } /* Called when the CPU acknowledges an interrupt */ int m68k_irq_ack(int level) { (void) level; // TODO exit_error("IRQ ack"); return M68K_INT_ACK_SPURIOUS; } static void make_hex(char* buff, unsigned int pc, unsigned int length) { char* ptr = buff; for (;length>0;length -= 2) { sprintf(ptr, "%04x", m68k_read_disassembler_16(pc)); pc += 2; ptr += 4; if (length > 2) *ptr++ = ' '; } } void m68k_instr_callback(int pc) { if (0) return; static char buff[100]; static char buff2[100]; 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 %08X: %-20s: %s\n", pc, buff2, buff); fflush(stdout); } int main(int argc, char* argv[]) { if (argc != 2) { printf("Usage: sim \n"); exit(-1); } FILE* const fhandle = fopen(argv[1], "rb"); if (fhandle == NULL) exit_error("Unable to open %s", argv[1]); const size_t fread_ret = fread(g_rom, 1, ROM_SIZE, fhandle); if (fread_ret <= 0) exit_error("Error reading %s", argv[1]); printf("Read into ROM %zu bytes\n", fread_ret); m68k_init(); m68k_set_cpu_type(M68K_CPU_TYPE_68000); m68k_pulse_reset(); while (1) { // 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); } return 0; }