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:
co-authored by
Claude Opus 5
parent
66e7b84272
commit
023362b05a
@@ -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"
|
||||
Reference in New Issue
Block a user