From b5397045db290c234a1e779b64538933f93b37b6 Mon Sep 17 00:00:00 2001 From: Oxore Date: Mon, 3 Oct 2022 02:05:09 +0300 Subject: Begin implementing DMA: impl memory to VRAM --- emulator.cpp | 2 + utils.hpp | 2 +- vdp.cpp | 193 ++++++++++++++++++++++++++++++++++++++++++++++++++--------- vdp.hpp | 14 ++++- 4 files changed, 180 insertions(+), 31 deletions(-) diff --git a/emulator.cpp b/emulator.cpp index de9be02..7b2e8a8 100644 --- a/emulator.cpp +++ b/emulator.cpp @@ -216,6 +216,7 @@ static std::string CreateResponse( constexpr size_t value_size = std::string_view("12345678").length(); char value[value_size + 1]{}; const int ret = snprintf(value, value_size + 1, "%08x", state.registers[i]); + (void) ret; assert(ret == value_size); result += std::string(value, value_size); } @@ -244,6 +245,7 @@ static std::string CreateResponse( constexpr size_t value_size = std::string_view("12345678").length(); char value_str[value_size + 1]{}; const int ret = snprintf(value_str, value_size + 1, "%08x", value); + (void) ret; assert(ret == value_size); return std::string(value_str, value_size); } diff --git a/utils.hpp b/utils.hpp index 0c49739..930ae02 100644 --- a/utils.hpp +++ b/utils.hpp @@ -13,10 +13,10 @@ #endif #else #include +#include #define UNREACHABLE (assert((void*)0 == "Unreachable code reached"), abort(), 1) #endif - #include namespace Utils { diff --git a/vdp.cpp b/vdp.cpp index e497bdf..0395d30 100644 --- a/vdp.cpp +++ b/vdp.cpp @@ -3,10 +3,52 @@ #include "vdp.hpp" #include "musashi-m68k/m68k.h" +#include "utils.hpp" +#include #include #include +#define MODESET2_DISP_MASK (1) +#define MODESET2_DISP_SHIFT (6) +#define MODESET2_DISP_GET(reg) \ + (((reg) & (MODESET2_DISP_MASK << MODESET2_DISP_SHIFT)) >> MODESET2_DISP_SHIFT) +#define MODESET2_DISP_SET(reg, v) \ + ((reg) = ((reg) & ~(MODESET2_DISP_MASK << MODESET2_DISP_SHIFT)) \ + | ((v & MODESET2_DISP_MASK) << MODESET2_DISP_SHIFT)) + +#define MODESET2_IE0_MASK (1) +#define MODESET2_IE0_SHIFT (5) +#define MODESET2_IE0_GET(reg) \ + (((reg) & (MODESET2_IE0_MASK << MODESET2_IE0_SHIFT)) >> MODESET2_IE0_SHIFT) +#define MODESET2_IE0_SET(reg, v) \ + ((reg) = ((reg) & ~(MODESET2_IE0_MASK << MODESET2_IE0_SHIFT)) \ + | ((v & MODESET2_IE0_MASK) << MODESET2_IE0_SHIFT)) + +#define MODESET2_M1_MASK (1) +#define MODESET2_M1_SHIFT (4) +#define MODESET2_M1_GET(reg) \ + (((reg) & (MODESET2_M1_MASK << MODESET2_M1_SHIFT)) >> MODESET2_M1_SHIFT) +#define MODESET2_M1_SET(reg, v) \ + ((reg) = ((reg) & ~(MODESET2_M1_MASK << MODESET2_M1_SHIFT)) \ + | ((v & MODESET2_M1_MASK) << MODESET2_M1_SHIFT)) + +#define MODESET2_M2_MASK (1) +#define MODESET2_M2_SHIFT (3) +#define MODESET2_M2_GET(reg) \ + (((reg) & (MODESET2_M2_MASK << MODESET2_M2_SHIFT)) >> MODESET2_M2_SHIFT) +#define MODESET2_M2_SET(reg, v) \ + ((reg) = ((reg) & ~(MODESET2_M2_MASK << MODESET2_M2_SHIFT)) \ + | ((v & MODESET2_M2_MASK) << MODESET2_M2_SHIFT)) + +#define DMASRCADRHIGH_DMD_MASK (3) +#define DMASRCADRHIGH_DMD_SHIFT (6) +#define DMASRCADRHIGH_DMD_GET(reg) \ + (((reg) & (DMASRCADRHIGH_DMD_MASK << DMASRCADRHIGH_DMD_SHIFT)) >> DMASRCADRHIGH_DMD_SHIFT) +#define DMASRCADRHIGH_DMD_SET(reg, v) \ + ((reg) = ((reg) & ~(DMASRCADRHIGH_DMD_MASK << DMASRCADRHIGH_DMD_SHIFT)) \ + | ((v & DMASRCADRHIGH_DMD_MASK) << DMASRCADRHIGH_DMD_SHIFT)) + uint32_t VDP::Read(const uint32_t offset, const enum bitness bitness) { uint32_t ret{}; @@ -76,27 +118,17 @@ void VDP::Write(const uint32_t offset, const enum bitness bitness, const uint32_ } } -#define MODESET2_DISP_MASK (1) -#define MODESET2_DISP_SHIFT (6) -#define MODESET2_DISP_EXTRACT(reg) \ - (((reg) & (MODESET2_DISP_MASK << MODESET2_DISP_SHIFT)) >> MODESET2_DISP_SHIFT) - -#define MODESET2_IE0_MASK (1) -#define MODESET2_IE0_SHIFT (5) -#define MODESET2_IE0_EXTRACT(reg) \ - (((reg) & (MODESET2_IE0_MASK << MODESET2_IE0_SHIFT)) >> MODESET2_IE0_SHIFT) - bool VDP::Scanline() { const uint16_t mode_set_2 = _reg[static_cast(RegID::kModeSet2)]; - if (!MODESET2_DISP_EXTRACT(mode_set_2)) { + if (!MODESET2_DISP_GET(mode_set_2)) { return true; } _lines_counter++; const uint16_t lines_per_screen = _status.pal_mode ? kLinesPerScreenPAL : kLinesPerScreenNTSC; if (_lines_counter >= lines_per_screen) { _lines_counter = 0; - if (MODESET2_IE0_EXTRACT(mode_set_2)) { + if (MODESET2_IE0_GET(mode_set_2)) { m68k_set_irq(6); _status.vblank = true; return true; @@ -194,6 +226,51 @@ void VDP::writeControl(const uint16_t value) addressModeToString(_address_mode), _address); } + const uint16_t mode_set_2 = _reg[static_cast(RegID::kModeSet2)]; + const uint8_t dma_address_mode = (_address_mode >> 4) & 0x3; + if (MODESET2_M1_GET(mode_set_2) && dma_address_mode) { + const uint16_t destination_address = _address; + const uint16_t transfer_size = + _reg[static_cast(RegID::kDMALengthCounterLow)] | + (_reg[static_cast(RegID::kDMALengthCounterHigh)] << 8); + const uint8_t dma_action = + DMASRCADRHIGH_DMD_GET(_reg[static_cast(RegID::kDMASourceAddressHigh)]); + switch (dma_action) { + case 0: + case 1: + { + if (DEBUG_TRACE_VDP_ACCESS) { + printf(": Running DMA Memory to VRAM\n"); + } + const uint32_t source_address = + _reg[static_cast(RegID::kDMASourceAddressLow)] | + (_reg[static_cast(RegID::kDMASourceAddressMid)] << 8) | + ((_reg[static_cast(RegID::kDMASourceAddressHigh)] & 0x3f) << 16); + runDMAMemoryToVRAM( + baseFromAddressMode(_address_mode), + source_address, + destination_address, + transfer_size); + } + break; + case 2: + { + if (DEBUG_TRACE_VDP_ACCESS) { + printf(": Running DMA VRAM Fill\n"); + } + runDMAVRAMFill(baseFromAddressMode(_address_mode)); + } + break; + case 3: + { + if (DEBUG_TRACE_VDP_ACCESS) { + printf(": Running DMA VRAM Copy\n"); + } + runDMAVRAMCopy(baseFromAddressMode(_address_mode)); + } + break; + } + } } else if (IsWriteToReg(value)) { // Write register // 1 0 0 RS4 RS3 RS2 RS1 RS0 @@ -294,18 +371,40 @@ uint16_t VDP::readStatusRegister() const return value; } +uint8_t* VDP::baseFromAddressMode(uint8_t address_mode) +{ + switch (static_cast(address_mode & 0xf)) { + case AddressMode::kVRAMWrite: + return _vram; + case AddressMode::kCRAMWrite: + return _cram; + case AddressMode::kVSRAMWrite: + return _vsram; + case AddressMode::kVRAMRead: + return _vram; + case AddressMode::kCRAMRead: + return _cram; + case AddressMode::kVSRAMRead: + return _vsram; + } + UNREACHABLE; + return nullptr; +} + const char* VDP::addressModeToString(const uint8_t address_mode) { - const uint8_t dma_address_mode = (address_mode >> 5) & 0x3; + // Bits other than CD5-CD0 cannot be set + assert((address_mode >> 6) == 0); + const uint8_t dma_address_mode = (address_mode >> 4) & 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"; + return "DMA ???, VRAM write"; case 2: - return "DMA VRAM fill, VRAM write"; + return "DMA Memory to VRAM/VRAM fill, VRAM write"; case 3: return "DMA VRAM copy, VRAM write"; } @@ -315,9 +414,9 @@ const char* VDP::addressModeToString(const uint8_t address_mode) case 0: return "CRAM write"; case 1: - return "DMA Memory to VRAM, CRAM write"; + return "DMA ???, CRAM write"; case 2: - return "DMA VRAM fill, CRAM write"; + return "DMA Memory to VRAM/VRAM fill, CRAM write"; case 3: return "DMA VRAM copy, CRAM write"; } @@ -327,9 +426,9 @@ const char* VDP::addressModeToString(const uint8_t address_mode) case 0: return "VSRAM write"; case 1: - return "DMA Memory to VRAM, VSRAM write"; + return "DMA ???, VSRAM write"; case 2: - return "DMA VRAM fill, VSRAM write"; + return "DMA Memory to VRAM/VRAM fill, VSRAM write"; case 3: return "DMA VRAM copy, VSRAM write"; } @@ -339,9 +438,9 @@ const char* VDP::addressModeToString(const uint8_t address_mode) case 0: return "VRAM read"; case 1: - return "DMA Memory to VRAM, VRAM read"; + return "DMA ???, VRAM read"; case 2: - return "DMA VRAM fill, VRAM read"; + return "DMA Memory to VRAM/VRAM fill, VRAM read"; case 3: return "DMA VRAM copy, VRAM read"; } @@ -351,9 +450,9 @@ const char* VDP::addressModeToString(const uint8_t address_mode) case 0: return "CRAM read"; case 1: - return "DMA Memory to VRAM, CRAM read"; + return "DMA ???, CRAM read"; case 2: - return "DMA VRAM fill, CRAM read"; + return "DMA Memory to VRAM/VRAM fill, CRAM read"; case 3: return "DMA VRAM copy, CRAM read"; } @@ -363,14 +462,15 @@ const char* VDP::addressModeToString(const uint8_t address_mode) case 0: return "VSRAM read"; case 1: - return "DMA Memory to VRAM, VSRAM read"; + return "DMA ???, VSRAM read"; case 2: - return "DMA VRAM fill, VSRAM read"; + return "DMA Memory to VRAM/VRAM fill, VSRAM read"; case 3: return "DMA VRAM copy, VSRAM read"; } break; } + UNREACHABLE; return "Unknown"; } @@ -407,9 +507,9 @@ const char* VDP::regIDToString(const RegID reg_id) return "WindowHorizontalPosition"; case RegID::kWindowVertialPosition: return "WindowVertialPosition"; - case RegID::kDMACounterLow: + case RegID::kDMALengthCounterLow: return "DMACounterLow"; - case RegID::kDMACounterHigh: + case RegID::kDMALengthCounterHigh: return "DMACounterHigh"; case RegID::kDMASourceAddressLow: return "DMASourceAddressLow"; @@ -422,3 +522,42 @@ const char* VDP::regIDToString(const RegID reg_id) } return "Unknown"; } + +void VDP::runDMAMemoryToVRAM( + uint8_t* const base, + const uint32_t source_address, + const uint16_t destination_address, + const uint16_t transfer_size) +{ + constexpr size_t kDumpWidth = 16; + constexpr size_t kVisualColumnWidth = 8; + for (size_t i = 0; i < transfer_size; i++) { + const uint32_t src_addr = source_address + i; + const uint32_t dst_addr = destination_address + i; + const uint8_t value = m68k_read_memory_8(src_addr); + if (DEBUG_TRACE_VDP_ACCESS) { + if (i % kDumpWidth == 0) { + printf("%06x:%06x: ", src_addr, dst_addr); + } + printf("%02x ", value); + if (i % kVisualColumnWidth == kVisualColumnWidth - 1) { + printf(" "); + } else if (i % kDumpWidth == kDumpWidth - 1) { + printf("\n"); + } + } + base[dst_addr] = value; + } +} + +void VDP::runDMAVRAMFill(uint8_t* base) +{ + (void) base; + // TODO +} + +void VDP::runDMAVRAMCopy(uint8_t* base) +{ + (void) base; + // TODO +} diff --git a/vdp.hpp b/vdp.hpp index 9357377..030b38e 100644 --- a/vdp.hpp +++ b/vdp.hpp @@ -57,8 +57,8 @@ class VDP { kScrollSize = 16, kWindowHorizontalPosition = 17, kWindowVertialPosition = 18, - kDMACounterLow = 19, - kDMACounterHigh = 20, + kDMALengthCounterLow = 19, + kDMALengthCounterHigh = 20, kDMASourceAddressLow = 21, kDMASourceAddressMid = 22, kDMASourceAddressHigh = 23, @@ -69,10 +69,18 @@ class VDP { void writeControl(uint16_t value); uint16_t readData(uint8_t address_mode, uint16_t address); uint16_t readStatusRegister() const; - + uint8_t* baseFromAddressMode(uint8_t address_mode); const char* addressModeToString(uint8_t address_mode); const char* regIDToString(RegID); + static void runDMAMemoryToVRAM( + uint8_t* base, + uint32_t source_address, + uint16_t destination_address, + uint16_t transfer_size); + static void runDMAVRAMFill(uint8_t* base); + static void runDMAVRAMCopy(uint8_t* base); + static constexpr size_t kRegistersCount = static_cast(RegID::kRegistersCount); static constexpr size_t kVRAMSize = 64*1024; static constexpr size_t kCRAMSize = 64*2; -- cgit v1.2.3