Give the Voyager a screen
A tile engine on ports 0x30 to 0x3F, bringing one bank of video memory registered the way the disk's buffer is. The CPU writes cell indices and the device turns them into pixels, which is the whole reason a screen is affordable at a megahertz: a frame is 16,667 cycles, a full 320 by 200 picture is 64,000 bytes, and a 40 by 25 map is 2,000. A program that changes two cells writes four bytes. The cost of a screen becomes the number of cells that changed rather than the number of pixels on it. Which makes colour depth free, so the tiles are eight bits: an 8 by 8 cell is 64 pixels and each picks independently out of 256 colours, with no per-cell limit of the kind that made a Spectrum two and C64 multicolour four. The low nibble of a cell's attribute is ADDED to every index in its tile, sixteen at a time, so a tile drawn in 0 to 15 appears in any of sixteen schemes without a second copy in tile memory - and a tile wanting all 256 leaves the nibble at zero and gets them. Neither use costs the other anything. Two decisions are arithmetic rather than taste, and both come from the machine having no multiply. A map row is a page whether the mode fills it or not, so a cell address is the row number as the high byte and the doubled column as the low byte with no arithmetic at all; otherwise every cursor move on a 40 column screen would cost a row-times-40 in software. And a palette entry is four bytes rather than three, so entry n is at n times four, a shift. THE MAP IS A RING and the Scroll register says which of its 128 rows is on top. Scrolling moves a register and no memory: blitting a 40 by 25 screen up one line is 1,920 bytes inside one bank, which is twelve percent of a frame even with the controller widened, and a program printing one page would spend six frames shuffling memory. It is now one port write - and the rows that scrolled off are still there, which is where a terminal gets scrollback it never had. The device is part of the machine rather than part of the window. It renders into a buffer that is a pure function of video memory, so the same program draws the same picture with nobody watching; Voyager puts that buffer on the glass and decides nothing. Both binaries take --screen, which saves a PPM when the machine stops, and that is what makes a screen checkable on a host with no display at all. Tests/video.sh checks fourteen named behaviours rather than comparing a recorded image, because a recorded image would say "something changed" and leave which of the palette, the tile, the attribute, the map or the scroll register broke to be found by hand. Verified by breaking three things in turn: the additive nibble failed exactly one check, the scroll origin exactly two, and moving every cell one pixel sideways exactly the four about placement. Tests/docs.sh could not count past nine, which is how a suite of ten scripts reported itself as wrong for the wrong reason. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01E2JrLzFvuFX9fgi1LDRjrW
This commit is contained in:
co-authored by
Claude Opus 5
parent
e3ef25e3b3
commit
83623a3df3
+20
-1
@@ -9,7 +9,7 @@ believe them.
|
||||
|
||||
## What The Suite Claims:
|
||||
|
||||
The suite is not one thing. It is nine scripts making five different kinds of claim, and
|
||||
The suite is not one thing. It is ten scripts making five different kinds of claim, and
|
||||
knowing which claim you are relying on is the whole point of this document. A recorded
|
||||
transcript and a byte-for-byte comparison against a second implementation both print
|
||||
`[ok ]`, and they are worth wildly different amounts.
|
||||
@@ -57,6 +57,7 @@ Individual scripts can be run on their own, from anywhere:
|
||||
./Tests/voyager.sh The same manifest, through the other front end.
|
||||
./Tests/disk.sh The disk tool against the format.
|
||||
./Tests/cycles.sh What the memory controller charges.
|
||||
./Tests/video.sh What the video device draws.
|
||||
./Tests/terminal.sh The things a recorded file cannot see.
|
||||
./Tests/native.sh The two assemblers against each other.
|
||||
./Tests/agree.sh The two filesystems against each other.
|
||||
@@ -143,6 +144,24 @@ then asks for the things the format says cannot happen and requires them to be r
|
||||
rather than half done. Roughly half of its checks are `refuses`, which is the shape
|
||||
worth copying: **a tool that never says no is not finished.**
|
||||
|
||||
`Tests/video.sh` belongs here too, and exists for the same reason as the two above: the
|
||||
suite has no display, and a screen nothing can look at is a screen nothing checks. The
|
||||
device renders into a buffer that is a pure function of video memory, and the machine can be
|
||||
asked to save it with `--screen`, so every check runs a program, saves the picture and reads
|
||||
pixels back out of it. No window, no display server, and the same answer every time.
|
||||
|
||||
**It checks named behaviours rather than a recorded image**, which for a screen matters more
|
||||
than usual. A recorded image would say "something changed" and leave which of the palette,
|
||||
the tile, the attribute, the map or the scroll register broke to be found by hand. Instead
|
||||
each check is one claim: that a tile lands where it is put and stops at the cell edge, that
|
||||
the palette is what colours it, that the attribute nibble adds sixteen, that scrolling moves
|
||||
which row is on top, that the map wraps, and that an impossible mode is refused without
|
||||
stopping the machine.
|
||||
|
||||
Breaking the additive nibble fails exactly one check. Breaking the scroll origin fails
|
||||
exactly two. Moving every cell one pixel sideways fails the four about placement. That is
|
||||
what a screen test is supposed to do.
|
||||
|
||||
`lint.sh` builds a fixture in which every line trips exactly one rule, and checks which
|
||||
warning came out at which line. It used to compare a total, and a total is a number that
|
||||
stays right while the thing behind it goes wrong: a change that stopped one rule firing and
|
||||
|
||||
Reference in New Issue
Block a user