From bfec175173f4e1a350729588526c4ff0be9ac949 Mon Sep 17 00:00:00 2001 From: Oxore Date: Thu, 11 Aug 2022 23:16:38 +0300 Subject: Initial commit --- emulator.c | 237 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 237 insertions(+) create mode 100644 emulator.c (limited to 'emulator.c') diff --git a/emulator.c b/emulator.c new file mode 100644 index 0000000..7eb30a8 --- /dev/null +++ b/emulator.c @@ -0,0 +1,237 @@ +#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; +} -- cgit v1.2.3