Two bugs, both in what the demo claimed rather than in the device. The assembler has no string escapes, so the "\n" written in a literal printed as a backslash and an n. A newline is a byte; Say.asm has always written one as 0x0A 0x00 and this now writes it out of the console port. And the line whose whole job was to still be there afterwards was wiped out on the way back, because the program called osTakeScreen - which restores the screen AS IT WAS BEFORE, so the tidy-up erased the one thing the demo was pointing at. It did not need saving: nothing it touches is the shell's. A program that damages nothing should not ask, and asking anyway costs it the screen it was standing on. Which turned out to be untrue as written, and that is the third thing. Flip drew with a tile of its own, and the system copies the font back over every tile at exit - so the filled screen went blank the moment the program left, and the check that the system put the display back could not tell a restored screen from an abandoned one. It passed with the restore deleted. So did the check that a program can show the other screen at all: a blank screen counts as one colour just as well as a filled one does. Now it fills with 0x0A, which is an asterisk in one of the reversed colour schemes: paper is the colour and ink is black, so a whole screen is drawn with NO TILE REDEFINED and it survives leaving. Both checks ask for the commonest colour in the picture rather than counting colours or naming a pixel - the font's only blank glyph is the space, whose attribute nibble is nought, so a filled screen is always a pattern and which pixel lands on paper depends on the character. Both were re-broken afterwards and both failed this time. Also cosmosFlip, a transcript test, which is what would have caught the printed backslash in the first place. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01E2JrLzFvuFX9fgi1LDRjrW
149 lines
6.0 KiB
NASM
149 lines
6.0 KiB
NASM
; 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 one bank this touches ----
|
|
;
|
|
; Six: 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 0d6
|
|
OUTA 0xE3
|
|
INIA 0x3B
|
|
OUTA 0xE2
|
|
INIA 0x03
|
|
OUTA 0xE8
|
|
|
|
; ---- And it does NOT take the screen ----
|
|
;
|
|
; osTakeScreen saves what is on the screen and puts it back at exit, and this program
|
|
; called it at first. That was wrong in a way worth keeping written down: it saves the
|
|
; screen AS IT WAS BEFORE, so the line printed below - the line whose whole job is to still
|
|
; be there afterwards - was wiped out by the restore that was meant to be tidy.
|
|
;
|
|
; It was not needed either. NOTHING THIS TOUCHES IS THE SHELL'S: the only memory it writes
|
|
; is the map of the screen nobody is looking at, and the only register it leaves changed is
|
|
; which screen that is - which the system puts back itself.
|
|
;
|
|
; A program that wants a screen saved should ask. A program that damages nothing should
|
|
; not, and asking anyway is not free - it costs the screen it was standing on.
|
|
|
|
SETD.0 Message
|
|
SWI osPrintString
|
|
INIA 0x0A
|
|
OUTA 0x00 ; The assembler has no escapes; a newline is a byte.
|
|
|
|
; Key mode, so a key arrives when it is pressed rather than when Return is.
|
|
INIA 0x01
|
|
OUTA 0x02
|
|
|
|
; ---- Every cell of the other screen, in one command ----
|
|
;
|
|
; TEN, and the reason is worth the paragraph. Fill writes one byte, and a cell is two, so
|
|
; whatever is filled with is BOTH the tile and the attribute - there is no filling a map
|
|
; with a tile and a colour that are different numbers.
|
|
;
|
|
; Ten as a tile is an asterisk, because the font begins at the space and glyph n is
|
|
; character n plus thirty two. Ten as an attribute is one of the eight REVERSED schemes,
|
|
; whose paper is a colour and whose ink is black. So the screen comes out green, covered in
|
|
; black asterisks, without a single tile being redefined.
|
|
;
|
|
; The high nibble stays at nought, which the manual asks for: it is reserved. That is the
|
|
; real constraint on which byte this can be - it has to be under sixteen to leave the
|
|
; nibble alone, and eight or over to land on a reversed scheme whose PAPER is the colour.
|
|
;
|
|
; Which means THIS PROGRAM WRITES NOTHING BUT THE SCREEN NOBODY IS LOOKING AT. It was
|
|
; drawn with a tile of its own first, and that tile was one the system copies the font back
|
|
; over at every exit - so the screen it had filled turned blank the moment it left, and a
|
|
; check that it had been put back could not tell a restored screen from an abandoned one.
|
|
; A picture that depends on the atlas does not survive leaving.
|
|
INIA 0d6
|
|
OUTA 0xE3
|
|
INIA 0x40
|
|
OUTA 0xE4
|
|
RSTA
|
|
OUTA 0xE5
|
|
INIA 0x0A
|
|
OUTA 0xE2 ; Fill takes the byte it writes from SourceLow.
|
|
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
|
|
|
|
; One line and no newline in it. A string literal is terminated where it ends, so a second
|
|
; one after a 0x0A byte would never be reached - printing stops at the first terminator. The
|
|
; newline is written to the console directly instead.
|
|
Message:
|
|
"A screen is drawn where you cannot see it. A key shows it, another comes back."
|