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
+145
View File
@@ -0,0 +1,145 @@
; The screen nobody is looking at.
;
; The screen brings two map banks and shows one of them. Everything this program draws goes
; into the other, so the picture does not change at all while it is being built - and then
; one byte out of one port shows the whole of it at once.
;
; ---- Why that is worth a port ----
;
; A screen drawn where it can be seen is seen half drawn. A game 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. The machines this one is pretending to
; be had the same problem and solved it the same way, except that they had to catch the few
; lines between one frame and the next to do the swap in. Here a frame is drawn from one bank
; in one go, so a flip cannot land halfway through one and there is nothing to race.
;
; ---- What it costs ----
;
; A whole bank, which is 64K of somebody's memory - and nothing, which is the point. The
; second screen is memory the device brought, the same as the first, so a program that wants
; it registers it and a program that does not never pays for it.
;
; Written by Anachronaut
#Include services.asm
#Program
#Base 0x5000
start:
; ---- The two banks this touches ----
;
; Four is the atlas, where the tiles are. Six is the other screen: three is the disk's and
; four and five are the ones the system registers to save a screen with, so six is the
; first number free. Nothing hands these out - see the table in the CosmOS README.
INIA 0d4
OUTA 0xE3
INIA 0x30
OUTA 0xE2
INIA 0x03
OUTA 0xE8
INIA 0d6
OUTA 0xE3
INIA 0x3B
OUTA 0xE2
INIA 0x03
OUTA 0xE8
; The screen back afterwards, because the tile overwritten below is one the shell spells
; with. Refused is survivable and is not checked: there is nothing this could do about it,
; and the system puts the font back at exit whether or not it saved anything.
SWI osTakeScreen
SETD.0 Message
SWI osPrintString
; Key mode, so a key arrives when it is pressed rather than when Return is.
INIA 0x01
OUTA 0x02
; ---- Tile one, made solid ----
;
; Sixty four pixels of index one, FILLED rather than blitted, which is why this program
; carries no picture of its own.
INIA 0d4
OUTA 0xE3
RSTA
OUTA 0xE4
INIA 0x40
OUTA 0xE5 ; Tile one begins at sixty four.
INIA 0x01
OUTA 0xE2 ; Fill takes the byte it writes from SourceLow.
RSTA
OUTA 0xE6
INIA 0x40
OUTA 0xE7 ; Sixty four bytes of it.
INIA 0x02
OUTA 0xE8
; ---- And every cell of the other screen ----
;
; One byte fills both halves of a cell, so this is tile one and attribute one everywhere:
; the tile is index one at every pixel and the attribute adds sixteen to all of them, which
; comes out as a screen solidly in scheme one's ink.
INIA 0d6
OUTA 0xE3
INIA 0x40
OUTA 0xE4
RSTA
OUTA 0xE5
INIA 0x01
OUTA 0xE2
INIA 0x80
OUTA 0xE6
RSTA
OUTA 0xE7 ; The whole map, which is 0x8000 bytes.
INIA 0x02
OUTA 0xE8
; NOTHING HAS CHANGED ON THE SCREEN. Every byte of that went where nobody can see it, and
; the line printed above is still sitting there to prove it - which is the reason this
; waits here rather than flipping straight away. What a back buffer is for is not visible
; in the flip; it is visible in the time before one.
CALL waitKey
; And this is the whole of showing it.
INIA 0x01
OUTA 0x3C
CALL waitKey
; ---- Which screen is showing is NOT put back here ----
;
; On purpose, and it is the one thing in this program worth arguing about. The system
; restores it at exit, the same way it restores the cursor and the ink, and for the same
; reason: a program that FAULTED while flipped could not have put it back, and a shell that
; only came out right for programs which remembered would be a shell that came out wrong
; the day one crashed. What the person is looking at belongs to the system.
;
; The console mode below IS put back, because that is this program's own borrowing rather
; than something the system hands out.
RSTA
OUTA 0x02 ; Line mode again.
SWI osExit
; ---- A key, asked for rather than waited on ----
;
; The console holds one until somebody wants it, so nothing pressed while the map was being
; filled is lost - it is sitting there and this returns immediately, which is right. A key
; pressed is a key meant for this program.
waitKey:
INA 0x01
INIB 0x01 ; READY
AND
BRQ waitKey
INA 0x00 ; Taken, so the shell is not handed a key meant for this.
RET
#Data
#Base 0x3000
Message:
"A whole screen is about to be drawn where you cannot see it - this line will still\nbe here when it is done. Press a key to show it, and another to come back.\n"
+10 -1
View File
@@ -725,6 +725,7 @@ from every assembly file in it. Several are old programs written for the bare ma
| Files | Writes a file, reads it back, renames it and deletes it, in 675 bytes, including nothing but the service names. It is what says a program does not need a filesystem inside it. |
| Break | Stops itself twice with SWI osBreak, so that the registers can be seen changing between one stop and the next. |
| Grid | The first program to use the screen as a screen. Redefines a tile above the font, fills all 128 map rows, and scrolls it diagonally a pixel at a time. |
| Flip | Draws a whole screen into the bank that is not being shown, waits, and then shows it in one byte out of one port. It deliberately does not put the displayed screen back, because that is the system's to restore - a program that faulted while flipped could not have. |
| Edit | A line editor. |
| Stream | Reads an 84,000 byte file through a buffer of 256, which is what says a file bigger than Data Memory can be read at all. |
| Type | Prints a named text file a block at a time, including one too large to fit in Data Memory. |
@@ -1199,7 +1200,15 @@ before quietly answers to nothing.
| 1 | Data Memory. The machine's. |
| 2 | The bank table. The machine's. |
| 3 | The disk's buffer, given at mount by `sbfsMount`. CosmOS needs it for as long as it is running. |
| 4 and up | Free for a program to use. |
| 4 | The screen's atlas - its tiles and palette - while `osTakeScreen` is saving or restoring. |
| 5 | The screen's map, for the same. |
| 6 and up | Free for a program to use. |
4 and 5 are only registered while a screen is being saved or given back, so a program is free
to point them somewhere else in between - but a program that takes the screen will find them
pointing at the screen again afterwards, so there is nothing to be gained by it. `Grid` uses
them for exactly what CosmOS uses them for. `Flip` wants a third bank, the screen nobody is
looking at, and takes 6.
`Grid` learned this the hard way and is the reason the table is here. It asked for 3, took the
disk's buffer, and every read the filesystem made afterwards came out of video memory - so the
+19 -2
View File
@@ -5123,6 +5123,19 @@ screenSane:
RSTA
OUTA 0x37
OUTA 0x38 ; No fraction of a cell in either direction.
OUTA 0x3C ; And the screen everybody else's map is in.
; ---- Which of the two screens is being shown ----
;
; A program that draws into the back buffer and flips is showing screen one, and the shell
; knows nothing about that. Its own scrollback, its prompt and every line the person typed
; are in screen NOUGHT, so a program that exited while flipped would hand back a shell
; drawing correctly onto a screen nobody had ever written to - blank, and looking for all
; the world like the machine had lost everything.
;
; Put back rather than left, by the same rule as the cursor and the ink in handleExit: a
; program that stopped early is not around to put anything back, and the shell owns what
; the person is looking at.
; ---- And glyphs and colours that can be read ----
;
@@ -5139,8 +5152,12 @@ screenSane:
OUTA 0x39
RET
; Video memory as bank 4, which is what makes it reachable at all. Bank 3 is the disk's; see
; the table in the CosmOS README, which exists because a program once took 3.
; Video memory as banks 4 and 5, which is what makes it reachable at all. Bank 3 is the
; disk's; see the table in the CosmOS README, which exists because a program once took 3.
;
; The BACK BUFFER is not given a number here. The system saves and restores what is on the
; screen, and what is on the screen is screen nought - a program that wants the other one
; registers it itself, the same as any program wanting memory nobody else is using.
screenBank:
INIA 0d4
OUTA 0xE3