diff --git a/Programs/CosmOS/Apps/Grid.asm b/Programs/CosmOS/Apps/Grid.asm index 9066a3a..41e1b94 100644 --- a/Programs/CosmOS/Apps/Grid.asm +++ b/Programs/CosmOS/Apps/Grid.asm @@ -51,6 +51,9 @@ start: ; at exit - and if it says it cannot, this carries on anyway, because it did before there ; was anywhere to put it. SWI osTakeScreen + MVQA + SETD.0 ScreenKept + STA.0 ; Nought means the system will put it back. CALL putTile CALL putPalette @@ -135,6 +138,58 @@ finished: ; ; All of it is osTakeScreen's now, and it gives back what was actually there rather than ; what a clean machine looks like. + ; + ; ---- Unless it said no ---- + ; + ; A machine with no volatile drive has nowhere to keep a screen, and answers so. Being told + ; no is not a fault and not a reason to stop: it means doing what this program did before + ; there was anywhere to put one, which is leaving a blank screen rather than a grid with + ; somebody's prompt printed into it. + SETD.0 ScreenKept + LDA.0 + BRA gridScreenKept + + RSTA + OUTA 0x34 + OUTA 0x36 ; The origins, or the shell looks at a corner of the map. + + INIA 0d4 + OUTA 0xE3 + INIA 0x40 + OUTA 0xE4 + RSTA + OUTA 0xE5 + OUTA 0xE2 ; Tile nought is the space and attribute nought is plain. + INIA 0x80 + OUTA 0xE6 + RSTA + OUTA 0xE7 + INIA 0x02 + OUTA 0xE8 ; Fill the whole map with it. + + ; And the colours the machine wakes up in, which is as near as this can get to the ones it + ; took: grey on black is what plain text has always been here. + INIA 0d4 + OUTA 0xE3 + INIA 0xFC + OUTA 0xE4 + RSTA + OUTA 0xE5 + OUTA 0xE9 + OUTA 0xE9 + OUTA 0xE9 + OUTA 0xE9 + INIA 0xD8 + OUTA 0xE9 + OUTA 0xE9 + OUTA 0xE9 + RSTA + OUTA 0xE9 + + INIA 0x01 + OUTA 0x05 ; Cleared, which also puts the cursor home. + +gridScreenKept: RSTA OUTA 0x02 ; Line mode, the way it was found. RSTA ; splitlint[redundant-assignment]: an exit status, not a mode @@ -358,6 +413,8 @@ everyCell: #Base 0x2000 +ScreenKept: + 0x00 FineDown: 0x00 FineAcross: diff --git a/Programs/CosmOS/README.md b/Programs/CosmOS/README.md index 816720c..ebdb999 100644 --- a/Programs/CosmOS/README.md +++ b/Programs/CosmOS/README.md @@ -843,7 +843,9 @@ walks back and forth without `Copy` itself knowing there is more than one disk. ### A Disk Of Your Own: -`make run-voyager` puts a second disk in **drive 1**, at `Disks/personal.img`. It is made the +`make run-voyager` puts a second disk in **drive 1**, at `Disks/personal.img`, and a scratch +drive made of memory in **drive 2**. The scratch drive is what `osTakeScreen` writes to; drive +1 is yours and comes after nothing, so adding the scratch drive later did not renumber it. It is made the first time it is needed and then left alone: never rebuilt, never cleaned, never committed. That last part is the point. Everything else in this repository is made from source and can be @@ -884,6 +886,16 @@ and console mode it already puts back. Q is zero if that was arranged; a machine volatile drive says no, and **a program told no should carry on regardless**, because it was going to before this existed. +**A program told no must cope.** There is no volatile drive on every machine, and a refusal is +not a fault - it means doing what the program would have done before there was anywhere to +save a screen. `Grid` clears up after itself when refused, which is the difference between a +clean prompt and a prompt printed into somebody's grid. + +**The system always leaves the screen usable, refusal or not.** The fine scroll registers go +back to zero at every program exit, because the console draws in whole cells and a view three +pixels into one puts every character three pixels out for ever. That is true whether or not +the picture could be saved, so it is not part of the saving. + **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 diff --git a/Programs/CosmOS/Source/cosmos.asm b/Programs/CosmOS/Source/cosmos.asm index d4a74b0..3f257ac 100644 --- a/Programs/CosmOS/Source/cosmos.asm +++ b/Programs/CosmOS/Source/cosmos.asm @@ -2090,6 +2090,14 @@ screenGiveDone: screenGiveNone: RET +; The registers a console cannot work without, put back. Not the picture - that is +; screenGive's, and only happens for a program that asked. +screenSane: + RSTA + OUTA 0x37 + OUTA 0x38 ; No fraction of a cell in either direction. + 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: @@ -3072,6 +3080,16 @@ handleExit: SETD.1 LastStatus STA.1 + ; ---- The screen made usable, whether or not the picture can be given back ---- + ; + ; A fraction of a cell is never what anybody wants left behind: the console draws in whole + ; cells, so a view three pixels into one puts every character three pixels out for ever. + ; That is true whether or not there was anywhere to save the picture, so it is not part of + ; the saving - a program refused by osTakeScreen still must not leave the shell squinting. + ; + ; Before screenGive, so that a restored screen's own registers win. + CALL screenSane + ; What was on the screen before this program had it, if it asked for that. CALL screenGive diff --git a/Tests/expected/cosmosCrossDisk.out b/Tests/expected/cosmosCrossDisk.out index faf3578..4cfdf3f 100644 --- a/Tests/expected/cosmosCrossDisk.out +++ b/Tests/expected/cosmosCrossDisk.out @@ -12,7 +12,7 @@ Snake.sbx 2164 Keys.sbx 664 Say.sbx 156 Break.sbx 149 -Grid.sbx 479 +Grid.sbx 559 notes.txt 21 Apps hi.script 121 diff --git a/Tests/expected/cosmosDrives.out b/Tests/expected/cosmosDrives.out index 7ed0627..8bf2a61 100644 --- a/Tests/expected/cosmosDrives.out +++ b/Tests/expected/cosmosDrives.out @@ -7,7 +7,7 @@ Snake.sbx 2164 Keys.sbx 664 Say.sbx 156 Break.sbx 149 -Grid.sbx 479 +Grid.sbx 559 notes.txt 21 Apps hi.script 121 diff --git a/Tests/expected/cosmosGrid.out b/Tests/expected/cosmosGrid.out index 71b7ff1..69ffa41 100644 --- a/Tests/expected/cosmosGrid.out +++ b/Tests/expected/cosmosGrid.out @@ -1,7 +1,7 @@ CosmOS > it says: before Grid finished -> finished +> finished > > it says: after Grid finished > greet.sbx 211 @@ -11,7 +11,7 @@ Snake.sbx 2164 Keys.sbx 664 Say.sbx 156 Break.sbx 149 -Grid.sbx 479 +Grid.sbx 559 notes.txt 21 Apps hi.script 121 diff --git a/Tests/expected/cosmosRun.out b/Tests/expected/cosmosRun.out index f3a8f66..20b9a3c 100644 --- a/Tests/expected/cosmosRun.out +++ b/Tests/expected/cosmosRun.out @@ -7,7 +7,7 @@ Snake.sbx 2164 Keys.sbx 664 Say.sbx 156 Break.sbx 149 -Grid.sbx 479 +Grid.sbx 559 notes.txt 21 Apps hi.script 121 diff --git a/Tests/expected/cosmosSlowDisk.out b/Tests/expected/cosmosSlowDisk.out index 3abc457..d55f474 100644 --- a/Tests/expected/cosmosSlowDisk.out +++ b/Tests/expected/cosmosSlowDisk.out @@ -6,7 +6,7 @@ Snake.sbx 2164 Keys.sbx 664 Say.sbx 156 Break.sbx 149 -Grid.sbx 479 +Grid.sbx 559 notes.txt 21 Apps hi.script 121 diff --git a/Tests/video.sh b/Tests/video.sh index 130c5a3..8e41585 100755 --- a/Tests/video.sh +++ b/Tests/video.sh @@ -860,6 +860,20 @@ SAME="$(python3 "$ROOT/Tests/samescreen.py" "$BUILD/before.ppm" "$BUILD/after.pp && 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" +# ---- And when there is nowhere to put it ---- +# +# The same program on a machine with no volatile drive. osTakeScreen answers no, and a program +# told no does what it did before there was anywhere to save a screen: it clears up after +# itself. What must NOT happen is the shell printing its prompt into somebody's grid, which is +# what happened the day the run targets had no scratch drive and this check did not exist. +timeout 30 "$EMU" --fast --cycles 200000000 --keyboard "$BUILD/after.keys" \ + --screen "$BUILD/noscratch.ppm" --disk "$ROOT/Tests/build/disks/cosmos.img" \ + "$BUILD/cosmos.bin" > "$BUILD/noscratch.out" 2>&1 || true +LEFT="$(python3 "$ROOT/Tests/periodic.py" "$BUILD/noscratch.ppm" grid)" +[ "$LEFT" != "yes" ] \ + && result ok "and clears up when it cannot be kept" "no grid left on the screen" \ + || result no "and clears up when it cannot be kept" "the grid is still there" + # ---- 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 diff --git a/makefile b/makefile index 62b9cf3..6243e50 100644 --- a/makefile +++ b/makefile @@ -172,6 +172,17 @@ COSMOS_DISK = $(PROG_BUILD)/cosmos.img # once it exists make never looks at it again. PERSONAL_DISK = Disks/personal.img +# ---- And a drive made of memory, as drive 2 ---- +# +# 2,048 blocks, half a megabyte, gone when the machine stops. The system keeps there whatever +# it wants back later and cannot hold - the screen a program took, and whatever comes after +# that. A machine without one does without: osTakeScreen answers no and a program told no +# carries on. +# +# AFTER the personal disk, so drive 1 stays the one that is yours. A scratch drive that took +# drive 1 would renumber somebody's disk the day it was added. +SCRATCH_BLOCKS = 2048 + # VOYAGER IS NOT IN THE HARD LIST. Everything below it - the assembler, the disk tool, the # linter, the whole test suite - has to build on a machine with no graphics library at all, @@ -608,13 +619,13 @@ $(PERSONAL_DISK): @echo " again - not clean, not a rebuild. Delete it by hand if you want a new one." run-cosmos: $(COSMOS_DISK) $(PERSONAL_DISK) - $(EMU_RUN) --disk $(COSMOS_DISK) --disk $(PERSONAL_DISK) + $(EMU_RUN) --disk $(COSMOS_DISK) --disk $(PERSONAL_DISK) --ram-disk $(SCRATCH_BLOCKS) # The same disk with the system handed over directly instead, which is what a debugger does: # memory is placed from outside and nothing on the disk is consulted about it. Useful when the # thing being debugged is the boot chain itself, since it skips the boot chain. run-cosmos-direct: $(COSMOS) $(COSMOS_DISK) $(PERSONAL_DISK) - $(EMU_RUN) --disk $(COSMOS_DISK) --disk $(PERSONAL_DISK) $(COSMOS) + $(EMU_RUN) --disk $(COSMOS_DISK) --disk $(PERSONAL_DISK) --ram-disk $(SCRATCH_BLOCKS) $(COSMOS) # ---- The same disk, on the machine with a screen ---- # @@ -626,10 +637,10 @@ run-cosmos-direct: $(COSMOS) $(COSMOS_DISK) $(PERSONAL_DISK) # an image full of programs written for the old one - and they will draw whatever the old way # now means. Making the disk a dependency of running it is what stops that being a puzzle. run-voyager: $(COSMOS_DISK) $(PERSONAL_DISK) - $(VOY_RUN) --disk $(COSMOS_DISK) --disk $(PERSONAL_DISK) + $(VOY_RUN) --disk $(COSMOS_DISK) --disk $(PERSONAL_DISK) --ram-disk $(SCRATCH_BLOCKS) run-voyager-direct: $(COSMOS) $(COSMOS_DISK) $(PERSONAL_DISK) - $(VOY_RUN) --disk $(COSMOS_DISK) --disk $(PERSONAL_DISK) $(COSMOS) + $(VOY_RUN) --disk $(COSMOS_DISK) --disk $(PERSONAL_DISK) --ram-disk $(SCRATCH_BLOCKS) $(COSMOS) # Pull in the dependency rules the assembler wrote with -M, so that touching a library # reassembles every program that includes it.