From 213083f2e09fd8108b53153c6dad3b80857fc7c3 Mon Sep 17 00:00:00 2001 From: "opencode.energia.arti.ee" Date: Fri, 30 Oct 2026 22:52:46 +0000 Subject: [PATCH] plan: task 4 verified by host unit tests (the driver has no network interface) --- ...-vt1200-stream-transport-and-row-strips.md | 58 ++++++++++++++----- 1 file changed, 43 insertions(+), 15 deletions(-) diff --git a/docs/superpowers/plans/2026-10-30-vt1200-stream-transport-and-row-strips.md b/docs/superpowers/plans/2026-10-30-vt1200-stream-transport-and-row-strips.md index 0a7dd16..13b1206 100644 --- a/docs/superpowers/plans/2026-10-30-vt1200-stream-transport-and-row-strips.md +++ b/docs/superpowers/plans/2026-10-30-vt1200-stream-transport-and-row-strips.md @@ -215,38 +215,66 @@ git commit -m "feat(stream): payload skeleton with one startup malloc" --- -### Task 4: Two-slot ring with header validation +### Task 4: Frame parser and two-slot handling **Files:** -- Modify: `harness/udpstream/vidstream.c` -- Test: `harness/mame/vidstream.lua` (mode `rx`) +- Create: `harness/udpstream/frame_parse.c`, `harness/udpstream/frame_parse.h` +- Create: `harness/udpstream/tests/test_frame_parse.c` +- Modify: `harness/udpstream/vidstream.c`, `harness/mame/vidstream.lua` **Interfaces:** -- Produces: in-guest counters `RX_OK` (`0x01810030`), `RX_BAD` (`0x01810034`), `RX_LAST_LEN` (`0x01810038`), `RX_SLOT` (`0x0181003C`). +- `int fp_parse(const unsigned char *buf, unsigned int len, fp_header *out)` — returns 1 for a + valid frame, 0 otherwise; fills `kind, frame_no, rows, stretch, payload_len, payload_off`. +- In-guest counters `RX_OK`, `RX_BAD`, `RX_LAST_LEN`, `RX_SLOT` at the byte-aligned marker page. -- [ ] **Step 1: Write the failing test** +**Note (plan amendment, ruling R11):** the MAME driver does **not** attach the LANCE to a host +network interface, so no test can hand it Ethernet frames in the emulator. Verification is +therefore two-part: (1) `fp_parse` is a plain C function compiled and unit-tested on the host +(`gcc -std=c89`), which pins the length/CRC rules; (2) the Lua harness injects a frame directly +into a slot and asserts the payload's counters. The real DMA path is proven in Task 7, on the unit. -In `harness/mame/vidstream.lua` mode `rx`: send one valid frame (80 rows, `S=12`) and one frame whose CRC byte is flipped, via `vidsend.py --fake`. Assert `RX_OK == 1` and `RX_BAD == 1`. +- [ ] **Step 1: Write the failing host test** -- [ ] **Step 2: Run to verify it fails** +`tests/test_frame_parse.c`: build a 16-byte header + payload with the same layout `frame.py` +writes (magic 'V','S', version 1, kind 1, frame_no, payload_len, rows, stretch, CRC16 at offset +12 over bytes 0..11 + payload). Assert `fp_parse` accepts it; flip one payload byte and assert it +is rejected; truncate it below `16 + payload_len` and assert rejection; corrupt the magic and the +version and assert rejection. -Run: `VT1200_MODE=rx harness/mame/run-vidstream.sh` -Expected: `RX_OK=0 RX_BAD=0 -> FAIL` (nothing parses yet) +- [ ] **Step 2: Run it to verify it fails** -- [ ] **Step 3: Implement slot receive + validation** +Run: `cc -std=c89 -Wall -o /tmp/tfp harness/udpstream/tests/test_frame_parse.c harness/udpstream/frame_parse.c` +Expected: link error, `fp_parse` undefined. -Ring of 16 descriptors, two slots of 24 KB at `POOL_PTR` and `POOL_PTR + 24576`; arm 16 descriptors per slot on entry to that slot; on completion compute `bytes = SUM(len)`; accept only if `bytes >= 16`, `magic == 'VS'`, `payload_len + 16 <= bytes`, and `crc16(header[0:12] + payload) == header_crc`. Reject → `RX_BAD++`, re-arm the same slot, no blit. +- [ ] **Step 3: Implement `frame_parse.c` / `.h`** -- [ ] **Step 4: Run to verify it passes** +K&R-compatible C89 that also compiles with the 1987 compiler: no `//`, no declarations after +statements, CRC16 CCITT-FALSE as in `frame.py`. `fp_parse` checks length first, then magic and +version, then CRC over `buf[0..11] + payload`. + +- [ ] **Step 4: Run the host test to verify it passes** + +Run: `cc -std=c89 -Wall -o /tmp/tfp harness/udpstream/tests/test_frame_parse.c harness/udpstream/frame_parse.c && /tmp/tfp` +Expected: `frame_parse: N/N ok`. + +- [ ] **Step 5: Wire it into the payload and the MAME harness** + +`vidstream.c` calls `fp_parse` on each completed slot, increments `RX_OK`/`RX_BAD`, and does not +blit on rejection. `vidstream.lua` mode `rx` writes a valid frame into slot A and a corrupted one +into slot B, sets the payload's "frame ready" word for each, and asserts `RX_OK == 1 && RX_BAD == 1`. + +- [ ] **Step 6: Run the MAME check** Run: `VT1200_MODE=rx harness/mame/run-vidstream.sh` Expected: `RX_OK=1 RX_BAD=1 -> PASS` -- [ ] **Step 5: Commit** +- [ ] **Step 7: Commit** ```bash -git add harness/udpstream/vidstream.c harness/mame/vidstream.lua -git commit -m "feat(stream): two-slot rx ring with header and crc validation" +git add harness/udpstream/frame_parse.c harness/udpstream/frame_parse.h \ + harness/udpstream/tests/test_frame_parse.c \ + harness/udpstream/vidstream.c harness/mame/vidstream.lua +git commit -m "feat(stream): frame parser shared by host tests and payload" ``` ---