summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorOxore <oxore@protonmail.com>2023-06-10 13:26:58 +0300
committerOxore <oxore@protonmail.com>2023-06-10 14:50:12 +0300
commitfccfe0e0b4848fa38403b515d77b6aba37570e54 (patch)
treef520df03c9d913ff9edfbd1ea626d9f93e92d625
parenta8beae02428f4c7762c3621b4a6d23a498b7d394 (diff)
Impl IO class with tracing, add VDP addr regs tracing
-rw-r--r--CMakeLists.txt2
-rw-r--r--bus.cpp15
-rw-r--r--emulator.cpp7
-rw-r--r--graphics.cpp12
-rw-r--r--io.cpp102
-rw-r--r--io.hpp41
-rw-r--r--vdp.cpp58
-rw-r--r--vdp.hpp2
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
)
diff --git a/bus.cpp b/bus.cpp
index 32a5b5c..f9aab5f 100644
--- a/bus.cpp
+++ b/bus.cpp
@@ -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);
diff --git a/io.cpp b/io.cpp
new file mode 100644
index 0000000..e46feab
--- /dev/null
+++ b/io.cpp
@@ -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;
+ }
+}
diff --git a/io.hpp b/io.hpp
new file mode 100644
index 0000000..de2478a
--- /dev/null
+++ b/io.hpp
@@ -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{};
+};
diff --git a/vdp.cpp b/vdp.cpp
index df3a7cc..6acb7ea 100644
--- a/vdp.cpp
+++ b/vdp.cpp
@@ -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;
}
diff --git a/vdp.hpp b/vdp.hpp
index ab8c337..1b86784 100644
--- a/vdp.hpp
+++ b/vdp.hpp
@@ -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