A second screen, and one port to say which is shown

A screen drawn where it can be seen is seen half drawn. A program that
moves forty things and rewrites the map underneath them is wrong for as
long as it takes to put them all right, and at a megahertz that is long
enough to look at.

So the device brings a second screen bank, on port 0x3B, and port 0x3C
says which of the two is displayed. Everything a program draws into the
other one is invisible until one byte shows the whole of it at once.

ONE REGISTER IS ENOUGH, where the hardware this imitates needed two. The
other said which screen the CPU's window pointed at; there is no window
here, because a program reaches a bank through the memory controller by
its number. Writing to the screen that is not shown is a matter of naming
its bank, and the device never has to be told.

And a flip cannot tear: a frame is drawn from one bank in one go, so a
flip either happened before that frame or happens before the next. There
is nothing to race, where the real machines had to catch the few lines
between frames to swap in.

The console draws into whichever screen is displayed rather than one of
its own, so a fault message lands where somebody can read it even if a
game had flipped. And CosmOS puts the displayed screen back at exit, the
way it already puts back the cursor and the ink: a program that faulted
while flipped could not have, and a shell that only came out right for
programs which remembered would come out wrong the day one crashed.

Flip.asm is the worked example. It deliberately does NOT restore the
display itself - that is the point of the paragraph above, and it is what
makes the system's guarantee the thing under test rather than the
program's good manners. Written the other way round first, where it
passed with the guarantee deleted.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01E2JrLzFvuFX9fgi1LDRjrW
This commit is contained in:
Anachronaut
2026-09-02 10:31:29 -04:00
co-authored by Claude Opus 5
parent 66e7b84272
commit 023362b05a
17 changed files with 399 additions and 37 deletions
+22 -3
View File
@@ -628,6 +628,8 @@ Two rather than one because the two halves of a screen are written at completely
| Screen | 0x4000 - 0xBFFF | The map. 128 rows of 256 bytes. |
| Screen | 0x0000 - 0xF9FF | In bitmap mode, the picture instead: 64,000 bytes, one to a pixel. |
**There are two screen banks and one atlas**, laid out identically, and the device shows one screen at a time. See Two Screens below.
**The bitmap is the same memory as the map**, which is what shared video memory has always been. Going to bitmap mode does not clear the text screen - it stops calling it one, and coming back finds the map holding whatever the picture put there.
**What a picture no longer costs is the font.** The tiles and the palette are in the other bank, where a bitmap cannot reach them, so a program can draw a picture and then put readable text back on the screen without asking the character generator for its glyphs again. While the two shared a bank, drawing anything destroyed them.
@@ -643,9 +645,24 @@ A bank is registered by naming the port that owns it, so a device with two banks
| Port | Owns |
| --- | --- |
| 0x30 | The atlas. |
| 0x3A | The screen. |
| 0x3A | Screen 0. |
| 0x3B | Screen 1. |
Nothing is read or written at 0x3A - it is a name for a bank, and the bus registry is where a program finds out it brings one. Asking the registry about the block gives an honest answer: those two ports say they bring memory and the other fourteen say they do not.
Nothing is read or written at 0x3A or 0x3B - they are names for banks, and the bus registry is where a program finds out they bring one. Asking the registry about the block gives an honest answer: those three ports say they bring memory and the other thirteen say they do not.
### Two Screens:
There are two screen banks and the device shows one of them. **Port 0x3C says which**, 0 or 1, and reads back what it was told; a screen that does not exist is not taken, the same as a mode that does not exist.
That is a **back buffer**: a whole screen's worth of map written where nobody can see it, and then shown all at once. A screen drawn where it can be seen is seen half drawn, and a program that moves forty things and rewrites the map underneath them is wrong for as long as it takes to put them all right - which at a megahertz is long enough to look at.
**One register is enough, where real hardware needed two.** The other said which screen the CPU's window pointed at. There is no window here: a program reaches a bank through the memory controller by its number, so writing to the screen that is not being shown is a matter of naming its bank, and the device never has to be told.
**A flip cannot tear.** A frame is drawn from one bank in one go, so a flip either happened before that frame or it happens before the next one; there is no state of having flipped halfway. The machines this one imitates had to catch the few lines between one frame and the next to do the swap in.
**The console draws into whichever screen is displayed**, rather than into one of its own. A game that flipped and then faulted needs the message to land where somebody can read it, and the console has no way of knowing that happened.
What a second screen costs is a whole bank of somebody's memory, and nothing else: it is memory the device brought, so a program that wants it registers it and a program that does not never pays for it. `Programs/CosmOS/Apps/Flip.asm` is the shortest thing to read that uses one.
The base port owns the atlas because tiles have been at 0x0000 since there was a screen at all. `Programs/Examples/picture.asm` registers both, and is the shortest thing to read that does.
@@ -677,7 +694,9 @@ The high nibble is reserved and should be left at zero, so that a meaning can be
| 0x37 | Fine X. How many pixels into that column the screen begins, 0 to 7. |
| 0x38 | Fine Y. How many pixels into that row the screen begins, 0 to 7. |
| 0x39 | Command. Bit 0 copies the font back, bit 1 the sixteen colour schemes. |
| 0x3A | Owns the screen bank. Not read or written. |
| 0x3A | Owns screen 0. Not read or written. |
| 0x3B | Owns screen 1. Not read or written. |
| 0x3C | Display. Which of the two screens is being shown. |
| Mode | Screen | Cells |
| --- | --- | --- |