summaryrefslogtreecommitdiff
path: root/vdp.cpp
diff options
context:
space:
mode:
authorOxore <oxore@protonmail.com>2022-10-01 19:34:58 +0300
committerOxore <oxore@protonmail.com>2022-10-01 23:09:44 +0300
commit72abe5f3e714df9cc8310a78bdfa648feb79c4d2 (patch)
tree0333ee5e61f02548c7ce9dc7038698d15369acc9 /vdp.cpp
parentf125cc7018ed32b7f919ff71ea3c7d9d2e6565de (diff)
Add more VDP tracing, add VRAM, CRAM, VSRAM and status
Diffstat (limited to 'vdp.cpp')
-rw-r--r--vdp.cpp344
1 files changed, 331 insertions, 13 deletions
diff --git a/vdp.cpp b/vdp.cpp
index 632429d..d870fce 100644
--- a/vdp.cpp
+++ b/vdp.cpp
@@ -3,24 +3,36 @@
#include "vdp.hpp"
+#include <cstring>
+#include <cstdio>
+
uint32_t VDP::Read(const uint32_t offset, const enum bitness bitness)
{
- const uint32_t res{};
if (DEBUG_TRACE_VDP_ACCESS) {
printf(
- "VDP r%d%s @0x%08x 0x%0*x\n",
+ "VDP r%d%s @0x%08x\n",
bitness * 8,
(bitness <= 1 ? " " : ""),
- base_address + offset,
- bitness * 2,
- res);
+ base_address + offset);
}
if (bitness == BITNESS_32) {
- // TODO
+ if (offset == 0) {
+ const auto ret = readData(_address_mode, _address & 0xfffe);
+ _address += _reg[static_cast<size_t>(RegID::kAutoIncrement)];
+ return ret;
+ } else if (offset == 4) {
+ return readStatusRegister() | (readStatusRegister() << 16);
+ }
} else if (bitness == BITNESS_16) {
- // TODO
+ if (offset == 0 || offset == 2) {
+ const auto ret = readData(_address_mode, _address & 0xfffe);
+ _address += _reg[static_cast<size_t>(RegID::kAutoIncrement)];
+ return ret;
+ } else if (offset == 4 || offset == 6) {
+ return readStatusRegister();
+ }
}
- // Ignore 8-bit reads for now
+ // XXX: Ignore 8-bit reads for now
return 0;
}
@@ -36,29 +48,335 @@ void VDP::Write(const uint32_t offset, const enum bitness bitness, const uint32_
value);
}
if (bitness == BITNESS_32) {
- if (offset == 4 || offset == 6) {
+ if (offset == 0) {
+ writeData(_address_mode, _address & 0xfffe, (value >> 16) & 0xffff);
+ _address += _reg[static_cast<size_t>(RegID::kAutoIncrement)];
+ writeData(_address_mode, _address & 0xfffe, value & 0xffff);
+ _address += _reg[static_cast<size_t>(RegID::kAutoIncrement)];
+ } else if (offset == 4) {
writeControl((value >> 16) & 0xffff);
writeControl(value & 0xffff);
}
} else if (bitness == BITNESS_16) {
- if (offset == 4 || offset == 6) {
+ if (offset == 0 || offset == 2) {
+ writeData(_address_mode, _address & 0xfffe, value & 0xffff);
+ _address += _reg[static_cast<size_t>(RegID::kAutoIncrement)];
+ } else if (offset == 4 || offset == 6) {
writeControl(value & 0xffff);
}
}
+ // XXX: Ignore 8-bit writes for now
if (DEBUG_TRACE_VDP_ACCESS) {
printf("\n");
}
- // Ignore 8-bit writes for now
+}
+
+void VDP::Reset()
+{
+ _status = {};
+ _control_write_second_word = {};
+ _address_mode = {};
+ _address = {};
+ memset(_reg, 0, kRegistersCount);
+ memset(_vram, 0, kVRAMSize);
+ memset(_cram, 0, kCRAMSize);
+ memset(_vsram, 0, kVSRAMSize);
+}
+
+static inline bool IsWriteToReg(const uint16_t value)
+{
+ return ((value >> 13) & 0x7) == 4;
+}
+
+void VDP::writeData(const uint8_t address_mode, const uint16_t address, const uint16_t value)
+{
+ switch (static_cast<AddressMode>(address_mode & 0xf)) {
+ case AddressMode::kVRAMWrite:
+ if (address >= kVRAMSize) {
+ if (DEBUG_TRACE_VDP_ACCESS) {
+ printf(": VRAM @0x%04x: invalid address, ignoring", address);
+ }
+ return;
+ }
+ if (DEBUG_TRACE_VDP_ACCESS) {
+ printf(": VRAM @0x%04x 0x%04x", address, value);
+ }
+ _vram[address] = value;
+ return;
+ case AddressMode::kCRAMWrite:
+ if (address >= kCRAMSize) {
+ if (DEBUG_TRACE_VDP_ACCESS) {
+ printf(": CRAM @0x%04x: invalid address, ignoring", address);
+ }
+ return;
+ }
+ if (DEBUG_TRACE_VDP_ACCESS) {
+ printf(": CRAM @0x%04x 0x%04x", address, value);
+ }
+ _cram[address] = value;
+ return;
+ case AddressMode::kVSRAMWrite:
+ if (address >= kVSRAMSize) {
+ if (DEBUG_TRACE_VDP_ACCESS) {
+ printf(": VSRAM @0x%04x: invalid address, ignoring", address);
+ }
+ return;
+ }
+ if (DEBUG_TRACE_VDP_ACCESS) {
+ printf(": VSRAM @0x%04x 0x%04x", address, value);
+ }
+ _vsram[address] = value;
+ return;
+ case AddressMode::kVRAMRead:
+ case AddressMode::kCRAMRead:
+ case AddressMode::kVSRAMRead:
+ break;
+ }
+ if (DEBUG_TRACE_VDP_ACCESS) {
+ printf(
+ ": 0x%02x(%s): invalid address_mode",
+ address_mode,
+ addressModeToString(address_mode));
+ }
}
void VDP::writeControl(const uint16_t value)
{
- if (((value >> 13) & 0x7) == 4) {
+ if (_control_write_second_word) {
+ // Write second word
+ // 0 0 0 0 0 0 0 0
+ // CD5 CD4 CD3 CD2 0 0 A15 A14
+ _address |= (value & 0x3) << 14;
+ _address_mode |= ((value >> 4) & 0xf) << 2;
+ _control_write_second_word = false;
+ if (DEBUG_TRACE_VDP_ACCESS) {
+ printf(
+ ": New address_mode=0x%02x(%s), address=0x%04x",
+ _address_mode,
+ addressModeToString(_address_mode),
+ _address);
+ }
+ } else if (IsWriteToReg(value)) {
+ // Write register
+ // 1 0 0 RS4 RS3 RS2 RS1 RS0
+ // D7 D6 D5 D4 D3 D2 D1 D0
const uint8_t reg_num = (value >> 8) & 0x1f;
const uint8_t reg_val = value & 0xff;
if (DEBUG_TRACE_VDP_ACCESS) {
- printf(": reg 0x%02x w 0x%02x", reg_num, reg_val);
+ printf(
+ ": reg 0x%02x(%s) = 0x%02x",
+ reg_num,
+ regIDToString(static_cast<RegID>(reg_num)),
+ reg_val);
}
_reg[reg_num] = reg_val;
+ } else if (!_control_write_second_word) {
+ // Write first word
+ // CD1 CD0 A13 A12 A11 A10 A9 A8
+ // A7 A6 A5 A4 A3 A2 A1 A0
+ _address = value & 0x3f;
+ _address_mode = (value >> 14) & 0x3;
+ _control_write_second_word = true;
+ }
+}
+
+uint16_t VDP::readData(const uint8_t address_mode, const uint16_t address)
+{
+ switch (static_cast<AddressMode>(address_mode & 0xf)) {
+ case AddressMode::kVRAMWrite:
+ case AddressMode::kCRAMWrite:
+ case AddressMode::kVSRAMWrite:
+ break;
+ case AddressMode::kVRAMRead:
+ if (address >= kVRAMSize) {
+ if (DEBUG_TRACE_VDP_ACCESS) {
+ printf(": VRAM @0x%04x: invalid address, ignoring", address);
+ }
+ return 0;
+ } else {
+ const auto value = _vram[address];
+ if (DEBUG_TRACE_VDP_ACCESS) {
+ printf(": VRAM @0x%04x 0x%04x", address, value);
+ }
+ return value;
+ }
+ case AddressMode::kCRAMRead:
+ if (address >= kCRAMSize) {
+ if (DEBUG_TRACE_VDP_ACCESS) {
+ printf(": CRAM @0x%04x: invalid address, ignoring", address);
+ }
+ return 0;
+ } else {
+ const auto value = _cram[address];
+ if (DEBUG_TRACE_VDP_ACCESS) {
+ printf(": CRAM @0x%04x 0x%04x", address, value);
+ }
+ return value;
+ }
+ case AddressMode::kVSRAMRead:
+ if (address >= kVSRAMSize) {
+ if (DEBUG_TRACE_VDP_ACCESS) {
+ printf(": VSRAM @0x%04x: invalid address, ignoring", address);
+ }
+ return 0;
+ } else {
+ const auto value = _vsram[address];
+ if (DEBUG_TRACE_VDP_ACCESS) {
+ printf(": VSRAM @0x%04x 0x%04x", address, value);
+ }
+ return value;
+ }
+ }
+ if (DEBUG_TRACE_VDP_ACCESS) {
+ printf(
+ ": 0x%02x(%s): invalid address_mode",
+ address_mode,
+ addressModeToString(address_mode));
+ }
+ return 0;
+}
+
+uint16_t VDP::readStatusRegister() const
+{
+ return 0
+ | (!_status.fifo_not_empty << 9)
+ | (_status.fifo_full << 8)
+ | (_status.v_irq << 7)
+ | (_status.sprites_overflow << 6)
+ | (_status.sprites_collision << 5)
+ | (_status.odd_frame << 4)
+ | (_status.vblank << 3)
+ | (_status.hblank << 2)
+ | (_status.dma_busy << 1)
+ | (_status.pal_mode << 0)
+ ;
+}
+
+const char* VDP::addressModeToString(const uint8_t address_mode)
+{
+ const uint8_t dma_address_mode = (address_mode >> 5) & 0x3;
+ switch (static_cast<AddressMode>(address_mode & 0xf)) {
+ case AddressMode::kVRAMWrite:
+ switch (dma_address_mode) {
+ case 0:
+ return "VRAM write";
+ case 1:
+ return "DMA Memory to VRAM, VRAM write";
+ case 2:
+ return "DMA VRAM fill, VRAM write";
+ case 3:
+ return "DMA VRAM copy, VRAM write";
+ }
+ break;
+ case AddressMode::kCRAMWrite:
+ switch (dma_address_mode) {
+ case 0:
+ return "CRAM write";
+ case 1:
+ return "DMA Memory to VRAM, CRAM write";
+ case 2:
+ return "DMA VRAM fill, CRAM write";
+ case 3:
+ return "DMA VRAM copy, CRAM write";
+ }
+ break;
+ case AddressMode::kVSRAMWrite:
+ switch (dma_address_mode) {
+ case 0:
+ return "VSRAM write";
+ case 1:
+ return "DMA Memory to VRAM, VSRAM write";
+ case 2:
+ return "DMA VRAM fill, VSRAM write";
+ case 3:
+ return "DMA VRAM copy, VSRAM write";
+ }
+ break;
+ case AddressMode::kVRAMRead:
+ switch (dma_address_mode) {
+ case 0:
+ return "VRAM read";
+ case 1:
+ return "DMA Memory to VRAM, VRAM read";
+ case 2:
+ return "DMA VRAM fill, VRAM read";
+ case 3:
+ return "DMA VRAM copy, VRAM read";
+ }
+ break;
+ case AddressMode::kCRAMRead:
+ switch (dma_address_mode) {
+ case 0:
+ return "CRAM read";
+ case 1:
+ return "DMA Memory to VRAM, CRAM read";
+ case 2:
+ return "DMA VRAM fill, CRAM read";
+ case 3:
+ return "DMA VRAM copy, CRAM read";
+ }
+ break;
+ case AddressMode::kVSRAMRead:
+ switch (dma_address_mode) {
+ case 0:
+ return "VSRAM read";
+ case 1:
+ return "DMA Memory to VRAM, VSRAM read";
+ case 2:
+ return "DMA VRAM fill, VSRAM read";
+ case 3:
+ return "DMA VRAM copy, VSRAM read";
+ }
+ break;
+ }
+ return "Unknown";
+}
+
+const char* VDP::regIDToString(const RegID reg_id)
+{
+ switch (reg_id) {
+ case RegID::kModeSet1:
+ return "ModeSet1";
+ case RegID::kModeSet2:
+ return "ModeSet2";
+ case RegID::kScrollAAddress:
+ return "ScrollAAddress";
+ case RegID::kWindowAddress:
+ return "WindowAddress";
+ case RegID::kScrollBAddress:
+ return "ScrollBAddress";
+ case RegID::kSpritesTableAddress:
+ return "SpritesTableAddress";
+ case RegID::kBackgroundColor:
+ return "BackgroundColor";
+ case RegID::kHint:
+ return "Hint";
+ case RegID::kModeSet3:
+ return "ModeSet3";
+ case RegID::kModeSet4:
+ return "ModeSet4";
+ case RegID::kHScrollTableAddress:
+ return "HScrollTableAddress";
+ case RegID::kAutoIncrement:
+ return "AutoIncrement";
+ case RegID::kScrollSize:
+ return "ScrollSize";
+ case RegID::kWindowHorizontalPosition:
+ return "WindowHorizontalPosition";
+ case RegID::kWindowVertialPosition:
+ return "WindowVertialPosition";
+ case RegID::kDMACounterLow:
+ return "DMACounterLow";
+ case RegID::kDMACounterHigh:
+ return "DMACounterHigh";
+ case RegID::kDMASourceAddressLow:
+ return "DMASourceAddressLow";
+ case RegID::kDMASourceAddressMid:
+ return "DMASourceAddressMid";
+ case RegID::kDMASourceAddressHigh:
+ return "DMASourceAddressHigh";
+ case RegID::kRegistersCount:
+ break;
}
+ return "Unknown";
}