docs: memory-space map from the spike; commit the plan amendment; ignore harness logs

This commit is contained in:
SDD committed 2026-10-16 02:15:13 +03:00
1 parent e23dadcfd4
commit 66784de1aa
6 files changed
+99 -66

No files matched your search

+3
View File
@@ -33,3 +33,6 @@ lat/code/latd/
harness/mame/vt1200-reset.trace
reference/x11/
tools/ghidra-headless-mcp/
# Generated harness logs
harness/mame/board-*.log
@@ -256,7 +256,13 @@ Expected: `all board tests passed`
- [ ] **Step 6: Wire the driver to the model and verify no regression**
In `harness/mame/vt1200.cpp`: add `#include "vt1200_board.h"`, give `vt1200_state` a `vt1200_board m_board;` member, and in `board_read`/`board_write` delegate to `m_board.read(addr)` / `m_board.write(addr, data)` instead of the current inline logic. In `machine_start`, translate the existing env vars into the model's setters (`VT1200_BOARD_DEFAULT`, `VT1200_BOARD_MAP`, `VT1200_BOARD_MODEL`, `VT1200_BOARD_BUSY_TICKS`, `VT1200_BOARD_SWITCH`). Call `m_board.tick()` once per emulated frame — the simplest correct place is the existing `scanline` callback guarded so it only fires once per frame, or `screen_update` when `cliprect.min_y == 0`.
In `harness/mame/vt1200.cpp`: add `#include "vt1200_board.h"`, give `vt1200_state` a `vt1200_board m_board;` member, and in `board_read`/`board_write` delegate to `m_board.read(addr)` / `m_board.write(addr, data)` instead of the current inline logic. In `machine_start`, translate the existing env vars into the model's setters (`VT1200_BOARD_DEFAULT`, `VT1200_BOARD_MAP`, `VT1200_BOARD_MODEL`, `VT1200_BOARD_BUSY_TICKS`, `VT1200_BOARD_SWITCH`). Call `m_board.tick()` once per emulated frame. Put it in the **scanline callback**, guarded so it fires exactly once per frame — the callback is invoked once per scanline (verified: lines 168, 169, 170 …), and `scanline == screen.visible_area().max_y` is the last line of the frame. Do **not** use `screen_update`: it is called with small clip regions and a guard there fired only once in an 80-frame run.
```cpp
// in scanline(), at the end:
if (scanline == screen.visible_area().max_y)
m_board.tick();
```
In `harness/mame/build.sh`: add the new source to the symlink list and to `SOURCES=` (comma-separated), and add `g++ -c vt1200_board.cpp` to the unit-test recipe.
-9
View File
@@ -1,9 +0,0 @@
#Ghidra Lock File
#Fri Oct 16 01:36:23 EEST 2026
<META>\ Supports\ File\ Channel\ Locking=Channel Lock
Hostname=sid
OS\ Architecture=amd64
OS\ Name=Linux
OS\ Version=7.2.4-arch1-2
Timestamp=10/16/26, 1\:36\u202FAM
Username=arti
View File
Whitespace-only changes.
-56
View File
@@ -1,56 +0,0 @@
# kind addr pc value (bit addresses; distinct (addr,pc) only)
W 0640000D pc=3F2000B0 val=0000
R 0640000F pc=3F200100 val=0000
R 0640000E pc=3F200150 val=0000
W 0620000D pc=3F200190 val=0000
W 0620000F pc=3F2001E0 val=0004
R 0640000F pc=3F200250 val=00FF
R 0640000D pc=3F200380 val=0070
R 0640000D pc=3F200A20 val=0070
R 0640000D pc=3F202650 val=0070
W 05900000 pc=3FDDCAE0 val=0000
W 05800000 pc=3FDDCB20 val=0004
R 0640000D pc=3F2045A0 val=0070
W 0620000D pc=3F2052C0 val=0000
W 0620000E pc=3F205310 val=00FF
W 0620000F pc=3F205370 val=0004
R 0640000E pc=3F2042D0 val=000F
R 0640000D pc=3F204300 val=0070
W 0640000D pc=3FDF1150 val=0000
W 0640000F pc=3FDF1190 val=0001
R 06200001 pc=3FDF3900 val=0001
W 06200003 pc=3FDF3AD0 val=0011
W 06200003 pc=3FDF3BE0 val=008C
R 0640000D pc=3FDF7DE0 val=0070
W 06200002 pc=3FA91260 val=00CA
W 06200002 pc=3FA91300 val=002A
W 06200002 pc=3FA913B0 val=003A
W 06200002 pc=3FA91460 val=004A
W 06200002 pc=3FA91500 val=005A
W 06200002 pc=3FA915A0 val=001A
W 0620000A pc=3FA91650 val=00CA
W 0620000A pc=3FA916F0 val=002A
W 0620000A pc=3FA917A0 val=003A
W 0620000A pc=3FA91850 val=004A
W 0620000A pc=3FA91900 val=005A
W 0620000A pc=3FA919A0 val=001A
W 06200000 pc=3FA91A30 val=0013
W 06200000 pc=3FA91AC0 val=0007
W 06200001 pc=3FA91B70 val=0099
W 06200002 pc=3FA91C70 val=0005
W 06200008 pc=3FA91D10 val=0007
W 06200008 pc=3FA91DB0 val=0007
W 06200009 pc=3FA91E60 val=0099
W 0620000A pc=3FA91F40 val=0005
W 06200005 pc=3FA91FE0 val=0000
R 06200001 pc=3FDCE670 val=0099
R 06200003 pc=3FDCE700 val=008C
R 06200001 pc=3FDCE820 val=0099
W 06200003 pc=3FDCE8D0 val=00E1
R 06200001 pc=3FDCE910 val=0099
R 06200003 pc=3FDCE970 val=00E1
R 06200001 pc=3FDCEA90 val=0099
W 0620000D pc=3FDF1B40 val=0000
W 0620000E pc=3FDF1B80 val=000C
R 06200001 pc=3FDCF420 val=0099
R 06200003 pc=3FDCF560 val=00E1
+89
View File
@@ -0,0 +1,89 @@
# VT1200 firmware — address-space map (spike, 2026-10-16)
What external memory/register space the v2.2 firmware actually touches, derived by
sweeping every scalar operand in the disassembled image plus the raw ROM images, and
cross-checked against the MAME harness.
## Conventions (read this first)
* The TMS34010 is **bit-addressed**. The firmware stores **bit addresses**.
A physical **byte** address is `bit >> 3`; **Ghidra** byte address = `0x07E40000 + file_offset`.
* This document gives **bit addresses** (the value the firmware actually stores) and,
in parentheses, the **byte** address (`bit>>3`).
* "harness unit" (the MAME driver's `BOARD_BASE` and the access-log address) = `bit >> 4`
= 2 bytes per unit. The four known windows are written `0x5800000` (bit) here, which is
the driver's `0x5800000` too (leading-zero identical) — but the **log** prints them as
`0x0580000D` style (`bit>>4`). Do not mix the two.
* Evidence codes: **CONST** = scalar-operand count from the Ghidra sweep (96,801
instructions / 1,177 distinct `@`-targets); **XREF** = string/reference cross-check;
**LOG** = `harness/mame/board-4w.log` / `board-access.log`; **SG** = service guide.
* "Driver?" = does `harness/mame/vt1200.cpp` currently map it.
## Region table
| # | bit range | byte range | what | evidence | driver? | conf. |
|---|---|---|---|---|---|---|
| 1 | `0x0000000`–`0x2000000` | `0x000000`–`0x400000` | **Main RAM** 4 MiB | mem-test at `0x07EDFF22` walks SIMM regions at bit `0x800000`/`0x1000000`… (byte 1 MiB/2 MiB); ~5 000 absolute globals; POST clears RAM; SG: 1 MiB onboard + 3×1 MiB SIMM | yes (bit `0`–`0x1FFFFFF`) | **HIGH** |
| 2 | `0xC0000000`–`0xC00001FF` | (on-chip) | **CPU on-chip registers** (DPYCTL/DPYSTRT/DPYADR/CONTROL/…) | datasheet + `MEMORY_MAP.md`; 72 absolute operands | internal | **HIGH** |
| 3 | `0x5000000` | `0xA00000` | **Memory-config / SIMM-presence input port.** bits 0,1,2 = "SIMM 1/2/3 installed" | CONST 3 `@` reads; XREF: `0x07E58FB2`/`0x07E58FCE`/`0x07E58FEA` read bits 0/1/2 then print `Not Present`/`SIMM n installed` (strings @ file `0x0199BD`…); also read at `0x07EDFF22` | **no** | **HIGH** |
| 4 | `0x5600000` | `0xAC0000` | **Unidentified board register block** — most-touched unmodelled region. Offsets `+0x00 +0x10 +0x20 +0x30 +0x80 +0x100 +0x200 +0x380` | CONST **110** `@` accesses (2nd only to RAM/the known windows); writer at `0x07E6CB62`, adjacent to X-server strings (`no screens found`) | **no** | **HIGH** region / **LOW** identity |
| 5 | `0x5800000` | `0xB00000` | **DMA/board data port** | CONST 10 `@`; LOG; paired with #6; firmware `>>3`s a bit address into it (byte-addressed device) | yes | **HIGH** |
| 6 | `0x5900000` | `0xB20000` | **DMA/board command port** | CONST 6 `@`; LOG (commands 0,1,2,4,0x42) | yes | **HIGH** |
| 7 | `0x6000000` | `0xC00000` | **Candidate NVRAM.** ~2 KiB user-settings copy writes here; sits in a 256 KiB device slot between #6 and #8 | CONST 2 (`0x07E957F4`, `0x07E95974` push it as the destination of a settings copy/metadata routine `0x07E966D0`); XREF: adjacent `Old user settings layout.` / `User settings invalid.` | **no** | **MEDIUM-LOW** |
| 8 | `0x6200000` | `0xC40000` | **Board window** (STATUS `+0x10`, CMD `+0x20`, config `+0xD0`) | CONST 26 `@`; LOG; `BRINGUP_LOG.md` | yes | **HIGH** |
| 9 | `0x6400000` | `0xC80000` | **Board window** incl. monitor-selection switch (bits 4–6 of `+0xD0`) | CONST 24 `@`; LOG; `BRINGUP_LOG.md` | yes | **HIGH** |
| 10 | `0x6800000` | `0xD00000` | **Ethernet MAC-address ROM** | CONST 2 (`0x07E46112`); the 6-iteration byte-read loop `0x07E4611E`–`0x07E4613A` copies 6 bytes (a MAC) from this base; SG level-1 "Ethernet address ROM test" | **no** | **HIGH** |
| 11 | `0x4000000` | `0x800000` | **VRAM / framebuffer — candidate only** | `MOVI 0x4000000,B4` at `0x07E40AB0` in the reset-bank video init (`video_regs_init`); the `B` file holds bitmap bases | **no** | **LOW** |
### Notes on rows 3–7 (the peripheral map is regular)
The byte addresses `0xA00000`, `0xAC0000`, `0xB00000`, `0xB20000`, `0xC00000`,
`0xC40000`, `0xC80000`, `0xD00000` look like a decoded device map with a ~256 KiB
slot at the top end (`0xC00000`, `0xC40000`, `0xC80000`, `0xD00000` are exactly
`0x40000` apart). That regularity is *circumstantial* evidence for rows 7 and 10.
## What was ruled out (candidates that are NOT regions)
These appear constantly as large 32-bit constants but are **not** addresses:
| value (bit) | file offsets | why it is not an address |
|---|---|---|
| `0x112A880`, `0x2DC6C0`, `0x5B8D80`, `0x927C0`, `0x281F90`, `0x3600400`, `0x4000500` | reset/POST bank | `DSJS` delay-loop counters (gate 2 in `BRINGUP_LOG.md`) and per-monitor display-format constants selected by the monitor switch (`0x07E4089E`–`0x07E4090A`) |
| `0x800000`, `0x1000000` | `0x07EDFF2C`… | **RAM region boundaries** used by the SIMM memory test (byte 1 MiB / 2 MiB), not devices |
| `0x4000000` (all but one) | 49 aligned hits | bit-26 mask OR/AND, not an address |
| byte `0x600000`–`0x7E40000` "buckets" | whole image | code bytes / data tables. A naive raw scan of every 32-bit word is ~25 % false positives. The `0x5000000`/`0x6000000` "cluster" in bank 6 is **unaligned byte noise** inside sparse tables — re-scanning 16-bit-aligned collapses it. |
## What remains unknown (stated plainly)
1. **Exact VRAM base and size.** The framebuffer is *not* accessed by any absolute operand
(the `@`-sweep finds it nowhere), so it is addressed indirectly — via the `B`-register
file and/or the `DPYADR` (`0xC00001E0`) register, both set at runtime from a RAM screen
descriptor. Row 11 is the only static hint and is **weak**. It is also possible the
video DRAM sits *behind* the `0x5800000`/`0x5900000` DMA pair rather than being CPU-visible.
2. **Identity of row 4 (`0x5600000`).** Heavy, display-adjacent, but I could not name the device.
3. **NVRAM extent / exact base** (row 7), and whether the MAC ROM (row 10) is 16-bit-wide
(the read loop advances 2 bytes per MAC byte).
4. **Extent of each I/O block** — only point accesses are observed, so sizes are guessed from slot spacing.
## How to reproduce
```
# operand sweep (Ghidra, session required):
# iterate listing.getInstructions(True); for each Scalar operand >= 0x10000 and < 0x40000000,
# bucket by (value>>3)>>16. Filter to "@0x<value>" operands for true memory accesses.
python3 tools/ptr_constants.py vt1200_v22.bin # ROM-pointer subset
# raw aligned scan: 32-bit LE words whose (value>>3) lands in the region of interest
```
## Durable Ghidra annotations added (project `ghidra/vt1200`, program `vt1200_v22.bin`)
* Memory blocks (with comments) created at each region byte base:
`VRAM_800000_CAND`, `IO_50_SIMM_MEMCFG`, `IO_56_BOARD_REG`, `IO_58_DMA_DATA`,
`IO_59_DMA_CMD`, `IO_60_NVRAM_CAND`, `IO_62_WIN2`, `IO_64_WIN3`, `IO_68_MACROM`.
* Functions created/named: `video_regs_init`, `io5600000_screen_init`,
`nvr_user_settings_validate`, `io_settings_copy_expand`, `io_settings_copy_linear`,
`io_settings_restore`, `io5800_5900_init`, `io5800_status_read`,
`keyboard_mouse_irq_handler`, `led_control_1/2`.
* PRE comments at the key access sites (MAC read, SIMM read, `0x5600000` write,
settings copy, SIMM mem-test, video init, `B4=0x4000000`).
* Program saved. Function count 8 → 19; memory blocks 1 → 10.