Files
vt1200/harness/mame/README.md
T

180 lines
7.4 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# VT1200 execution harness (MAME)
A minimal MAME machine that loads the VT1200 firmware into a TMS34010 CPU so
we can **run it under MAME's debugger**: instruction trace, breakpoints,
single-stepping, and direct memory watch. It is a *visibility* tool, not an
accurate VT1200 emulation.
Everything in this directory is source-of-truth in this repo; the MAME source
tree is disposable and lives outside the project
(`/home/arti/code/k-space/mame0289`).
```
harness/mame/
├── vt1200.cpp # the MAME driver (symlinked into the MAME tree)
├── build.sh # clone-safe build wrapper
├── *.lua # probe / capture / dump scripts (many; see the reports)
└── roms/vt1200/ # MAME ROM dir (symlink to ../../vt1200_v22.bin)
```
Reports in this directory:
| file | what it records |
|---|---|
| `GATE_CLEANUP_REPORT.md` | promoting the working config to the default; retiring the settled env gates |
| `RENDER_REPORT.md` | the active-pixel scanline renderer, and the geometry it derived |
| `DUART_REPORT.md` | the DUARTs: wiring, the ISR-driven transmit, the datasheet-verified model edits |
| `BRINGUP_LOG.md` | the whole bring-up narrative, **including withdrawn claims** — read it sceptically |
| `ROMPATCH_REPORT.md` | runtime ROM patching (debug only — see the caveat) |
## Address model (the important part)
The TMS34010 is **bit-addressed**: a register/PC holds a bit address, and a
pointer `P` refers to physical byte `P >> 3`. MAME models this with a program
space of `memory_access<32, 1, 3>`, i.e. the **address-map unit is 1 bit**
(a 16-bit word spans 16 address units). Source: `tms34010.h` — note the
TMS34020 differs (`memory_access<32, 2, 3>`), so this is *not* interchangeable
with the 34020. Therefore:
* Address-map entries here are **bit addresses**, not byte addresses.
* `read_word(0x3f200000)` returns ROM bytes 0..1 (physical byte 0x07e40000).
* The reset vector is read from logical bit `0xffffffe0`, which maps to the
last 4 bytes of the image (file offset `0x1bfffc`).
The driver maps:
| region | bit range | bytes |
|---|---|---|
| RAM | `0x00000000`–`0x001fffff` | 4 MiB at byte 0 |
| ROM | `0x3f200000`–`0x3fffffff` | 1.75 MiB at byte 0x07e40000 |
| ROM aliases | `0x7f…`, `0xbf…`, `0xff200000`–`0xffffffff` | same ROM (top 2 logical bits not decoded) |
The `0xff…` alias is what makes the reset-vector page resolve.
### What is modelled by default
This **changed** — see `GATE_CLEANUP_REPORT.md`. The working configuration used
to be a six-variable incantation; it is now the default, and a bare
`vt1200 vt1200` with **no environment** runs it.
* Video RAM at bit `0x04000000` — required for the level-1 VIDEO MEMORY test.
* The board-window handshake model (two-tick busy bit).
* MAME's `SCN2681` DUART at **DUART1** (`0x0640000`, host/printer), with input
port **IP4–IP6 held high** — that is how the driver reads the VR150 monitor
switch (`0x70`). The level-1 host-port transmit is **ISR-driven**, so a real
DUART is required here, not a convenience.
* A mono palette (pens 0/1 = black/white) and an active-pixel scanline renderer
that reads VRAM. See `RENDER_REPORT.md`.
A bare run progresses through POST and level 1 and stops at `HOST PORT - 15`,
then **wedges in the system-board LED loop** — a level-1 failure is *fatal*, not
merely reported, so the OS is unreachable while it fails.
### What is not modelled
**LANCE Ethernet**, and **DUART2** (`0x0620000`, keyboard/mouse — opt in with
`VT1200_DUART2=1`). The OS is therefore not usable yet: it is reached, but it
does not paint.
### Getting past level 1
`VT1200_SKIP_LEVEL1=1` drives DUART1's **IP3** high, which the firmware takes as
a signal to jump to the OS cold-start and skip **all 15** level-1 tests. Note
what this is: a *modelled board input*, and the real machine reads IP3 **low**.
So a level-1-skipped run is evidence about the **OS, graphics and crash
behaviour**, and is **not** evidence about the real terminal's POST.
The skip is deliberately **not** the default: the real machine runs level 1, so
the faithful configuration stays the default and the switch is how we diverge.
## Environment knobs (14; down from 33)
All opt-in, all off by default, so a bare run is the working configuration.
Instrumentation: `VT1200_DUARTLOG`, `VT1200_BOARD_LOG`, `VT1200_BOARD_MAP`,
`VT1200_IRQLOG`, `VT1200_LOG_UNMAPPED`, `VT1200_DPYLOG` (+`_FRAMES`),
`VT1200_DUMP_FRAME`, `VT1200_DUMP_RAM`, `VT1200_DUMP_VRAM`, `VT1200_DUMP_DIR`,
`VT1200_NO_RENDER`. Behaviour switches: `VT1200_SKIP_LEVEL1`, `VT1200_DUART2`.
## Regression baseline
`progress.lua` at 200 frames, **no env**:
```
PC=3FDCE400 samples=53 (78 distinct PCs)
```
This value **changed** when the working config became the default — previously
`PC=3FDCE400 samples=199` (a single PC), because a no-env run used to wedge at
the hardware-ready gate. The new value is *better*: a bare run now executes real
POST work. It is a change detector, not a specification — if it moves without
you meaning it to, find out why.
## Build
MAME source is required. A shallow 0.289 checkout is large and slow to fetch.
```sh
git clone --depth 1 --branch mame0289 \
https://github.com/mamedev/mame.git /home/arti/code/k-space/mame0289
harness/mame/build.sh # symlinks the driver in and runs make
```
`build.sh` runs `make -j$JOBS SUBTARGET=vt1200
SOURCES=src/mame/dec/vt1200.cpp`, which builds a single-driver binary
`/home/arti/code/k-space/mame0289/vt1200`.
The MAME tree is large and the build is **memory-hungry**: `build.sh`
defaults to **`-j8`**, not all cores. Override with `JOBS=4
harness/mame/build.sh` on a small/low-memory machine. Progress is written to
`harness/mame/build.log`.
## Run
Headless execution and inspection use MAME's Lua debugger API from
`-autoboot_script`. (`-debugscript` only works when a debugger UI drives the
console, so it is not usable headless.)
```sh
cd /home/arti/code/k-space/vt1200
M=/home/arti/code/k-space/mame0289/vt1200
# trace execution from the reset vector
$M vt1200 -rompath harness/mame/roms -video none -sound none -nothrottle \
-debug -debugger none \
-autoboot_script harness/mame/trace.lua -autoboot_delay 0
# demonstrate the pcfReadBitmaps n*4 overflow (OVF_N overrides n, decimal)
$M vt1200 -rompath harness/mame/roms -video none -sound none -nothrottle \
-debug -debugger none -debuglog -seconds_to_run 5 \
-autoboot_script harness/mame/overflow.lua -autoboot_delay 0
```
The Lua API exposes `manager.machine.debugger`, `device.debug` (step, go,
bpset, wpset), CPU registers (`cpu.state['A0'].value`), memory
(`cpu.spaces['program']:read_u32/write_u32`), and frame hooks.
### Trace from the reset vector (`trace.lua`)
Prints the reset PC (expect `3F200040`), disassembles the power-on code to
`reset.dasm`, and writes an instruction trace of the first two frames to
`vt1200-reset.trace`.
### Exercise the `pcfReadBitmaps` overflow (`overflow.lua`)
Instead of booting the parser we jump directly into its arithmetic block with
a crafted in-memory `PCF_CharInfo`:
```
a9 = 0x00040000 ; fake pCS; pCS->nChars at a9+0x270
a13 = 0x00060000 ; fake arg blk; n (from pcfReadInt32) at a13+0x20
write_u32(0x00040270, 0) ; nChars == 0
write_u32(0x00060020, n) ; n
pc = 3f984e70
break at 3f985060 ; just after 'sll 0x2,a11'
```
This is possible because the font parser's field moves use **field 1**, which
`SETF 0,0,1` leaves at 32 bits, so `n` is a full 32-bit `pcfReadInt32` value.
See `FINDINGS.md` for results and the rest of the analysis.