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.
This commit is contained in:
SDD committed 2026-10-16 13:01:40 +03:00
1 parent c19c603d77
commit 6cbb362bb9
2 files changed
+20 -1

No files matched your search

+4
View File
@@ -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
+16 -1
View File
@@ -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<scn2681_device> m_duart1; // 0x0640000: host(A)/printer(B)
required_device<scn2681_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)