diff options
author | Oxore <oxore@protonmail.com> | 2022-10-03 02:05:09 +0300 |
---|---|---|
committer | Oxore <oxore@protonmail.com> | 2022-10-03 02:05:09 +0300 |
commit | b5397045db290c234a1e779b64538933f93b37b6 (patch) | |
tree | 16feb8aabd2f3ae1714e3fbaeea79fc89a6e6c2b /vdp.cpp | |
parent | 872d2c2766536a372af5d1048bed7514078f9d31 (diff) |
Begin implementing DMA: impl memory to VRAM
Diffstat (limited to 'vdp.cpp')
-rw-r--r-- | vdp.cpp | 193 |
1 files changed, 166 insertions, 27 deletions
@@ -3,10 +3,52 @@ #include "vdp.hpp" #include "musashi-m68k/m68k.h" +#include "utils.hpp" +#include <cassert> #include <cstring> #include <cstdio> +#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<size_t>(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<size_t>(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<size_t>(RegID::kDMALengthCounterLow)] | + (_reg[static_cast<size_t>(RegID::kDMALengthCounterHigh)] << 8); + const uint8_t dma_action = + DMASRCADRHIGH_DMD_GET(_reg[static_cast<size_t>(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<size_t>(RegID::kDMASourceAddressLow)] | + (_reg[static_cast<size_t>(RegID::kDMASourceAddressMid)] << 8) | + ((_reg[static_cast<size_t>(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<AddressMode>(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<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"; + 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 +} |