From 6cbb362bb917f9de5d60570e23d9efe1a8fd69d1 Mon Sep 17 00:00:00 2001 From: SDD Date: Fri, 16 Oct 2026 13:01:40 +0300 Subject: [PATCH] harness: VT1200_DUART1_INT2 -- route DUART1's IRQ to INT2 (A/B knob) The OS's DUART1 driver services the 0x6400000 window from the INT2 stub (0x0F30 -> 0x3FA93070); with the default INT1 wiring the DUART1 TxRDY IRQ is handed to the INT1 stub's 0x5800000 board-DMA handler (0x3F7151F0 -> 0x3F9D5B40), which never reads the DUART ISR, so INTPEND's INT1 bit stays latched and the CPU re-enters the handler ~387x per frame. Empirical A/B (level-1-skipped boot via VT1200_DUART_IP3): default (INT1): INT1 stub entered 387x in one frame; screen frozen. VT1200_DUART1_INT2=1: zero interrupt entries in a one-frame trace; the OS reads DUART1 ISR (reg5) at pc=3FB43900 right after the IRQ. INTENB reads 0x0606 (INT1|INT2|HI|DI), so the routing (not the enable mask) is what identifies the line. Opt-in; default unchanged. osprobe.lua: also print INTENB and DUART1 MR1A/CSRA in the globals dump. --- harness/mame/osprobe.lua | 4 ++++ harness/mame/vt1200.cpp | 17 ++++++++++++++++- 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/harness/mame/osprobe.lua b/harness/mame/osprobe.lua index d88739f..ccf7575 100644 --- a/harness/mame/osprobe.lua +++ b/harness/mame/osprobe.lua @@ -64,6 +64,10 @@ emu.register_frame_done(function() local v = p:read_u32(g) print(string.format("GLOBAL @%08X = %08X", g, v)) end + -- TMS34010 on-chip INTENB (0xC0000110): which external lines are enabled. + print(string.format("INTENB = %04X", p:read_u16(0xc0000110))) + -- DUART1 MR1A (reg0) and CSRA (reg2) are side-effect-free reads. + print(string.format("DUART1 MR1A=%02X CSRA=%02X", p:read_u16(0x6400000) & 0xff, p:read_u16(0x6400020) & 0xff)) end local v = pc.value hist[v] = (hist[v] or 0) + 1 diff --git a/harness/mame/vt1200.cpp b/harness/mame/vt1200.cpp index 8d4e736..430f6ef 100644 --- a/harness/mame/vt1200.cpp +++ b/harness/mame/vt1200.cpp @@ -65,6 +65,16 @@ input, not a ROM change: the real terminal reads IP3 low. See reference/level1-bypass-analysis.md. + VT1200_DUART1_INT2=1 route DUART1's IRQ to TMS34010 INT2 (input + line 1) instead of INT1 (line 0). Default + is INT1, the wiring the level-1 self-test + wanted. The OS's DUART1 driver attaches to + INT2 (its stub 0x0F30 -> 0x3FA93070 handles + the 0x6400000 window), so with the default + the OS's DUART interrupt is serviced by the + INT1 stub's 0x5800000 board-DMA handler and + never acknowledged. Kept opt-in so the two + wirings can be A/B tested. Video: the driver paints the active scanlines itself, reading the framebuffer out of video RAM (see render_active_line). VT1200_NO_RENDER=1 @@ -211,6 +221,7 @@ private: // byte 2N, i.e. harness offset N), which MAME's 68681 model expects. required_device m_duart1; // 0x0640000: host(A)/printer(B) required_device m_duart2; // 0x0620000: keyboard(A)/mouse(B) + bool m_duart1_int2 = false; // VT1200_DUART1_INT2 // The four undecoded board windows, owned by the standalone model in // vt1200_board.h so it can be unit-tested without MAME. The driver only @@ -484,6 +495,10 @@ void vt1200_state::machine_start() // (0x3F5788C0) and skip the whole level-1 self-test batch. if (getenv("VT1200_DUART_IP3")) m_duart1->ip3_w(1); + // VT1200_DUART1_INT2=1 routes DUART1's IRQ to INT2 (line 1) so + // the OS's DUART1 driver (INT2 stub 0x0F30 -> 0x3FA93070) can + // acknowledge it, instead of the INT1 board-DMA handler. + m_duart1_int2 = (getenv("VT1200_DUART1_INT2") != nullptr); } } @@ -925,7 +940,7 @@ void vt1200_state::duart1_irq_w(int state) (unsigned long long)m_maincpu->total_cycles()); fflush(m_irqlog); } - m_maincpu->set_input_line(0, state ? ASSERT_LINE : CLEAR_LINE); + m_maincpu->set_input_line(m_duart1_int2 ? 1 : 0, state ? ASSERT_LINE : CLEAR_LINE); } void vt1200_state::duart2_irq_w(int state)