diff --git a/harness/mame/BRINGUP_LOG.md b/harness/mame/BRINGUP_LOG.md index bca8067..d525a1c 100644 --- a/harness/mame/BRINGUP_LOG.md +++ b/harness/mame/BRINGUP_LOG.md @@ -16,7 +16,8 @@ handshake the firmware waits on and modelling it correctly. | `VT1200_BOARD_MAP=` | per-address fixed return values, e.g. `0x06200001=1` | | `VT1200_BOARD_DEFAULT=` | value for addresses with no override | | `VT1200_BOARD_MODEL=handshake` | write-back registers **plus a self-clearing busy bit** | -| `VT1200_BOARD_BUSY=` / `_TICKS=` / `_BIT=` | tune the handshake | +| `VT1200_BOARD_BUSY_TICKS=` | busy-bit tick count for `VT1200_BOARD_MODEL=handshake` (the busy bit is fixed to bit 0 of the `+0x10` STATUS register) | +| `VT1200_BOARD_SWITCH=::` | monitor switch: bits 4-6 of `0x0640000D` read as `` (raw bits, or a position 0-7) | | `VT1200_BOARD_RAM=1` | windows behave as plain read/write RAM | | `VT1200_NO_RENDER=1` | restore the old blank-everything video behaviour | | `VT1200_DUMP_FRAME=` / `VT1200_DUMP_DIR=` | write that frame as a PPM | @@ -331,6 +332,11 @@ a constant for the whole byte breaks the output bits, so the boot stays stuck. New harness knob for exactly this: **`VT1200_BOARD_SWITCH=::`** — bits in `` read as ``, all other bits stay write-back. +*(Updated 2026-10-16: the model now applies this mix only to the monitor switch port +`0x0640000D` with mask `0x70`, and `` is the raw bits **or** a position 0-7. A +different ``/`` is warned about and ignored — see the extraction section at +the end.)* + ``` VT1200_BOARD_MODEL=handshake VT1200_BOARD_BUSY_TICKS=2 \ VT1200_BOARD_SWITCH="0640000D:70:70" @@ -548,7 +554,8 @@ unrelated blocks — and it explains why the same shapes keep appearing. interface traffic will live, and level 0 requires the LANCE. 2. **Find what the firmware waits for before enabling interrupts.** `INTENB` is never written at all (verified with watchpoints), so the stall is a board-level wait. -3. **Hunt the remaining bit-mixed ports** (`VT1200_BOARD_SWITCH=::`). +3. **Hunt the remaining bit-mixed ports** — note `VT1200_BOARD_SWITCH` now models only + the monitor switch port (`0x0640000D`, bits 4-6); other ports warn and are ignored. 4. **Build the stateful status model**: board status bits are busy/done handshakes, never constants — every gate so far has needed behaviour. 5. **Write the scanline renderer** (needs the framebuffer layout; MAME has no generic @@ -562,7 +569,8 @@ unrelated blocks — and it explains why the same shapes keep appearing. `0x000EE4` (reset-bank disables) plus `0x06F308`, `0x09DC54`, `0x09DC60`, `0x09DDAC`. 2. **Hunt the remaining bit-mixed ports** — level 0 includes an *I/O data path test*, and every other configuration input will have the shape "input bits mixed with - latched outputs" (use `VT1200_BOARD_SWITCH=::`). + latched outputs" — note `VT1200_BOARD_SWITCH` now models only the monitor switch port + (`0x0640000D`, bits 4-6); other ports warn and are ignored. 3. **Build the stateful status model** (gate 4, and the video / I-O-path tests): a graphics or I/O op starts -> busy bit set -> clears after N reads. Every gate so far has needed behaviour, never a constant. @@ -603,8 +611,10 @@ The busy bit now has the semantics the design spec intended: a write to `+0x20` inline code armed on any write and cleared after N *reads*). The old `VT1200_BOARD_BUSY` and `VT1200_BOARD_BUSY_BIT` knobs are dropped — the model hardcodes the busy bit as bit 0 of the STATUS register. `VT1200_BOARD_SWITCH` is likewise narrowed to the monitor switch -(bits 4-6 of `0x64000D0`); the arbitrary `::` form is no longer -honoured. +(bits 4-6 of `0x64000D0`): `` is accepted as the raw register bits (e.g. `70`) or a +position 0-7, and the input mix is applied only when the knob is supplied. A `` or +`` that does not match the monitor switch port warns (via `osd_printf_info`) and is +ignored instead of silently no-oping. No regression: with no env vars the wedge is still `PC=3FDCE400 samples=199`, and the handshake config (`MODEL=handshake BUSY_TICKS=2 SWITCH=0640000D:70:70`) still advances diff --git a/harness/mame/test_vt1200_board.cpp b/harness/mame/test_vt1200_board.cpp index 2c8403d..bc31dcd 100644 --- a/harness/mame/test_vt1200_board.cpp +++ b/harness/mame/test_vt1200_board.cpp @@ -49,12 +49,34 @@ static void test_busy_bit_arms_on_write_and_clears(void) CHECK((b.read(status) & 0x0001) == 0x0000); // done } +static void test_monitor_switch_accepts_raw_bits_or_position(void) +{ + vt1200_board raw; + raw.set_monitor_switch(0x70); // raw register bits + raw.write(VT1200_WIN3 + VT1200_OFF_SWITCH, 0x0001); + CHECK((raw.read(VT1200_WIN3 + VT1200_OFF_SWITCH) & 0x0070) == 0x0070); + + vt1200_board pos; + pos.set_monitor_switch(7); // position 7 + pos.write(VT1200_WIN3 + VT1200_OFF_SWITCH, 0x0001); + CHECK((pos.read(VT1200_WIN3 + VT1200_OFF_SWITCH) & 0x0070) == 0x0070); +} + +static void test_switch_mix_only_when_configured(void) +{ + vt1200_board b; // no set_monitor_switch call + b.write(VT1200_WIN3 + VT1200_OFF_SWITCH, 0x0070); + CHECK(b.read(VT1200_WIN3 + VT1200_OFF_SWITCH) == 0x0070); // returned verbatim +} + int main(void) { test_default_read(); test_override_read(); test_monitor_switch_is_mixed_with_latches(); test_busy_bit_arms_on_write_and_clears(); + test_monitor_switch_accepts_raw_bits_or_position(); + test_switch_mix_only_when_configured(); std::printf(failures ? "%d FAILURE(S)\n" : "all board tests passed\n", failures); return failures ? 1 : 0; } diff --git a/harness/mame/vt1200.cpp b/harness/mame/vt1200.cpp index 7c313a8..a037c13 100644 --- a/harness/mame/vt1200.cpp +++ b/harness/mame/vt1200.cpp @@ -179,12 +179,21 @@ void vt1200_state::machine_start() m_board.set_busy_ticks((int)strtol(t, nullptr, 0)); // The monitor-selection switch lives in bits 4-6 of 0x64000D0. The model - // mixes those input bits with the port's write-back output latches. + // mixes those input bits with the port's write-back output latches; the + // value may be the raw register bits (e.g. 70) or a position 0-7. Any + // other port or mask is not modelled, so say so rather than ignoring it. if (const char *sw = getenv("VT1200_BOARD_SWITCH")) { unsigned a = 0, m = 0, v = 0; if (sscanf(sw, "%x:%x:%x", &a, &m, &v) == 3) - m_board.set_monitor_switch(u8((v & 0x70) >> 4)); + { + if (a != VT1200_WIN3 + VT1200_OFF_SWITCH) + osd_printf_info("vt1200: VT1200_BOARD_SWITCH addr %07X is not the monitor switch port %07X; addr ignored\n", + a, VT1200_WIN3 + VT1200_OFF_SWITCH); + if (m != 0x70) + osd_printf_info("vt1200: VT1200_BOARD_SWITCH mask %02X is not the monitor switch mask 70; mask ignored\n", m); + m_board.set_monitor_switch(u8(v)); + } } // Video: render by default; optionally dump a frame as PPM. diff --git a/harness/mame/vt1200_board.cpp b/harness/mame/vt1200_board.cpp index ae71648..89ae469 100644 --- a/harness/mame/vt1200_board.cpp +++ b/harness/mame/vt1200_board.cpp @@ -18,7 +18,7 @@ uint16_t vt1200_board::read(uint32_t addr) if (st != m_store.end()) value = st->second; - if (is_switch_port(addr)) + if (m_switch_set && is_switch_port(addr)) return (uint16_t)((value & 0xff8f) | (m_switch_bits & 0x0070)); if (m_handshake && (addr & 0xffff) == VT1200_OFF_STATUS) diff --git a/harness/mame/vt1200_board.h b/harness/mame/vt1200_board.h index 7a69e0f..f0c1bc3 100644 --- a/harness/mame/vt1200_board.h +++ b/harness/mame/vt1200_board.h @@ -41,7 +41,18 @@ public: void set_override(uint32_t addr, uint16_t v) { m_override[addr] = v; } void set_model_handshake(bool on) { m_handshake = on; } void set_busy_ticks(int n) { m_busy_ticks = n; } - void set_monitor_switch(uint8_t position) { m_switch_bits = (uint16_t)((position & 7) << 4); } + + // 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 + // value <= 0x07 is a position and is shifted into bits 4-6. The input mix + // is only applied to reads after this has been called. + void set_monitor_switch(uint8_t bits_or_position) + { + m_switch_bits = (uint16_t)(bits_or_position > 0x07 + ? bits_or_position : ((bits_or_position & 0x07) << 4)); + m_switch_set = true; + } // Bus interface. uint16_t read(uint32_t addr); @@ -57,5 +68,6 @@ private: bool m_handshake = false; int m_busy_ticks = 0; int m_busy_left = 0; + bool m_switch_set = false; // set_monitor_switch was called uint16_t m_switch_bits = 0; };