Give the screen back: osTakeScreen, and the RAM disk earns its keep
A program that takes the whole screen leaves the shell a blank one, and
whatever was on it is gone. There was nowhere to put 48K of video memory on
a machine with 64K of Data Memory that CosmOS already lives in.
A DRIVE MADE OF MEMORY IS SOMEWHERE. The screen goes to a file on the
scratch drive - the first volatile drive found at boot - like any other
file, and comes back from handleExit alongside the vectors and console mode
already put back there. The filesystem does the allocating, so this
invented nothing: it is 196 pages of tiles, map and palette, with a block
on the front holding the cursor, the four scroll registers and the mode.
NOT AUTOMATIC, and that is the whole design. Saving on every program start
would be cheap enough; restoring on every exit would be wrong, because dir
and Files and Say print and stop and their output is the reason you ran
them. A program says it took the screen, and one that says nothing behaves
exactly as every program did before this existed.
It deleted thirty lines of Grid, and they were all wrong anyway: four
scroll registers put back by hand, the map filled with spaces, the cursor
sent home, palette bank 0 written out - and the other fifteen banks kept
Grid's colours, because there was nowhere to have kept the real ones. Grid
is 64 bytes smaller and gives back what was actually there.
The check compares the screen before against the screen after, CELL BY
CELL, and allows only the rows around the cursor to differ - found from
where the text ends rather than guessed at, because the first version
assumed the cursor was near the bottom of the screen and let three real
differences through.
Two things cost time and neither was the feature:
- An edit adding "SWI osTakeScreen" to Grid was in the same script as a
failing s.index, so the file was never written - and the COMMENT
describing the call did land, from a later edit. Grid documented a call
it did not make, and read as though it should have worked.
- docs.sh caught osTakeScreen having no row in the services table, which
is the check the service layer added for exactly this and the second
time it has earned itself.
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
04f1ffabd4
commit
ab72443b99
@@ -44,6 +44,14 @@ start:
|
|||||||
INIA 0x03
|
INIA 0x03
|
||||||
OUTA 0xE8 ; RegisterBank.
|
OUTA 0xE8 ; RegisterBank.
|
||||||
|
|
||||||
|
; ---- Asking for the screen back afterwards ----
|
||||||
|
;
|
||||||
|
; Everything below overwrites a tile, all sixteen colour schemes and every cell of the map,
|
||||||
|
; and none of that is this program's to keep. The system puts it somewhere and gives it back
|
||||||
|
; at exit - and if it says it cannot, this carries on anyway, because it did before there
|
||||||
|
; was anywhere to put it.
|
||||||
|
SWI osTakeScreen
|
||||||
|
|
||||||
CALL putTile
|
CALL putTile
|
||||||
CALL putPalette
|
CALL putPalette
|
||||||
CALL putMap
|
CALL putMap
|
||||||
@@ -119,74 +127,15 @@ finished:
|
|||||||
|
|
||||||
; ---- Putting the screen back ----
|
; ---- Putting the screen back ----
|
||||||
;
|
;
|
||||||
; All four scroll registers, or the shell inherits a view that begins half way into a cell.
|
; ---- What used to be here ----
|
||||||
RSTA
|
|
||||||
OUTA 0x36
|
|
||||||
OUTA 0x37
|
|
||||||
OUTA 0x38
|
|
||||||
|
|
||||||
; The row origin too, and then every cell of the map and not just the visible ones. A
|
|
||||||
; console that scrolls would otherwise walk down into rows this program filled, and find a
|
|
||||||
; grid underneath its own output.
|
|
||||||
OUTA 0x34 ; A is still nought, from the three above.
|
|
||||||
|
|
||||||
INIA 0d4
|
|
||||||
OUTA 0xE3
|
|
||||||
INIA 0x40
|
|
||||||
OUTA 0xE4
|
|
||||||
RSTA
|
|
||||||
OUTA 0xE5
|
|
||||||
OUTA 0xE2 ; The byte to write: tile 0 is the space, attribute 0 is plain.
|
|
||||||
INIA 0x80
|
|
||||||
OUTA 0xE6
|
|
||||||
RSTA
|
|
||||||
OUTA 0xE7 ; 0x8000 bytes, which is the whole map.
|
|
||||||
INIA 0x02
|
|
||||||
OUTA 0xE8 ; Fill.
|
|
||||||
|
|
||||||
; ---- And the cursor back to the top ----
|
|
||||||
;
|
;
|
||||||
; The Fill above empties the map and says nothing to the console about it, so the shell
|
; Four scroll registers put back, the whole map filled with spaces, the cursor sent home,
|
||||||
; carried on writing from wherever the cursor had been left standing when this program
|
; and palette bank 0 written out by hand - and it was STILL wrong, because the other fifteen
|
||||||
; started - part way down a screen that no longer has anything on it. Clearing is what
|
; banks kept this program's colours and there was nowhere to have put the real ones.
|
||||||
; puts a cursor home, and it costs one write.
|
|
||||||
INIA 0x01
|
|
||||||
OUTA 0x05
|
|
||||||
|
|
||||||
; ---- And the colours it woke up with ----
|
|
||||||
;
|
;
|
||||||
; Only the first pair, and that is worth being honest about. The console's own scheme is
|
; All of it is osTakeScreen's now, and it gives back what was actually there rather than
|
||||||
; sixteen banks - colours on black in 0 to 7, the same colours inverted in 8 to 15 - and
|
; what a clean machine looks like.
|
||||||
; this program wrote over all of them, because the attribute nibble lands on exactly the
|
|
||||||
; entries the console uses and there is nowhere else for it to land. Putting all thirty two
|
|
||||||
; back would mean copying the device's own table into an application, which is the kind of
|
|
||||||
; duplication that goes stale the first time somebody picks a nicer green.
|
|
||||||
;
|
|
||||||
; So it restores bank 0, grey on black, which is what plain text has always been and what
|
|
||||||
; the shell will be using when it gets the machine back. The other fifteen keep this
|
|
||||||
; program's colours until something else writes them, which is visible only to a program
|
|
||||||
; that sets the console's attribute port.
|
|
||||||
;
|
|
||||||
; THE REAL ANSWER IS A COMMAND TO THE SCREEN saying "give me back what you woke up with",
|
|
||||||
; the same way the console has one for clearing. There is not one, and this program is the
|
|
||||||
; first thing that ever wanted it.
|
|
||||||
INIA 0d4
|
|
||||||
OUTA 0xE3
|
|
||||||
INIA 0xFC
|
|
||||||
OUTA 0xE4
|
|
||||||
RSTA
|
RSTA
|
||||||
OUTA 0xE5
|
|
||||||
OUTA 0xE9 ; Entry 0, the paper: black.
|
|
||||||
OUTA 0xE9
|
|
||||||
OUTA 0xE9
|
|
||||||
OUTA 0xE9
|
|
||||||
INIA 0xD8
|
|
||||||
OUTA 0xE9 ; Entry 1, the ink: grey.
|
|
||||||
OUTA 0xE9
|
|
||||||
OUTA 0xE9
|
|
||||||
RSTA
|
|
||||||
OUTA 0xE9
|
|
||||||
|
|
||||||
OUTA 0x02 ; Line mode, the way it was found.
|
OUTA 0x02 ; Line mode, the way it was found.
|
||||||
RSTA ; splitlint[redundant-assignment]: an exit status, not a mode
|
RSTA ; splitlint[redundant-assignment]: an exit status, not a mode
|
||||||
SWI osExit
|
SWI osExit
|
||||||
|
|||||||
@@ -870,6 +870,36 @@ too, and that is no use on a disk which has not got one. The directory is sixtee
|
|||||||
names, chosen rather than worked out: a scratch disk runs out of names long before it runs out
|
names, chosen rather than worked out: a scratch disk runs out of names long before it runs out
|
||||||
of room, and this machine cannot divide.
|
of room, and this machine cannot divide.
|
||||||
|
|
||||||
|
### Giving The Screen Back:
|
||||||
|
|
||||||
|
A program that takes the whole screen leaves the shell a blank one, and whatever was on it -
|
||||||
|
the listing you were reading, the error you were about to act on - is gone. There is nowhere
|
||||||
|
to put 48K of video memory on a machine with 64K of Data Memory that CosmOS is already living
|
||||||
|
in.
|
||||||
|
|
||||||
|
**A drive made of memory is somewhere.** `SWI osTakeScreen` says *"I am about to use the whole
|
||||||
|
screen, and would like what is on it now put back when I exit."* The system writes video
|
||||||
|
memory to a file on the scratch drive and restores it from `handleExit`, alongside the vectors
|
||||||
|
and console mode it already puts back. Q is zero if that was arranged; a machine with no
|
||||||
|
volatile drive says no, and **a program told no should carry on regardless**, because it was
|
||||||
|
going to before this existed.
|
||||||
|
|
||||||
|
**It is not automatic, and that is the point.** Saving on every program start would be cheap
|
||||||
|
enough, but restoring on every exit would be wrong: `dir`, `Files` and `Say` print and stop,
|
||||||
|
and their output is the reason you ran them. A program that says nothing behaves exactly as
|
||||||
|
every program did before this existed.
|
||||||
|
|
||||||
|
**Tiles, map and palette all go** - 196 pages, and a block on the front holding the cursor,
|
||||||
|
the four scroll registers and the mode. The map's off-screen rows are the console's
|
||||||
|
scrollback; the tiles are the font, which a program that redefines one has overwritten; and
|
||||||
|
the palette is where the console's own colours live. `Grid` used to give back the map and not
|
||||||
|
the colours, and handed the shell green text on a blue ground.
|
||||||
|
|
||||||
|
It also replaced thirty lines of `Grid`: four scroll registers put back by hand, the map
|
||||||
|
filled with spaces, the cursor sent home, and palette bank 0 written out - all of which was
|
||||||
|
*still* wrong, because the other fifteen banks kept `Grid`'s colours and there was nowhere to
|
||||||
|
have kept the real ones.
|
||||||
|
|
||||||
### Where A Program Is Looked For:
|
### Where A Program Is Looked For:
|
||||||
|
|
||||||
Three places, tried in order:
|
Three places, tried in order:
|
||||||
@@ -939,6 +969,7 @@ Those numbers are written down once, in `Programs/CosmOS/Source/services.asm`, w
|
|||||||
| osPrintNumber | A and B together are a number. Prints it in decimal, without leading zeroes. |
|
| osPrintNumber | A and B together are a number. Prints it in decimal, without leading zeroes. |
|
||||||
| osBreak | Stops the program, shows every register as it had them, waits for a key, and carries on. |
|
| osBreak | Stops the program, shows every register as it had them, waits for a key, and carries on. |
|
||||||
| osLastStatus | Q answers what the last program exited with: 0 it did what it was asked, 1 it did not, 2 it was asked wrongly. A program may give its own meanings if it says so. |
|
| osLastStatus | Q answers what the last program exited with: 0 it did what it was asked, 1 it did not, 2 it was asked wrongly. A program may give its own meanings if it says so. |
|
||||||
|
| osTakeScreen | Says this program is about to use the whole screen and would like what is on it put back when it exits. Q is zero if that was arranged; anything else means it was not, which is the ordinary answer on a machine with no volatile drive. See Giving The Screen Back. |
|
||||||
| osBootState | Q answers how the last start went: 0 settled, 1 trying, 2 fell back. A machine with no disk answers settled, because there is nothing there to be unsettled about. |
|
| osBootState | Q answers how the last start went: 0 settled, 1 trying, 2 fell back. A machine with no disk answers settled, because there is nothing there to be unsettled about. |
|
||||||
| osBootSettle | Puts it back to settled, which is how a machine that fell back is told the situation has changed. Q is zero if the disk took it. **Settling is the only write a program gets** - marking a start as trying or fallen back is the loader's business, and a service that let a program claim either would let it lie about something the loader cannot check. |
|
| osBootSettle | Puts it back to settled, which is how a machine that fell back is told the situation has changed. Q is zero if the disk took it. **Settling is the only write a program gets** - marking a start as trying or fallen back is the loader's business, and a service that let a program claim either would let it lie about something the loader cannot check. |
|
||||||
|
|
||||||
|
|||||||
@@ -1840,6 +1840,373 @@ scriptNoName:
|
|||||||
;
|
;
|
||||||
; SET WHEREVER A PROGRAM STARTS, of which there are two: run, and typing a program's name.
|
; SET WHEREVER A PROGRAM STARTS, of which there are two: run, and typing a program's name.
|
||||||
; Restored in handleExit, which is the one place they both come back through.
|
; Restored in handleExit, which is the one place they both come back through.
|
||||||
|
; ---- Putting the screen somewhere and getting it back ----
|
||||||
|
;
|
||||||
|
; A program that takes the whole screen leaves the shell a blank one, and everything that was
|
||||||
|
; on it - the listing you were reading, the error you were about to act on - is gone. There is
|
||||||
|
; nowhere to put 32K on a machine with 64K of Data Memory that CosmOS is already living in.
|
||||||
|
;
|
||||||
|
; A DRIVE MADE OF MEMORY IS SOMEWHERE. The map goes to a file on the scratch drive like any
|
||||||
|
; other file, and comes back the same way; the filesystem does the allocating, and this had to
|
||||||
|
; invent nothing at all to have somewhere to put it.
|
||||||
|
;
|
||||||
|
; EVERYTHING A PROGRAM CAN DISTURB, which is more than the part on screen. The map's off
|
||||||
|
; screen rows are the console's scrollback; the tiles are the font, which a program that
|
||||||
|
; redefines one has overwritten; and the palette is where the console's own colours live -
|
||||||
|
; Grid could give back the map and not the colours, and handed the shell green text on blue.
|
||||||
|
;
|
||||||
|
; 192 pages of tiles and map, which are next to each other, then the four of palette. 196 in
|
||||||
|
; all, and a register block on the front.
|
||||||
|
;
|
||||||
|
; ---- Saved on being asked, restored on the way out ----
|
||||||
|
;
|
||||||
|
; Saving on every program start would be cheap enough. Restoring on every exit would be
|
||||||
|
; WRONG: dir, Files and Say print and stop, and their output is the reason you ran them.
|
||||||
|
; So a program says it is taking the screen, and one that says nothing behaves exactly as
|
||||||
|
; every program did before this existed.
|
||||||
|
screenTake:
|
||||||
|
SETD.0 SbfsScratch1
|
||||||
|
LDA.0
|
||||||
|
INIB 0xFF
|
||||||
|
CCF
|
||||||
|
SUB
|
||||||
|
BRQ screenNoScratch ; No volatile drive, so nowhere to put it.
|
||||||
|
|
||||||
|
; Where the caller was, and where the file is going.
|
||||||
|
INA 0x24
|
||||||
|
SETD.0 ScreenWasDrive
|
||||||
|
STA.0
|
||||||
|
SETD.0 SbfsScratch1
|
||||||
|
LDA.0
|
||||||
|
CALL sbfsUse
|
||||||
|
|
||||||
|
CALL screenBank
|
||||||
|
|
||||||
|
; A hundred and twenty nine blocks: one of registers, then the map.
|
||||||
|
SETD.0 SbfsFileBlocks
|
||||||
|
RSTA
|
||||||
|
STA.0
|
||||||
|
INCD.0
|
||||||
|
INIA 0d197
|
||||||
|
STA.0
|
||||||
|
SETD.0 SbfsFileTail
|
||||||
|
RSTA
|
||||||
|
STA.0
|
||||||
|
SETD.0 ScreenFileName
|
||||||
|
CALL sbfsStreamStart
|
||||||
|
BNQ screenTakeFailed
|
||||||
|
|
||||||
|
; Block nought is where the screen was, rather than what was on it: the cursor, the four
|
||||||
|
; scroll registers and the mode. A picture put back under a different origin is not the
|
||||||
|
; picture that was taken.
|
||||||
|
CALL screenClearBlock
|
||||||
|
SETD.0 ScreenBlock
|
||||||
|
INA 0x03
|
||||||
|
STA.0
|
||||||
|
INCD.0
|
||||||
|
INA 0x04
|
||||||
|
STA.0
|
||||||
|
INCD.0
|
||||||
|
INA 0x34
|
||||||
|
STA.0
|
||||||
|
INCD.0
|
||||||
|
INA 0x36
|
||||||
|
STA.0
|
||||||
|
INCD.0
|
||||||
|
INA 0x37
|
||||||
|
STA.0
|
||||||
|
INCD.0
|
||||||
|
INA 0x38
|
||||||
|
STA.0
|
||||||
|
INCD.0
|
||||||
|
INA 0x31
|
||||||
|
STA.0
|
||||||
|
|
||||||
|
RSTA
|
||||||
|
RSTB
|
||||||
|
SETD.2 SbfsIndex
|
||||||
|
STA.2
|
||||||
|
INCD.2
|
||||||
|
STB.2
|
||||||
|
SETD.1 ScreenBlock
|
||||||
|
CALL sbfsStreamWrite
|
||||||
|
BNQ screenTakeFailed
|
||||||
|
|
||||||
|
; And the map, a block at a time through the one buffer there is.
|
||||||
|
RSTA
|
||||||
|
SETD.0 ScreenAt
|
||||||
|
STA.0
|
||||||
|
screenTakeBlock:
|
||||||
|
SETD.0 ScreenAt
|
||||||
|
LDA.0
|
||||||
|
CALL screenPageFor
|
||||||
|
MVQA
|
||||||
|
CALL screenFromVideo
|
||||||
|
|
||||||
|
SETD.0 ScreenAt
|
||||||
|
LDA.0
|
||||||
|
INCA
|
||||||
|
SETD.2 SbfsIndex
|
||||||
|
RSTB
|
||||||
|
STB.2
|
||||||
|
INCD.2
|
||||||
|
STA.2 ; Block n of the map is block n+1 of the file.
|
||||||
|
SETD.1 ScreenBlock
|
||||||
|
CALL sbfsStreamWrite
|
||||||
|
BNQ screenTakeFailed
|
||||||
|
|
||||||
|
SETD.0 ScreenAt
|
||||||
|
LDA.0
|
||||||
|
INCA
|
||||||
|
STA.0
|
||||||
|
INIB 0d196
|
||||||
|
CCF
|
||||||
|
SUB
|
||||||
|
BNQ screenTakeBlock
|
||||||
|
|
||||||
|
SETD.0 SbfsFileBlocks
|
||||||
|
RSTA
|
||||||
|
STA.0
|
||||||
|
INCD.0
|
||||||
|
INIA 0d197
|
||||||
|
STA.0
|
||||||
|
SETD.0 SbfsFileTail
|
||||||
|
RSTA
|
||||||
|
STA.0
|
||||||
|
CALL sbfsStreamDone
|
||||||
|
BNQ screenTakeFailed
|
||||||
|
|
||||||
|
INIA 0x01
|
||||||
|
SETD.0 ScreenSaved
|
||||||
|
STA.0
|
||||||
|
CALL screenGoBack
|
||||||
|
RSTA
|
||||||
|
RSTB
|
||||||
|
CCF
|
||||||
|
ADD
|
||||||
|
RET
|
||||||
|
|
||||||
|
screenTakeFailed:
|
||||||
|
RSTA
|
||||||
|
SETD.0 ScreenSaved
|
||||||
|
STA.0
|
||||||
|
CALL screenGoBack
|
||||||
|
screenNoScratch:
|
||||||
|
RSTA
|
||||||
|
INIB 0d1
|
||||||
|
CCF
|
||||||
|
ADD
|
||||||
|
RET
|
||||||
|
|
||||||
|
; Whatever screenTake put away, put back. Nothing at all if it never ran.
|
||||||
|
screenGive:
|
||||||
|
SETD.0 ScreenSaved
|
||||||
|
LDA.0
|
||||||
|
BRA screenGiveNone
|
||||||
|
|
||||||
|
RSTA
|
||||||
|
STA.0 ; Once only: the next program takes its own.
|
||||||
|
INA 0x24
|
||||||
|
SETD.0 ScreenWasDrive
|
||||||
|
STA.0
|
||||||
|
SETD.0 SbfsScratch1
|
||||||
|
LDA.0
|
||||||
|
CALL sbfsUse
|
||||||
|
|
||||||
|
CALL screenBank
|
||||||
|
|
||||||
|
SETD.0 ScreenFileName
|
||||||
|
CALL fileLookup
|
||||||
|
BNQ screenGiveDone
|
||||||
|
|
||||||
|
; The map first, then the registers, so that nothing is drawn under an origin that is about
|
||||||
|
; to change.
|
||||||
|
RSTA
|
||||||
|
SETD.0 ScreenAt
|
||||||
|
STA.0
|
||||||
|
screenGiveBlock:
|
||||||
|
SETD.0 ScreenAt
|
||||||
|
LDA.0
|
||||||
|
INCA
|
||||||
|
SETD.2 SbfsIndex
|
||||||
|
RSTB
|
||||||
|
STB.2
|
||||||
|
INCD.2
|
||||||
|
STA.2
|
||||||
|
SETD.1 ScreenBlock
|
||||||
|
CALL sbfsReadOne
|
||||||
|
BNQ screenGiveDone
|
||||||
|
|
||||||
|
SETD.0 ScreenAt
|
||||||
|
LDA.0
|
||||||
|
CALL screenPageFor
|
||||||
|
MVQA
|
||||||
|
CALL screenToVideo
|
||||||
|
|
||||||
|
SETD.0 ScreenAt
|
||||||
|
LDA.0
|
||||||
|
INCA
|
||||||
|
STA.0
|
||||||
|
INIB 0d196
|
||||||
|
CCF
|
||||||
|
SUB
|
||||||
|
BNQ screenGiveBlock
|
||||||
|
|
||||||
|
; And where it was.
|
||||||
|
RSTA
|
||||||
|
RSTB
|
||||||
|
SETD.2 SbfsIndex
|
||||||
|
STA.2
|
||||||
|
INCD.2
|
||||||
|
STB.2
|
||||||
|
SETD.1 ScreenBlock
|
||||||
|
CALL sbfsReadOne
|
||||||
|
BNQ screenGiveDone
|
||||||
|
|
||||||
|
SETD.0 ScreenBlock
|
||||||
|
LDA.0
|
||||||
|
OUTA 0x03
|
||||||
|
INCD.0
|
||||||
|
LDA.0
|
||||||
|
OUTA 0x04
|
||||||
|
INCD.0
|
||||||
|
LDA.0
|
||||||
|
OUTA 0x34
|
||||||
|
INCD.0
|
||||||
|
LDA.0
|
||||||
|
OUTA 0x36
|
||||||
|
INCD.0
|
||||||
|
LDA.0
|
||||||
|
OUTA 0x37
|
||||||
|
INCD.0
|
||||||
|
LDA.0
|
||||||
|
OUTA 0x38
|
||||||
|
INCD.0
|
||||||
|
LDA.0
|
||||||
|
OUTA 0x31
|
||||||
|
|
||||||
|
screenGiveDone:
|
||||||
|
CALL screenGoBack
|
||||||
|
screenGiveNone:
|
||||||
|
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.
|
||||||
|
screenBank:
|
||||||
|
INIA 0d4
|
||||||
|
OUTA 0xE3
|
||||||
|
INIA 0x30
|
||||||
|
OUTA 0xE2
|
||||||
|
INIA 0x03
|
||||||
|
OUTA 0xE8
|
||||||
|
RET
|
||||||
|
|
||||||
|
; Back to the drive whoever called was standing on.
|
||||||
|
screenGoBack:
|
||||||
|
SETD.0 ScreenWasDrive
|
||||||
|
LDA.0
|
||||||
|
CALL sbfsUse
|
||||||
|
RET
|
||||||
|
|
||||||
|
; ---- Which page of video memory a saved block is ----
|
||||||
|
;
|
||||||
|
; Nought to 191 are the tiles and the map, which sit next to each other from 0x0000. After
|
||||||
|
; that comes 16K of nothing, so 192 to 195 jump to 0xFC and are the palette. One sum rather
|
||||||
|
; than two loops, because two loops is two places to get the file's block numbers wrong.
|
||||||
|
screenPageFor:
|
||||||
|
INIB 0d192
|
||||||
|
CCF
|
||||||
|
SUB
|
||||||
|
BRC screenPageDirect ; Borrowed, so it is below 192 and the page is the index.
|
||||||
|
MVQA
|
||||||
|
INIB 0xFC
|
||||||
|
CCF
|
||||||
|
ADD
|
||||||
|
RET
|
||||||
|
screenPageDirect:
|
||||||
|
RSTB
|
||||||
|
CCF
|
||||||
|
ADD
|
||||||
|
RET
|
||||||
|
|
||||||
|
; A holds a page of video memory. Its 256 bytes come into ScreenBlock.
|
||||||
|
screenFromVideo:
|
||||||
|
PSHA
|
||||||
|
INIA 0d4
|
||||||
|
OUTA 0xE0
|
||||||
|
POPA
|
||||||
|
OUTA 0xE1
|
||||||
|
RSTA
|
||||||
|
OUTA 0xE2
|
||||||
|
INIA 0x01
|
||||||
|
OUTA 0xE3 ; Into Data Memory.
|
||||||
|
CALL screenBufferDest
|
||||||
|
CALL screenLength
|
||||||
|
INIA 0x01
|
||||||
|
OUTA 0xE8
|
||||||
|
RET
|
||||||
|
|
||||||
|
; A holds a page of video memory. ScreenBlock goes back into it.
|
||||||
|
screenToVideo:
|
||||||
|
PSHA
|
||||||
|
INIA 0d4
|
||||||
|
OUTA 0xE3
|
||||||
|
POPA
|
||||||
|
OUTA 0xE4
|
||||||
|
RSTA
|
||||||
|
OUTA 0xE5
|
||||||
|
INIA 0x01
|
||||||
|
OUTA 0xE0 ; Out of Data Memory.
|
||||||
|
CALL screenBufferSource
|
||||||
|
CALL screenLength
|
||||||
|
INIA 0x01
|
||||||
|
OUTA 0xE8
|
||||||
|
RET
|
||||||
|
|
||||||
|
; Where ScreenBlock is, told to the controller. A Data Pointer's two bytes cannot be read out
|
||||||
|
; of it, so it goes to memory first and comes back a byte at a time.
|
||||||
|
screenBufferDest:
|
||||||
|
SETD.1 ScreenBlockAt
|
||||||
|
SETD.0 ScreenBlock
|
||||||
|
STD.0.1
|
||||||
|
LDA.1
|
||||||
|
OUTA 0xE4
|
||||||
|
INCD.1
|
||||||
|
LDA.1
|
||||||
|
OUTA 0xE5
|
||||||
|
RET
|
||||||
|
|
||||||
|
screenBufferSource:
|
||||||
|
SETD.1 ScreenBlockAt
|
||||||
|
SETD.0 ScreenBlock
|
||||||
|
STD.0.1
|
||||||
|
LDA.1
|
||||||
|
OUTA 0xE1
|
||||||
|
INCD.1
|
||||||
|
LDA.1
|
||||||
|
OUTA 0xE2
|
||||||
|
RET
|
||||||
|
|
||||||
|
screenLength:
|
||||||
|
INIA 0x01
|
||||||
|
OUTA 0xE6
|
||||||
|
RSTA
|
||||||
|
OUTA 0xE7 ; 0x0100, which is one block.
|
||||||
|
RET
|
||||||
|
|
||||||
|
; The block, emptied. Everything the register block below does not fill has to be nought, or
|
||||||
|
; a screen restored would carry whatever the last file read left in here.
|
||||||
|
screenClearBlock:
|
||||||
|
SETD.0 ScreenBlock
|
||||||
|
RSTB
|
||||||
|
screenClearByte:
|
||||||
|
RSTA
|
||||||
|
STA.0
|
||||||
|
INCD.0
|
||||||
|
DECB
|
||||||
|
BNB screenClearByte
|
||||||
|
RET
|
||||||
|
|
||||||
; ---- run ----
|
; ---- run ----
|
||||||
;
|
;
|
||||||
; Hands the machine to whatever was loaded. Where the Stack is now is written down first,
|
; Hands the machine to whatever was loaded. Where the Stack is now is written down first,
|
||||||
@@ -2683,6 +3050,16 @@ bootSettleNo:
|
|||||||
ADD ; A is the answer, so Q becomes it.
|
ADD ; A is the answer, so Q becomes it.
|
||||||
SRET
|
SRET
|
||||||
|
|
||||||
|
; The program is about to draw over everything. Q says whether what is there now will come
|
||||||
|
; back, and a program that is told no carries on anyway.
|
||||||
|
handleTakeScreen:
|
||||||
|
CALL screenTake
|
||||||
|
MVQA
|
||||||
|
MVSD.2
|
||||||
|
DPUP.2 0d02
|
||||||
|
STA.2
|
||||||
|
RETI
|
||||||
|
|
||||||
handleExit:
|
handleExit:
|
||||||
; ---- What the program made of it ----
|
; ---- What the program made of it ----
|
||||||
;
|
;
|
||||||
@@ -2695,6 +3072,9 @@ handleExit:
|
|||||||
SETD.1 LastStatus
|
SETD.1 LastStatus
|
||||||
STA.1
|
STA.1
|
||||||
|
|
||||||
|
; What was on the screen before this program had it, if it asked for that.
|
||||||
|
CALL screenGive
|
||||||
|
|
||||||
; The drive the person was on, whatever the program did with it.
|
; The drive the person was on, whatever the program did with it.
|
||||||
PSHA
|
PSHA
|
||||||
SETD.1 RunDrive
|
SETD.1 RunDrive
|
||||||
@@ -3909,6 +4289,8 @@ Separator:
|
|||||||
; Where a program is looked for when it is not where you are. One fixed place rather than a
|
; Where a program is looked for when it is not where you are. One fixed place rather than a
|
||||||
; list somebody sets, because a list would need somewhere to live between one boot and the
|
; list somebody sets, because a list would need somewhere to live between one boot and the
|
||||||
; next, and there is no such place yet.
|
; next, and there is no such place yet.
|
||||||
|
ScreenFileName:
|
||||||
|
"sbfs.screen"
|
||||||
AppsPrefix:
|
AppsPrefix:
|
||||||
"/Apps/"
|
"/Apps/"
|
||||||
SystemAppsPrefix:
|
SystemAppsPrefix:
|
||||||
@@ -4194,6 +4576,16 @@ SearchDrive:
|
|||||||
0x00
|
0x00
|
||||||
RunDrive:
|
RunDrive:
|
||||||
0x00
|
0x00
|
||||||
|
ScreenSaved:
|
||||||
|
0x00
|
||||||
|
ScreenWasDrive:
|
||||||
|
0x00
|
||||||
|
ScreenAt:
|
||||||
|
0x00
|
||||||
|
ScreenBlockAt:
|
||||||
|
0x00 0x00
|
||||||
|
ScreenBlock:
|
||||||
|
#Reserve 0d256
|
||||||
FileCacheValid:
|
FileCacheValid:
|
||||||
0x00
|
0x00
|
||||||
FileCacheName:
|
FileCacheName:
|
||||||
@@ -4391,6 +4783,7 @@ CommandLine:
|
|||||||
osPrintNumber handlePrintNumber
|
osPrintNumber handlePrintNumber
|
||||||
osBreak handleBreak
|
osBreak handleBreak
|
||||||
osLastStatus handleLastStatus
|
osLastStatus handleLastStatus
|
||||||
|
osTakeScreen handleTakeScreen
|
||||||
osBootState handleBootState
|
osBootState handleBootState
|
||||||
osBootSettle handleBootSettle
|
osBootSettle handleBootSettle
|
||||||
Device 0x20 diskDone
|
Device 0x20 diskDone
|
||||||
|
|||||||
@@ -284,6 +284,9 @@ sbfsMountAll:
|
|||||||
SETD.1 SbfsDrive
|
SETD.1 SbfsDrive
|
||||||
STA.1
|
STA.1
|
||||||
OUTA 0x24 ; Drive 0, whatever the controller was left on.
|
OUTA 0x24 ; Drive 0, whatever the controller was left on.
|
||||||
|
INIA 0xFF
|
||||||
|
SETD.1 SbfsScratch1
|
||||||
|
STA.1 ; No scratch drive until one is found.
|
||||||
|
|
||||||
; The live record belongs to nobody yet, so every slot starts empty and a drive that fails
|
; The live record belongs to nobody yet, so every slot starts empty and a drive that fails
|
||||||
; to mount keeps an empty one.
|
; to mount keeps an empty one.
|
||||||
@@ -347,6 +350,26 @@ sbfsMountEach:
|
|||||||
BNQ sbfsMountNext
|
BNQ sbfsMountNext
|
||||||
|
|
||||||
sbfsMountGot:
|
sbfsMountGot:
|
||||||
|
; ---- And whether this is the one to keep scratch on ----
|
||||||
|
;
|
||||||
|
; A volatile drive is somewhere the system may write without asking, because nothing on it
|
||||||
|
; outlives the machine. The FIRST one found is the scratch drive; a machine with two has
|
||||||
|
; made a decision nobody expressed, and taking the lower number is at least predictable.
|
||||||
|
INA 0x26
|
||||||
|
INIB 0x01
|
||||||
|
AND
|
||||||
|
BRQ sbfsMountNotScratch
|
||||||
|
SETD.1 SbfsScratch1
|
||||||
|
LDA.1
|
||||||
|
INIB 0xFF
|
||||||
|
CCF
|
||||||
|
SUB
|
||||||
|
BNQ sbfsMountNotScratch ; There is one already.
|
||||||
|
SETD.1 SbfsDriveAt
|
||||||
|
LDA.1
|
||||||
|
SETD.1 SbfsScratch1
|
||||||
|
STA.1
|
||||||
|
sbfsMountNotScratch:
|
||||||
|
|
||||||
; Mounted: remember which, and put the live record where it belongs.
|
; Mounted: remember which, and put the live record where it belongs.
|
||||||
SETD.1 SbfsDriveAt
|
SETD.1 SbfsDriveAt
|
||||||
@@ -3661,6 +3684,10 @@ SbfsDriveCount:
|
|||||||
0x00
|
0x00
|
||||||
SbfsDriveAt:
|
SbfsDriveAt:
|
||||||
0x00
|
0x00
|
||||||
|
; Which drive the system may write scratch to, or 0xFF for a machine with none. It is a drive
|
||||||
|
; the machine called volatile, so nothing written there was ever going to survive anyway.
|
||||||
|
SbfsScratch1:
|
||||||
|
0xFF
|
||||||
SbfsPathWanted:
|
SbfsPathWanted:
|
||||||
0x00
|
0x00
|
||||||
|
|
||||||
|
|||||||
@@ -167,3 +167,14 @@
|
|||||||
; print it: a program that failed has already said so in words, and a number beside that
|
; print it: a program that failed has already said so in words, and a number beside that
|
||||||
; would be noise. This is for the thing that cannot read words.
|
; would be noise. This is for the thing that cannot read words.
|
||||||
osLastStatus 0d35
|
osLastStatus 0d35
|
||||||
|
|
||||||
|
; ---- Taking the screen, and giving it back ----
|
||||||
|
;
|
||||||
|
; Says that this program is about to use the whole screen and would like what is on it now put
|
||||||
|
; back when it exits. Q is zero if that was arranged; anything else means it was not, which is
|
||||||
|
; the ordinary answer on a machine with no volatile drive to keep it on - and a program told
|
||||||
|
; no should carry on regardless, because it was going to before this existed.
|
||||||
|
;
|
||||||
|
; NOT AUTOMATIC, and that is the point: dir and Say print and stop, and their output is the
|
||||||
|
; reason you ran them. Only a program that says it took the screen gets the screen put back.
|
||||||
|
osTakeScreen 0d36
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ Snake.sbx 2164
|
|||||||
Keys.sbx 664
|
Keys.sbx 664
|
||||||
Say.sbx 156
|
Say.sbx 156
|
||||||
Break.sbx 149
|
Break.sbx 149
|
||||||
Grid.sbx 543
|
Grid.sbx 479
|
||||||
notes.txt 21
|
notes.txt 21
|
||||||
Apps <dir>
|
Apps <dir>
|
||||||
hi.script 121
|
hi.script 121
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ Snake.sbx 2164
|
|||||||
Keys.sbx 664
|
Keys.sbx 664
|
||||||
Say.sbx 156
|
Say.sbx 156
|
||||||
Break.sbx 149
|
Break.sbx 149
|
||||||
Grid.sbx 543
|
Grid.sbx 479
|
||||||
notes.txt 21
|
notes.txt 21
|
||||||
Apps <dir>
|
Apps <dir>
|
||||||
hi.script 121
|
hi.script 121
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
CosmOS
|
CosmOS
|
||||||
> it says: before Grid
|
> it says: before Grid
|
||||||
finished
|
finished
|
||||||
> [2J[Hfinished
|
> finished
|
||||||
> > it says: after Grid
|
> > it says: after Grid
|
||||||
finished
|
finished
|
||||||
> greet.sbx 211
|
> greet.sbx 211
|
||||||
@@ -11,7 +11,7 @@ Snake.sbx 2164
|
|||||||
Keys.sbx 664
|
Keys.sbx 664
|
||||||
Say.sbx 156
|
Say.sbx 156
|
||||||
Break.sbx 149
|
Break.sbx 149
|
||||||
Grid.sbx 543
|
Grid.sbx 479
|
||||||
notes.txt 21
|
notes.txt 21
|
||||||
Apps <dir>
|
Apps <dir>
|
||||||
hi.script 121
|
hi.script 121
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ Snake.sbx 2164
|
|||||||
Keys.sbx 664
|
Keys.sbx 664
|
||||||
Say.sbx 156
|
Say.sbx 156
|
||||||
Break.sbx 149
|
Break.sbx 149
|
||||||
Grid.sbx 543
|
Grid.sbx 479
|
||||||
notes.txt 21
|
notes.txt 21
|
||||||
Apps <dir>
|
Apps <dir>
|
||||||
hi.script 121
|
hi.script 121
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ Snake.sbx 2164
|
|||||||
Keys.sbx 664
|
Keys.sbx 664
|
||||||
Say.sbx 156
|
Say.sbx 156
|
||||||
Break.sbx 149
|
Break.sbx 149
|
||||||
Grid.sbx 543
|
Grid.sbx 479
|
||||||
notes.txt 21
|
notes.txt 21
|
||||||
Apps <dir>
|
Apps <dir>
|
||||||
hi.script 121
|
hi.script 121
|
||||||
|
|||||||
@@ -0,0 +1,47 @@
|
|||||||
|
# Two screens, compared a cell at a time: is the second the first, restored?
|
||||||
|
#
|
||||||
|
# Cells rather than pixels, and "ink or no ink" rather than colour, because what is being
|
||||||
|
# checked is that the TEXT came back - a restore that got the map right and the palette wrong
|
||||||
|
# would still be a restore that lost the colours, and that is checked by the colours being
|
||||||
|
# the console's own elsewhere.
|
||||||
|
#
|
||||||
|
# THE ROWS AROUND THE CURSOR ARE ALLOWED TO DIFFER, and they are found rather than guessed at.
|
||||||
|
# The screen is given back and THEN the shell carries on writing to it - a "finished" and a
|
||||||
|
# prompt, two or three lines - so the bottom of what was there is where they land. The cursor
|
||||||
|
# is not near the bottom of the SCREEN, so "the last few rows of the screen" is the wrong
|
||||||
|
# exemption and let a real difference through the first time this ran.
|
||||||
|
#
|
||||||
|
# Everything above that is what the restore is judged on, which here is 25 rows of 28.
|
||||||
|
import sys
|
||||||
|
|
||||||
|
|
||||||
|
def cells(path):
|
||||||
|
data = open(path, "rb").read()
|
||||||
|
fields = data.split(b"\n", 3)
|
||||||
|
width, height = (int(n) for n in fields[1].split())
|
||||||
|
body = fields[3]
|
||||||
|
out = []
|
||||||
|
for cy in range(height // 8):
|
||||||
|
row = ""
|
||||||
|
for cx in range(width // 8):
|
||||||
|
inked = any(
|
||||||
|
body[((cy * 8 + j) * width + cx * 8 + i) * 3:
|
||||||
|
((cy * 8 + j) * width + cx * 8 + i) * 3 + 3] != b"\x00\x00\x00"
|
||||||
|
for j in range(8) for i in range(8))
|
||||||
|
row += "#" if inked else "."
|
||||||
|
out.append(row)
|
||||||
|
return out
|
||||||
|
|
||||||
|
|
||||||
|
before, after = cells(sys.argv[1]), cells(sys.argv[2])
|
||||||
|
if len(before) != len(after):
|
||||||
|
print("the screens are different sizes")
|
||||||
|
sys.exit(0)
|
||||||
|
differ = [n for n, (b, a) in enumerate(zip(before, after)) if b != a]
|
||||||
|
inked = [n for n, row in enumerate(before) if "#" in row]
|
||||||
|
settled = (max(inked) - 3) if inked else 0
|
||||||
|
early = [n for n in differ if n < settled]
|
||||||
|
if early:
|
||||||
|
print("row %d is not what it was" % early[0])
|
||||||
|
else:
|
||||||
|
print("yes")
|
||||||
@@ -838,6 +838,28 @@ else
|
|||||||
result no "a program drew a grid of its own tile" "no picture came out"
|
result no "a program drew a grid of its own tile" "no picture came out"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# ---- A program gives the screen back ----
|
||||||
|
#
|
||||||
|
# Grid takes the whole screen: it redefines a tile, writes all sixteen colour schemes over the
|
||||||
|
# console's own, and fills every cell of the map. Then it asks the system for what was there
|
||||||
|
# before, and the system has somewhere to put it because the machine has a drive made of
|
||||||
|
# memory.
|
||||||
|
#
|
||||||
|
# WHAT IS COMPARED IS THE SCREEN BEFORE AGAINST THE SCREEN AFTER, cell by cell. Checking that
|
||||||
|
# it merely looks like text would pass on a restore that put back somebody else's text, and
|
||||||
|
# checking a few pixels would pass on one that got the palette right and the map wrong.
|
||||||
|
python3 -c "open('$BUILD/before.keys','wb').write(b'dir\n' + b'Say a line to come back to\n' + b'\x00'*200)"
|
||||||
|
python3 -c "open('$BUILD/after.keys','wb').write(b'dir\n' + b'Say a line to come back to\n' + b'Grid\n' + b'\x00'*600 + b'q' + b'\x00'*200)"
|
||||||
|
for phase in before after; do
|
||||||
|
timeout 30 "$EMU" --fast --cycles 200000000 --keyboard "$BUILD/$phase.keys" \
|
||||||
|
--screen "$BUILD/$phase.ppm" --disk "$ROOT/Tests/build/disks/cosmos.img" \
|
||||||
|
--ram-disk 2048 "$BUILD/cosmos.bin" > "$BUILD/$phase.out" 2>&1 || true
|
||||||
|
done
|
||||||
|
SAME="$(python3 "$ROOT/Tests/samescreen.py" "$BUILD/before.ppm" "$BUILD/after.ppm")"
|
||||||
|
[ "$SAME" = "yes" ] \
|
||||||
|
&& result ok "a program gives the screen back" "every row it did not write on is as it was" \
|
||||||
|
|| result no "a program gives the screen back" "$SAME"
|
||||||
|
|
||||||
# ---- Clearing puts the cursor back at the top ----
|
# ---- Clearing puts the cursor back at the top ----
|
||||||
#
|
#
|
||||||
# A screen with nothing on it and a cursor half way down it is not a cleared screen. This
|
# A screen with nothing on it and a cursor half way down it is not a cleared screen. This
|
||||||
|
|||||||
Reference in New Issue
Block a user