From a2f19b2d29a4de58cc96497afbfa652d46c4bbc5 Mon Sep 17 00:00:00 2001 From: SDD Date: Fri, 16 Oct 2026 01:54:37 +0300 Subject: [PATCH] harness: model the 0x5800000/0x5900000 DMA command/data pair --- harness/mame/test_vt1200_board.cpp | 15 +++++++++++++++ harness/mame/vt1200_board.cpp | 18 ++++++++++++++++++ harness/mame/vt1200_board.h | 13 +++++++++++++ 3 files changed, 46 insertions(+) diff --git a/harness/mame/test_vt1200_board.cpp b/harness/mame/test_vt1200_board.cpp index 2d0a7b6..225603b 100644 --- a/harness/mame/test_vt1200_board.cpp +++ b/harness/mame/test_vt1200_board.cpp @@ -86,6 +86,20 @@ static void test_switch_mix_only_when_configured(void) CHECK(b.read(VT1200_WIN3 + VT1200_OFF_SWITCH) == 0x0070); // returned verbatim } +static void test_dma_pair_command_completes(void) +{ + vt1200_board b; + b.set_model_handshake(true); + b.set_dma_ticks(2); + + b.write(VT1200_WIN0, 0x0000); // data port first (as the firmware does) + b.write(VT1200_WIN1, 0x0001); // then a command + CHECK(b.read(VT1200_WIN1) == 0x0001); // accepted + + b.tick(); b.tick(); + CHECK(b.read(VT1200_WIN1) == 0x0000); // completed +} + int main(void) { test_default_read(); @@ -95,6 +109,7 @@ int main(void) test_windows_are_independent(); test_monitor_switch_accepts_raw_bits_or_position(); test_switch_mix_only_when_configured(); + test_dma_pair_command_completes(); std::printf(failures ? "%d FAILURE(S)\n" : "all board tests passed\n", failures); return failures ? 1 : 0; } diff --git a/harness/mame/vt1200_board.cpp b/harness/mame/vt1200_board.cpp index 5a4560a..75b1a6e 100644 --- a/harness/mame/vt1200_board.cpp +++ b/harness/mame/vt1200_board.cpp @@ -18,6 +18,11 @@ uint16_t vt1200_board::read(uint32_t addr) if (st != m_store.end()) value = st->second; + // DMA command port: while a command is in flight the port reads back the + // latched command; once the configured ticks elapse it reads back 0. + if (m_dma_ticks > 0 && (addr & 0xffff0000) == VT1200_WIN1) + return (m_dma_left > 0) ? m_dma_cmd : (uint16_t)0x0000; + if (m_switch_set && is_switch_port(addr)) return (uint16_t)((value & 0xff8f) | (m_switch_bits & 0x0070)); @@ -41,6 +46,15 @@ void vt1200_board::write(uint32_t addr, uint16_t data) auto ticks = m_busy_ticks_by_win.find(win); m_busy_left[win] = (ticks != m_busy_ticks_by_win.end()) ? ticks->second : 0; } + + // A command written to the DMA command port (WIN1) is latched and, when the + // DMA model is configured, starts its completion timer. + if ((addr & 0xffff0000) == VT1200_WIN1) + { + m_dma_cmd = data; + if (m_dma_ticks > 0) + m_dma_left = m_dma_ticks; + } } void vt1200_board::tick() @@ -49,4 +63,8 @@ void vt1200_board::tick() for (auto &entry : m_busy_left) if (entry.second > 0) entry.second--; + + // Merge the DMA pair's timer into the same tick. + if (m_dma_left > 0) + m_dma_left--; } diff --git a/harness/mame/vt1200_board.h b/harness/mame/vt1200_board.h index e4a8279..f8f8e6a 100644 --- a/harness/mame/vt1200_board.h +++ b/harness/mame/vt1200_board.h @@ -53,6 +53,12 @@ public: } void set_window_busy_ticks(uint32_t window_base, int n) { m_busy_ticks_by_win[window_base] = n; } + // DMA command/data pair at WIN0 (data) / WIN1 (command). A write to the + // command port is accepted and reads back its value for n ticks; after the + // ticks elapse the command port reads back 0. n == 0 (the default) leaves + // the pair with no DMA semantics, so the port just behaves as a latch. + void set_dma_ticks(int n) { m_dma_ticks = n; } + // Monitor switch (bits 4-6 of the switch port). The argument is accepted // unambiguously as EITHER the raw register bits (e.g. 0x70) OR a small // position 0-7: a value above 0x07 is taken as the raw bit pattern, any @@ -82,6 +88,13 @@ private: // count for the command currently in flight. std::map m_busy_ticks_by_win; std::map m_busy_left; + // DMA command/data pair. m_dma_ticks is the configured completion time; + // m_dma_left is how many ticks remain for the command in flight; m_dma_cmd + // is the value written to the command port. All three only have meaning + // when m_dma_ticks > 0. + int m_dma_ticks = 0; + int m_dma_left = 0; + uint16_t m_dma_cmd = 0; bool m_switch_set = false; // set_monitor_switch was called uint16_t m_switch_bits = 0; };