diff options
author | Oxore <oxore@protonmail.com> | 2023-06-10 13:26:58 +0300 |
---|---|---|
committer | Oxore <oxore@protonmail.com> | 2023-06-10 14:50:12 +0300 |
commit | fccfe0e0b4848fa38403b515d77b6aba37570e54 (patch) | |
tree | f520df03c9d913ff9edfbd1ea626d9f93e92d625 | |
parent | a8beae02428f4c7762c3621b4a6d23a498b7d394 (diff) |
Impl IO class with tracing, add VDP addr regs tracing
-rw-r--r-- | CMakeLists.txt | 2 | ||||
-rw-r--r-- | bus.cpp | 15 | ||||
-rw-r--r-- | emulator.cpp | 7 | ||||
-rw-r--r-- | graphics.cpp | 12 | ||||
-rw-r--r-- | io.cpp | 102 | ||||
-rw-r--r-- | io.hpp | 41 | ||||
-rw-r--r-- | vdp.cpp | 58 | ||||
-rw-r--r-- | vdp.hpp | 2 |
8 files changed, 206 insertions, 33 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index ec342a7..5f89536 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -16,6 +16,7 @@ set(emulator_sources graphics.cpp m68k_debugging.cpp vdp.cpp + io.cpp ) set(musashi_m68k_sources musashi-m68k/m68kcpu.c @@ -78,6 +79,7 @@ target_compile_definitions(emulator PRIVATE DEBUG_TRACE_INSTRUCTIONS=0 DEBUG_TRACE_GDB_REMOTE=0 DEBUG_TRACE_VDP_ACCESS=1 + DEBUG_TRACE_IO_ACCESS=1 HAS_GRAPHICS=1 ) @@ -5,6 +5,7 @@ #include "musashi-m68k/m68k.h" #include "utils.hpp" #include "vdp.hpp" +#include "io.hpp" #include <algorithm> #include <cassert> @@ -21,6 +22,7 @@ namespace Adr { static constexpr uint32_t kZ80BusReq = 0x00a11100; +static constexpr uint32_t kZ80Reset = 0x00a11200; } extern void m68k_breakpoint_callback(void); @@ -28,7 +30,7 @@ extern void m68k_breakpoint_callback(void); extern unsigned char g_rom[ROM_SIZE]; extern unsigned char g_ram[RAM_SIZE]; extern unsigned char g_sound_ram[SOUND_RAM_SIZE]; -extern unsigned char g_io1[IO1_SIZE]; +extern IO g_io1; extern unsigned char g_io2[VDP_SIZE]; extern unsigned char g_psg[PSG_SIZE]; extern VDP g_vdp; @@ -153,7 +155,7 @@ static inline ReadResult memory_read( }; } else if (is_in_range(address, IO1_START, IO1_SIZE)) { return ReadResult{ - memory_read_concrete(bitness, g_io1, address - IO1_START), + g_io1.Read(address - g_io1.base_address, bitness), true, }; } else if (is_in_range(address, VDP_START, VDP_SIZE)) { @@ -228,14 +230,7 @@ static inline bool memory_write( memory_write_concrete(bitness, g_sound_ram, address - SOUND_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); - if (address == Adr::kZ80BusReq || address == Adr::kZ80BusReq + 1) { - if (g_io1[Adr::kZ80BusReq - IO1_START] == 1 && g_io1[Adr::kZ80BusReq - IO1_START + 1] == 0) { - // Acknowledge S80 BUSREQ - g_io1[Adr::kZ80BusReq - IO1_START + 0] = 0; - g_io1[Adr::kZ80BusReq - IO1_START + 1] = 0; - } - } + g_io1.Write(address - g_io1.base_address, bitness, value); return true; } else if (is_in_range(address, VDP_START, VDP_SIZE)) { if (address == PSG_START) { diff --git a/emulator.cpp b/emulator.cpp index 262f160..0dc63b9 100644 --- a/emulator.cpp +++ b/emulator.cpp @@ -4,6 +4,7 @@ #include "bus.hpp" #include "graphics.hpp" #include "vdp.hpp" +#include "io.hpp" #include "m68k_debugging.hpp" #include "gdbremote_parser.hpp" #include "utils.hpp" @@ -38,7 +39,7 @@ unsigned char g_rom[ROM_SIZE] = {}; unsigned char g_ram[RAM_SIZE] = {}; unsigned char g_sound_ram[SOUND_RAM_SIZE] = {}; -unsigned char g_io1[IO1_SIZE] = {}; +IO g_io1(IO1_START); unsigned char g_psg[PSG_SIZE] = {}; VDP g_vdp(VDP_START); std::vector<Breakpoint> code_bkpts{}, read_bkpts{}, write_bkpts{}, access_bkpts{}; @@ -441,13 +442,13 @@ void ParseAndReact( static void RunSingleVideoCycle(M68KDebuggingControl& m68k_debug, Graphics& graphics) { do { - g_cycles_counter += m68k_execute(1000); + g_cycles_counter += m68k_execute(100000); if (m68k_debug.HasBreakpoint()) { return; } } while (!g_vdp.Scanline()); graphics.Render(g_vdp); - g_cycles_counter += m68k_execute(8000); + g_cycles_counter += m68k_execute(800000); } int emulator(M68KDebuggingControl& m68k_debug, Graphics& graphics) diff --git a/graphics.cpp b/graphics.cpp index 56d0532..d193b50 100644 --- a/graphics.cpp +++ b/graphics.cpp @@ -21,8 +21,8 @@ Graphics::Graphics() _window = SDL_CreateWindow("Gut (SEGA MD/G emulator)", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, - VDP().kRenderWidth * kIntegerScaling, - VDP().kRenderHeight * kIntegerScaling, + VDP(0).kRenderWidth * kIntegerScaling, + VDP(0).kRenderHeight * kIntegerScaling, SDL_WINDOW_RESIZABLE); if (!_window) { SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't create window: %s\n", SDL_GetError()); @@ -39,8 +39,8 @@ Graphics::Graphics() _renderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STREAMING, - VDP().kRenderWidth, - VDP().kRenderHeight); + VDP(0).kRenderWidth, + VDP(0).kRenderHeight); if (!_render_texture) { SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't create texture: %s\n", SDL_GetError()); SDL_Quit(); @@ -85,9 +85,9 @@ void Graphics::Render(const VDP& vdp) // TODO probably should return and propagate error abort(); } - assert(pitch == VDP().kRenderWidth * sizeof(*buffer)); + assert(pitch == VDP(0).kRenderWidth * sizeof(*buffer)); (void) pitch; - memcpy(pixels, buffer, VDP().kRenderWidth * VDP().kRenderHeight * sizeof(*buffer)); + memcpy(pixels, buffer, VDP(0).kRenderWidth * VDP(0).kRenderHeight * sizeof(*buffer)); SDL_UnlockTexture(_render_texture); SDL_RenderClear(_renderer); SDL_RenderCopy(_renderer, _render_texture, NULL, NULL); @@ -0,0 +1,102 @@ +/* SPDX-License-Identifier: Unlicense + */ + +#include "io.hpp" + +#include <cstdio> + +uint32_t IO::Read(const uint32_t offset, const enum bitness bitness) +{ + uint32_t ret{}; + if (bitness == BITNESS_32) { + ret = (read(offset + 3) << 24) | + (read(offset + 2) << 16) | + (read(offset + 1) << 8) | + read(offset + 0); + } else if (bitness == BITNESS_16) { + ret = (read(offset + 1) << 8) | read(offset + 0); + } else if (bitness == BITNESS_8) { + ret = read(offset); + } + if (DEBUG_TRACE_IO_ACCESS) { + printf( + "IO r%d%s @0x%08x 0x%0*x\n", + bitness * 8, + (bitness <= 1 ? " " : ""), + base_address + offset, + bitness * 2, + ret); + } + return ret; +} + +void IO::Write(const uint32_t offset, const enum bitness bitness, const uint32_t value) +{ + if (DEBUG_TRACE_IO_ACCESS) { + printf( + "IO w%d%s @0x%08x 0x%0*x\n", + bitness * 8, + (bitness <= 1 ? " " : ""), + base_address + offset, + bitness * 2, + value); + } + if (bitness == BITNESS_32) { + write(offset + 3, value & 0xff); + write(offset + 2, (value >> 8) & 0xff); + write(offset + 1, (value >> 16) & 0xff); + write(offset + 0, (value >> 24) & 0xff); + } else if (bitness == BITNESS_16) { + write(offset + 0, (value >> 8) & 0xff); + write(offset + 1, value & 0xff); + } else if (bitness == BITNESS_8) { + write(offset, value & 0xff); + } +} + +uint32_t IO::read(const uint32_t offset) +{ + switch (offset) { + case kData1Offset: return _data1; + case kData2Offset: return _data2; + case kData3Offset: return _data3; + case kControl1Offset: return _control1; + case kControl2Offset: return _control2; + case kControl3Offset: return _control3; + case kTx1Offset: return _tx1; + case kRx1Offset: return _rx1; + case kStatus1Offset: return _status1; + case kTx2Offset: return _tx2; + case kRx2Offset: return _rx2; + case kStatus2Offset: return _status2; + case kRx3Offset: return _tx3; + case kTx3Offset: return _rx3; + case kStatus3Offset: return _status3; + case kZ80BusReq: return !_z80_busreq; + case kZ80Reset: return 0; + } + return 0; +} + +void IO::write(const uint32_t offset, const uint8_t value) +{ + switch (offset) { + case kData1Offset: _data1 = value; break; + case kData2Offset: _data2 = value; break; + case kData3Offset: _data3 = value; break; + case kControl1Offset: _control1 = value; break; + case kControl2Offset: _control2 = value; break; + case kControl3Offset: _control3 = value; break; + case kTx1Offset: _tx1 = value; break; + case kRx1Offset: _rx1 = value; break; + case kStatus1Offset: _status1 = value; break; + case kTx2Offset: _tx2 = value; break; + case kRx2Offset: _rx2 = value; break; + case kStatus2Offset: _status2 = value; break; + case kRx3Offset: _tx3 = value; break; + case kTx3Offset: _rx3 = value; break; + case kStatus3Offset: _status3 = value; break; + case kZ80BusReq: _z80_busreq = value & 0x1; break; + case kZ80Reset: _z80_reset = value & 0x1; break; + } +} @@ -0,0 +1,41 @@ +/* SPDX-License-Identifier: Unlicense + */ + +#pragma once + +#include "bus.hpp" + +class IO { +public: + constexpr IO(const uint32_t base_address_a): base_address(base_address_a) {} + uint32_t Read(uint32_t offset, enum bitness); + void Write(uint32_t offset, enum bitness, uint32_t value); + const uint32_t base_address; + constexpr static uint32_t kData1Offset = 0x3; + constexpr static uint32_t kData2Offset = 0x5; + constexpr static uint32_t kData3Offset = 0x7; + constexpr static uint32_t kControl1Offset = 0x9; + constexpr static uint32_t kControl2Offset = 0xb; + constexpr static uint32_t kControl3Offset = 0xd; + constexpr static uint32_t kTx1Offset = 0xf; + constexpr static uint32_t kRx1Offset = 0x11; + constexpr static uint32_t kStatus1Offset = 0x13; + constexpr static uint32_t kTx2Offset = 0x15; + constexpr static uint32_t kRx2Offset = 0x17; + constexpr static uint32_t kStatus2Offset = 0x19; + constexpr static uint32_t kTx3Offset = 0x1b; + constexpr static uint32_t kRx3Offset = 0x1d; + constexpr static uint32_t kStatus3Offset = 0x1f; + constexpr static uint32_t kZ80BusReq = 0x1100; + constexpr static uint32_t kZ80Reset = 0x1200; +private: + uint32_t read(uint32_t offset); + void write(uint32_t offset, uint8_t value); + uint8_t _control1{}, _control2{}, _control3{}; + uint8_t _data1{}, _data2{}, _data3{}; + uint8_t _tx1{}, _rx1{}, _status1{}; + uint8_t _tx2{}, _rx2{}, _status2{}; + uint8_t _tx3{}, _rx3{}, _status3{}; + bool _z80_reset{}; + bool _z80_busreq{}; +}; @@ -131,7 +131,8 @@ static constexpr uint16_t kScrollSpeedMask = BitsCountToMask(10); // Each pixel has 4 bit depth color static constexpr uint16_t kPixelColorMask = BitsCountToMask(kBitsPerPixel); -static const char* reg_mode_set_1_bits[8] = { +static const char* reg_mode_set_1_bits_desc[16] = { + "", "", "", "", "", "", "", "", "Unused(7)", "Unused(6)", "Unused(5)", @@ -142,7 +143,8 @@ static const char* reg_mode_set_1_bits[8] = { "Unused(0)", }; -static const char* reg_mode_set_2_bits[8] = { +static const char* reg_mode_set_2_bits_desc[16] = { + "", "", "", "", "", "", "", "", "Unused(7)", "Display(6)", "VInt(5)", @@ -153,7 +155,8 @@ static const char* reg_mode_set_2_bits[8] = { "Unused(0)", }; -static const char* reg_mode_set_3_bits[8] = { +static const char* reg_mode_set_3_bits_desc[16] = { + "", "", "", "", "", "", "", "", "Unused(7)", "Unused(6)", "Unused(5)", @@ -164,7 +167,8 @@ static const char* reg_mode_set_3_bits[8] = { "HScrollLo(0)", }; -static const char* reg_mode_set_4_bits[8] = { +static const char* reg_mode_set_4_bits_desc[16] = { + "", "", "", "", "", "", "", "", "H40CellHi(7)", "Unused(6)", "Unused(5)", @@ -175,12 +179,26 @@ static const char* reg_mode_set_4_bits[8] = { "H40CellLo(0)", }; -static void TraceRegBits(FILE* s, const char* bits_desc[8], const uint8_t val) +static const char* reg_status_bits_desc[16] = { + "", "", "", "", "", "", + "FIFOEmpty(9)", + "FIFOFull(8)", + "VInt(7)", + "SpriteOverflow(6)", + "SpriteCollision(5)", + "OddFrame(4)", + "InVBlank(3)", + "InHBlank(2)", + "DMABusy(1)", + "PAL(0)", +}; + +static void TraceRegBits(FILE* s, const char* bits_desc[16], const uint16_t val) { - fprintf(s, "("); + fprintf(s, " ("); bool separator{}; - for (size_t i = 0; i < 8; i++) { - if (val & (1 << (7 - i))) { + for (size_t i = 0; i < 16; i++) { + if (val & (1 << (15 - i))) { if (separator) { fprintf(s, " | "); separator = false; @@ -198,26 +216,31 @@ static void TraceRegWrite(FILE* const s, const uint8_t reg, const uint8_t val) fprintf(s, ": reg 0x%02x(%s) = 0x%02x", reg, VDP::RegIDToString(reg_id), val); switch (reg_id) { case VDP::RegID::kModeSet1: - return TraceRegBits(s, reg_mode_set_1_bits, val); + return TraceRegBits(s, reg_mode_set_1_bits_desc, val); case VDP::RegID::kModeSet2: - return TraceRegBits(s, reg_mode_set_2_bits, val); + return TraceRegBits(s, reg_mode_set_2_bits_desc, val); case VDP::RegID::kScrollAAddress: + fprintf(s, " (0x%04x)", uint16_t(val & 0x38) << 10); break; case VDP::RegID::kWindowAddress: + fprintf(s, " (0x%04x)", uint16_t(val & 0x3e) << 10); break; case VDP::RegID::kScrollBAddress: + fprintf(s, " (0x%04x)", uint16_t(val & 0x7) << 13); break; case VDP::RegID::kSpritesTableAddress: + fprintf(s, " (0x%04x)", uint16_t(val & 0x7f) << 9); break; case VDP::RegID::kBackgroundColor: break; case VDP::RegID::kHint: break; case VDP::RegID::kModeSet3: - return TraceRegBits(s, reg_mode_set_3_bits, val); + return TraceRegBits(s, reg_mode_set_3_bits_desc, val); case VDP::RegID::kModeSet4: - return TraceRegBits(s, reg_mode_set_4_bits, val); + return TraceRegBits(s, reg_mode_set_4_bits_desc, val); case VDP::RegID::kHScrollTableAddress: + fprintf(s, " (0x%04x)", uint16_t(val & 0x3f) << 10); break; case VDP::RegID::kAutoIncrement: break; @@ -232,10 +255,18 @@ static void TraceRegWrite(FILE* const s, const uint8_t reg, const uint8_t val) case VDP::RegID::kDMALengthCounterHigh: break; case VDP::RegID::kDMASourceAddressLow: + fprintf(s, " (0xXXXX%02x)", val); break; case VDP::RegID::kDMASourceAddressMid: + fprintf(s, " (0xXX%02xXX)", val); break; case VDP::RegID::kDMASourceAddressHigh: + { + const char* op = (val & 0x80) + ? ((val & 0x40) ? "VRAM Copy" : "VRAM Fill") + : "MemToVRAM"; + fprintf(s, " (%s 0x%02xXXXX)", op, val & ((val & 0x80) ? 0x3f : 0x7f)); + } break; case VDP::RegID::kRegistersCount: break; @@ -837,7 +868,8 @@ uint16_t VDP::readStatusRegister() const | (_status.pal_mode << 0) ; if (DEBUG_TRACE_VDP_ACCESS) { - printf(": Status %04x", value); + fprintf(stdout, ": Status %04x", value); + TraceRegBits(stdout, reg_status_bits_desc, value); } return value; } @@ -47,7 +47,7 @@ public: kRegistersCount, ///< Keep it last }; - constexpr VDP(const uint32_t base_address_a = VDP_START): base_address(base_address_a) {} + constexpr VDP(const uint32_t base_address_a): base_address(base_address_a) {} uint32_t Read(uint32_t offset, enum bitness); void Write(uint32_t offset, enum bitness, uint32_t value); bool Scanline(); // Returns true if display disabled or vblank happened |