summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorOxore <oxore@protonmail.com>2022-10-03 02:05:09 +0300
committerOxore <oxore@protonmail.com>2022-10-03 02:05:09 +0300
commitb5397045db290c234a1e779b64538933f93b37b6 (patch)
tree16feb8aabd2f3ae1714e3fbaeea79fc89a6e6c2b
parent872d2c2766536a372af5d1048bed7514078f9d31 (diff)
Begin implementing DMA: impl memory to VRAM
-rw-r--r--emulator.cpp2
-rw-r--r--utils.hpp2
-rw-r--r--vdp.cpp193
-rw-r--r--vdp.hpp14
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 <cassert>
+#include <cstdlib>
#define UNREACHABLE (assert((void*)0 == "Unreachable code reached"), abort(), 1)
#endif
-
#include <stdint.h>
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 <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
+}
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<size_t>(RegID::kRegistersCount);
static constexpr size_t kVRAMSize = 64*1024;
static constexpr size_t kCRAMSize = 64*2;