From 903b8dbcaad887f6e14cc8cffc22ddda08dc9f85 Mon Sep 17 00:00:00 2001 From: Oxore Date: Sat, 27 Aug 2022 11:53:25 +0300 Subject: Move to C++ completely --- CMakeLists.txt | 4 +- bus.c | 209 --------------------------------------------------------- bus.cpp | 208 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ bus.h | 18 ----- bus.hpp | 18 +++++ emulator.c | 102 ---------------------------- emulator.cpp | 102 ++++++++++++++++++++++++++++ m68kconf.h | 8 +++ 8 files changed, 338 insertions(+), 331 deletions(-) delete mode 100644 bus.c create mode 100644 bus.cpp delete mode 100644 bus.h create mode 100644 bus.hpp delete mode 100644 emulator.c create mode 100644 emulator.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index c94615b..d6456c7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -16,8 +16,8 @@ set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -fsanitize=address -fno-omit set(CMAKE_LINKER_FLAGS_DEBUG "${CMAKE_LINKER_FLAGS_DEBUG} -fsanitize=address -fno-omit-frame-pointer") set(emulator_sources - bus.c - emulator.c + bus.cpp + emulator.cpp ) set(musashi_m68k_sources musashi-m68k/m68kcpu.c diff --git a/bus.c b/bus.c deleted file mode 100644 index 64a8ac9..0000000 --- a/bus.c +++ /dev/null @@ -1,209 +0,0 @@ -/* SPDX-License-Identifier: Unlicense - */ - -#include "bus.h" - -#include -#include -#include -#include -#include -#include - -#include "musashi-m68k/m68k.h" - -unsigned char g_rom[ROM_SIZE] = {0}; -unsigned char g_ram[RAM_SIZE] = {0}; -unsigned char g_io1[IO1_SIZE] = {0}; -unsigned char g_io2[IO2_SIZE] = {0}; - -static void exit_error(char* fmt, ...) -{ - va_list args; - va_start(args, fmt); - vfprintf(stderr, fmt, args); - va_end(args); - fprintf(stderr, "\n"); - unsigned int pc = m68k_get_reg(NULL, M68K_REG_PPC); - char buff[100]; - 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; -} - -enum bitness { - BITNESS_8, - BITNESS_16, - BITNESS_32, -}; - -struct read_result { - unsigned int result; - bool successful; -}; - -static inline unsigned int memory_read_concrete( - enum bitness bitness, - unsigned char const * base, - unsigned int address) -{ - switch (bitness) { - case BITNESS_8: - return base[address]; - case BITNESS_16: - return (base[address] << 8) | base[address + 1]; - case BITNESS_32: - return (base[address] << 24) | - (base[address + 1] << 16) | - (base[address + 2] << 8) | - base[address + 3]; - } - __builtin_unreachable(); -} - -static inline struct read_result memory_read( - enum bitness bitness, - unsigned int address) -{ - if (is_in_range(address, ROM_START, ROM_SIZE)) - return (struct read_result){ - memory_read_concrete(bitness, g_rom, address - ROM_START), - true, - }; - else if (is_in_range(address, RAM_START, RAM_SIZE)) - return (struct read_result){ - memory_read_concrete(bitness, g_ram, address - RAM_START), - true, - }; - else if (is_in_range(address, IO1_START, IO1_SIZE)) - return (struct read_result){ - memory_read_concrete(bitness, g_io1, address - IO1_START), - true, - }; - else if (is_in_range(address, IO2_START, IO2_SIZE)) - return (struct read_result){ - memory_read_concrete(bitness, g_io2, address - IO2_START), - true, - }; - return (struct read_result){0, false}; -} - -static inline void memory_write_concrete( - enum bitness bitness, - unsigned char * base, - unsigned int address, - unsigned int value) -{ - switch (bitness) { - case BITNESS_8: - base[address] = value & 0xff; - break; - case BITNESS_16: - base[address + 0] = (value >> 8) & 0xff; - base[address + 1] = value & 0xff; - break; - case BITNESS_32: - base[address + 0] = (value >> 24) & 0xff; - base[address + 1] = (value >> 16) & 0xff; - base[address + 2] = (value >> 8) & 0xff; - base[address + 3] = value & 0xff; - break; - } -} - -static inline bool memory_write( - enum bitness bitness, - unsigned int address, - unsigned int value) -{ - if (is_in_range(address, ROM_START, ROM_SIZE)) { - memory_write_concrete(bitness, g_rom, address - ROM_START, value); - return true; - } else if (is_in_range(address, RAM_START, RAM_SIZE)) { - memory_write_concrete(bitness, g_ram, address - RAM_START, value); - return true; - } else if (is_in_range(address, IO1_START, IO1_SIZE)) { - memory_write_concrete(bitness, g_io1, address - IO1_START, value); - return true; - } else if (is_in_range(address, IO2_START, IO2_SIZE)) { - memory_write_concrete(bitness, g_io2, address - IO2_START, value); - return true; - } - return false; -} - -#define MASK_24(X) ((X) & (0xFF << 24)) - -unsigned int m68k_read_memory_8(unsigned int address) -{ - assert(MASK_24(address) == 0); // Just curious - const struct read_result ret = memory_read(BITNESS_8, address); - if (!ret.successful) - exit_error("Read error u8 @%08x", address); - return ret.result; -} - -unsigned int m68k_read_memory_16(unsigned int address) -{ - assert(MASK_24(address) == 0); // Just curious - const struct read_result ret = memory_read(BITNESS_16, address); - if (!ret.successful) - exit_error("Read error u16 @%08x", address); - return ret.result; -} - -unsigned int m68k_read_memory_32(unsigned int address) -{ - assert(MASK_24(address) == 0); // Just curious - const struct read_result ret = memory_read(BITNESS_32, address); - if (!ret.successful) - exit_error("Read error u32 @%08x", address); - return ret.result; -} - -unsigned int m68k_read_disassembler_16(unsigned int address) -{ - assert(MASK_24(address) == 0); // Just curious - const struct read_result ret = memory_read(BITNESS_16, address); - if (!ret.successful) - exit_error("Disasm read error u16 @0x%08x", address); - return ret.result; -} - -unsigned int m68k_read_disassembler_32(unsigned int address) -{ - assert(MASK_24(address) == 0); // Just curious - const struct read_result ret = memory_read(BITNESS_32, address); - if (!ret.successful) - exit_error("Disasm read error u32 @0x%08x", address); - return ret.result; -} - -void m68k_write_memory_8(unsigned int address, unsigned int value) -{ - assert(MASK_24(address) == 0); // Just curious - const bool successful = memory_write(BITNESS_8, address, value); - if (!successful) - 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 - const bool successful = memory_write(BITNESS_16, address, value); - if (!successful) - 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 - const bool successful = memory_write(BITNESS_16, address, value); - if (!successful) - exit_error("Attempted to write %08x (u32) to address %08x", value, address); -} diff --git a/bus.cpp b/bus.cpp new file mode 100644 index 0000000..caff07c --- /dev/null +++ b/bus.cpp @@ -0,0 +1,208 @@ +/* SPDX-License-Identifier: Unlicense + */ + +#include "bus.hpp" +#include "musashi-m68k/m68k.h" + +#include +#include +#include +#include +#include +#include + +unsigned char g_rom[ROM_SIZE] = {}; +unsigned char g_ram[RAM_SIZE] = {}; +unsigned char g_io1[IO1_SIZE] = {}; +unsigned char g_io2[IO2_SIZE] = {}; + +static void exit_error(const char* fmt, ...) +{ + va_list args; + va_start(args, fmt); + vfprintf(stderr, fmt, args); + va_end(args); + fprintf(stderr, "\n"); + unsigned int pc = m68k_get_reg(NULL, M68K_REG_PPC); + char buff[100]; + 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; +} + +enum bitness { + BITNESS_8, + BITNESS_16, + BITNESS_32, +}; + +struct read_result { + unsigned int result; + bool successful; +}; + +static inline unsigned int memory_read_concrete( + enum bitness bitness, + unsigned char const * base, + unsigned int address) +{ + switch (bitness) { + case BITNESS_8: + return base[address]; + case BITNESS_16: + return (base[address] << 8) | base[address + 1]; + case BITNESS_32: + return (base[address] << 24) | + (base[address + 1] << 16) | + (base[address + 2] << 8) | + base[address + 3]; + } + __builtin_unreachable(); +} + +static inline struct read_result memory_read( + enum bitness bitness, + unsigned int address) +{ + if (is_in_range(address, ROM_START, ROM_SIZE)) + return (struct read_result){ + memory_read_concrete(bitness, g_rom, address - ROM_START), + true, + }; + else if (is_in_range(address, RAM_START, RAM_SIZE)) + return (struct read_result){ + memory_read_concrete(bitness, g_ram, address - RAM_START), + true, + }; + else if (is_in_range(address, IO1_START, IO1_SIZE)) + return (struct read_result){ + memory_read_concrete(bitness, g_io1, address - IO1_START), + true, + }; + else if (is_in_range(address, IO2_START, IO2_SIZE)) + return (struct read_result){ + memory_read_concrete(bitness, g_io2, address - IO2_START), + true, + }; + return (struct read_result){0, false}; +} + +static inline void memory_write_concrete( + enum bitness bitness, + unsigned char * base, + unsigned int address, + unsigned int value) +{ + switch (bitness) { + case BITNESS_8: + base[address] = value & 0xff; + break; + case BITNESS_16: + base[address + 0] = (value >> 8) & 0xff; + base[address + 1] = value & 0xff; + break; + case BITNESS_32: + base[address + 0] = (value >> 24) & 0xff; + base[address + 1] = (value >> 16) & 0xff; + base[address + 2] = (value >> 8) & 0xff; + base[address + 3] = value & 0xff; + break; + } +} + +static inline bool memory_write( + enum bitness bitness, + unsigned int address, + unsigned int value) +{ + if (is_in_range(address, ROM_START, ROM_SIZE)) { + memory_write_concrete(bitness, g_rom, address - ROM_START, value); + return true; + } else if (is_in_range(address, RAM_START, RAM_SIZE)) { + memory_write_concrete(bitness, g_ram, address - RAM_START, value); + return true; + } else if (is_in_range(address, IO1_START, IO1_SIZE)) { + memory_write_concrete(bitness, g_io1, address - IO1_START, value); + return true; + } else if (is_in_range(address, IO2_START, IO2_SIZE)) { + memory_write_concrete(bitness, g_io2, address - IO2_START, value); + return true; + } + return false; +} + +#define MASK_24(X) ((X) & (0xFF << 24)) + +unsigned int m68k_read_memory_8(unsigned int address) +{ + assert(MASK_24(address) == 0); // Just curious + const struct read_result ret = memory_read(BITNESS_8, address); + if (!ret.successful) + exit_error("Read error u8 @%08x", address); + return ret.result; +} + +unsigned int m68k_read_memory_16(unsigned int address) +{ + assert(MASK_24(address) == 0); // Just curious + const struct read_result ret = memory_read(BITNESS_16, address); + if (!ret.successful) + exit_error("Read error u16 @%08x", address); + return ret.result; +} + +unsigned int m68k_read_memory_32(unsigned int address) +{ + assert(MASK_24(address) == 0); // Just curious + const struct read_result ret = memory_read(BITNESS_32, address); + if (!ret.successful) + exit_error("Read error u32 @%08x", address); + return ret.result; +} + +unsigned int m68k_read_disassembler_16(unsigned int address) +{ + assert(MASK_24(address) == 0); // Just curious + const struct read_result ret = memory_read(BITNESS_16, address); + if (!ret.successful) + exit_error("Disasm read error u16 @0x%08x", address); + return ret.result; +} + +unsigned int m68k_read_disassembler_32(unsigned int address) +{ + assert(MASK_24(address) == 0); // Just curious + const struct read_result ret = memory_read(BITNESS_32, address); + if (!ret.successful) + exit_error("Disasm read error u32 @0x%08x", address); + return ret.result; +} + +void m68k_write_memory_8(unsigned int address, unsigned int value) +{ + assert(MASK_24(address) == 0); // Just curious + const bool successful = memory_write(BITNESS_8, address, value); + if (!successful) + 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 + const bool successful = memory_write(BITNESS_16, address, value); + if (!successful) + 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 + const bool successful = memory_write(BITNESS_16, address, value); + if (!successful) + exit_error("Attempted to write %08x (u32) to address %08x", value, address); +} diff --git a/bus.h b/bus.h deleted file mode 100644 index baa65be..0000000 --- a/bus.h +++ /dev/null @@ -1,18 +0,0 @@ -/* SPDX-License-Identifier: Unlicense - */ - -#pragma once - -#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) - -extern unsigned char g_rom[ROM_SIZE]; -extern unsigned char g_ram[RAM_SIZE]; -extern unsigned char g_io1[IO1_SIZE]; -extern unsigned char g_io2[IO2_SIZE]; diff --git a/bus.hpp b/bus.hpp new file mode 100644 index 0000000..baa65be --- /dev/null +++ b/bus.hpp @@ -0,0 +1,18 @@ +/* SPDX-License-Identifier: Unlicense + */ + +#pragma once + +#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) + +extern unsigned char g_rom[ROM_SIZE]; +extern unsigned char g_ram[RAM_SIZE]; +extern unsigned char g_io1[IO1_SIZE]; +extern unsigned char g_io2[IO2_SIZE]; diff --git a/emulator.c b/emulator.c deleted file mode 100644 index 21b9c94..0000000 --- a/emulator.c +++ /dev/null @@ -1,102 +0,0 @@ -/* SPDX-License-Identifier: Unlicense - */ - -#include "bus.h" - -#include -#include -#include -#include -#include "musashi-m68k/m68k.h" - -#if !defined(DEBUG_TRACE_INSTRUCTIONS) -# define DEBUG_TRACE_INSTRUCTIONS 0 -#endif - -static void exit_error(char* fmt, ...) -{ - va_list args; - va_start(args, fmt); - vfprintf(stderr, fmt, args); - va_end(args); - fprintf(stderr, "\n"); - exit(EXIT_FAILURE); -} - -/* Called when the CPU pulses the RESET line */ -void m68k_reset_callback(void) -{ - // TODO -} - -/* 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 (!DEBUG_TRACE_INSTRUCTIONS) - return; - char buff[100]; - unsigned int instr_size = - m68k_disassemble(buff, pc, M68K_CPU_TYPE_68000); - char buff2[100]; - 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; -} diff --git a/emulator.cpp b/emulator.cpp new file mode 100644 index 0000000..0e3fb29 --- /dev/null +++ b/emulator.cpp @@ -0,0 +1,102 @@ +/* SPDX-License-Identifier: Unlicense + */ + +#include "bus.hpp" +#include "musashi-m68k/m68k.h" + +#include +#include +#include +#include + +#if !defined(DEBUG_TRACE_INSTRUCTIONS) +# define DEBUG_TRACE_INSTRUCTIONS 0 +#endif + +static void exit_error(const char* fmt, ...) +{ + va_list args; + va_start(args, fmt); + vfprintf(stderr, fmt, args); + va_end(args); + fprintf(stderr, "\n"); + exit(EXIT_FAILURE); +} + +/* Called when the CPU pulses the RESET line */ +void m68k_reset_callback(void) +{ + // TODO +} + +/* 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 (!DEBUG_TRACE_INSTRUCTIONS) + return; + char buff[100]; + unsigned int instr_size = + m68k_disassemble(buff, pc, M68K_CPU_TYPE_68000); + char buff2[100]; + 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; +} diff --git a/m68kconf.h b/m68kconf.h index 09e3e95..0b67f76 100644 --- a/m68kconf.h +++ b/m68kconf.h @@ -30,6 +30,10 @@ #ifndef M68KCONF__HEADER #define M68KCONF__HEADER +#ifdef __cplusplus +extern "C" { +#endif + /* Configuration switches. * Use OPT_SPECIFY_HANDLER for configuration options that allow callbacks. * OPT_SPECIFY_HANDLER causes the core to link directly to the function @@ -209,6 +213,10 @@ void m68k_instr_callback(int pc); #endif /* M68K_COMPILE_FOR_MAME */ +#ifdef __cplusplus +} +#endif + /* ======================================================================== */ /* ============================== END OF FILE ============================= */ /* ======================================================================== */ -- cgit v1.2.3