From 72abe5f3e714df9cc8310a78bdfa648feb79c4d2 Mon Sep 17 00:00:00 2001 From: Oxore Date: Sat, 1 Oct 2022 19:34:58 +0300 Subject: Add more VDP tracing, add VRAM, CRAM, VSRAM and status --- vdp.cpp | 344 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 331 insertions(+), 13 deletions(-) (limited to 'vdp.cpp') 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 +#include + 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(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(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(RegID::kAutoIncrement)]; + writeData(_address_mode, _address & 0xfffe, value & 0xffff); + _address += _reg[static_cast(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(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(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(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(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(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"; } -- cgit v1.2.3