Flip says the true thing, and the checks that let it lie
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
This commit is contained in:
co-authored by
Claude Opus 5
parent
023362b05a
commit
eee95ef0ce
@@ -22,7 +22,7 @@ Break.sbx 149
|
||||
Grid.sbx 571
|
||||
Press.sbx 872
|
||||
Mode.sbx 48
|
||||
Flip.sbx 291
|
||||
Flip.sbx 173
|
||||
Crash.sbx 632
|
||||
vars.script 50
|
||||
blocks.script 343
|
||||
|
||||
@@ -12,7 +12,7 @@ Break.sbx 149
|
||||
Grid.sbx 571
|
||||
Press.sbx 872
|
||||
Mode.sbx 48
|
||||
Flip.sbx 291
|
||||
Flip.sbx 173
|
||||
Crash.sbx 632
|
||||
vars.script 50
|
||||
blocks.script 343
|
||||
|
||||
@@ -29,7 +29,7 @@ Break.sbx 149
|
||||
Grid.sbx 571
|
||||
Press.sbx 872
|
||||
Mode.sbx 48
|
||||
Flip.sbx 291
|
||||
Flip.sbx 173
|
||||
Crash.sbx 632
|
||||
vars.script 50
|
||||
blocks.script 343
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
CosmOS
|
||||
> Say before Flip
|
||||
it says: before Flip
|
||||
finished
|
||||
> Flip
|
||||
A screen is drawn where you cannot see it. A key shows it, another comes back.
|
||||
finished
|
||||
> Say after Flip
|
||||
it says: after Flip
|
||||
finished
|
||||
> dir
|
||||
greet.sbx 211
|
||||
hello.sbx 53
|
||||
Life.sbx 1396
|
||||
Snake.sbx 2164
|
||||
Keys.sbx 664
|
||||
Say.sbx 156
|
||||
Break.sbx 149
|
||||
Grid.sbx 571
|
||||
Press.sbx 872
|
||||
Mode.sbx 48
|
||||
Flip.sbx 173
|
||||
Crash.sbx 632
|
||||
vars.script 50
|
||||
blocks.script 343
|
||||
loops.script 272
|
||||
tune.sbx 306
|
||||
notes.txt 21
|
||||
Apps <dir>
|
||||
hi.script 121
|
||||
bad.script 45
|
||||
plain.script 24
|
||||
cross.script 280
|
||||
nonl.script 38
|
||||
outer.script 376
|
||||
inner.script 44
|
||||
loop.script 35
|
||||
25 files, 1 directory
|
||||
> exit
|
||||
halted
|
||||
Execution halted.
|
||||
[exit 0]
|
||||
@@ -19,7 +19,7 @@ Break.sbx 149
|
||||
Grid.sbx 571
|
||||
Press.sbx 872
|
||||
Mode.sbx 48
|
||||
Flip.sbx 291
|
||||
Flip.sbx 173
|
||||
Crash.sbx 632
|
||||
vars.script 50
|
||||
blocks.script 343
|
||||
|
||||
@@ -105,7 +105,7 @@ Break.sbx 149
|
||||
Grid.sbx 571
|
||||
Press.sbx 872
|
||||
Mode.sbx 48
|
||||
Flip.sbx 291
|
||||
Flip.sbx 173
|
||||
Crash.sbx 632
|
||||
vars.script 50
|
||||
blocks.script 343
|
||||
|
||||
@@ -24,7 +24,7 @@ Break.sbx 149
|
||||
Grid.sbx 571
|
||||
Press.sbx 872
|
||||
Mode.sbx 48
|
||||
Flip.sbx 291
|
||||
Flip.sbx 173
|
||||
Crash.sbx 632
|
||||
vars.script 50
|
||||
blocks.script 343
|
||||
|
||||
@@ -12,7 +12,7 @@ Break.sbx 149
|
||||
Grid.sbx 571
|
||||
Press.sbx 872
|
||||
Mode.sbx 48
|
||||
Flip.sbx 291
|
||||
Flip.sbx 173
|
||||
Crash.sbx 632
|
||||
vars.script 50
|
||||
blocks.script 343
|
||||
|
||||
@@ -10,7 +10,7 @@ Break.sbx 149
|
||||
Grid.sbx 571
|
||||
Press.sbx 872
|
||||
Mode.sbx 48
|
||||
Flip.sbx 291
|
||||
Flip.sbx 173
|
||||
Crash.sbx 632
|
||||
vars.script 50
|
||||
blocks.script 343
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
Say before Flip
|
||||
Flip
|
||||
abSay after Flip
|
||||
dir
|
||||
exit
|
||||
@@ -968,6 +968,15 @@ cosmosStartupBad | CosmOS/Source/cosmos.asm | run | cosmosSta
|
||||
# So this runs a program by name, then Grid, then the same program again. The second one is
|
||||
# the check. dir at the end says the disk is still there to be read.
|
||||
cosmosGrid | CosmOS/Source/cosmos.asm | run | cosmosGrid.in | 60000000 | disks/cosmos.img
|
||||
# ---- The screen nobody is looking at ----
|
||||
#
|
||||
# Flip draws a whole screen into the bank that is not shown. What is checked here is not the
|
||||
# picture - video.sh has that - but the LINE IT PRINTS, which is the thing the program claims
|
||||
# will still be there when it comes back. It was not, twice over: the assembler has no string
|
||||
# escapes, so a "\n" written in a literal printed as two characters; and the program called
|
||||
# osTakeScreen, which restores the screen as it was BEFORE the line was printed and so wiped
|
||||
# out the one thing it was pointing at. A program that damages nothing should not ask.
|
||||
cosmosFlip | CosmOS/Source/cosmos.asm | run | cosmosFlip.in | 60000000 | disks/cosmos.img
|
||||
# Which disk the registers mean. Several disks are one controller with a drive register
|
||||
# rather than several devices, because a port is an immediate byte inside the instruction
|
||||
# that names it and a program cannot compute one. Run with a single disk, so drive 1 is a
|
||||
|
||||
+34
-22
@@ -85,6 +85,21 @@ ASM
|
||||
# bitmap pixel 5 are both address 0x0005. So every write below names the memory it is for,
|
||||
# and there is deliberately no bare poke that picks by address - a helper that guessed would
|
||||
# be right for the tiles and wrong for a picture, silently.
|
||||
# The colour most of a picture is made of. Asked this way rather than by naming a pixel,
|
||||
# because a filled screen is a PATTERN - the font has one blank glyph and it is the space,
|
||||
# whose attribute nibble is nought - and which pixel lands on paper depends on the shape of
|
||||
# whichever character was filled with.
|
||||
commonest() {
|
||||
# commonest <ppm>
|
||||
python3 -c "
|
||||
import collections, sys
|
||||
d = open(sys.argv[1], 'rb').read()
|
||||
px = d[d.index(b'255\n') + 4:]
|
||||
counts = collections.Counter(px[o:o + 3] for o in range(0, len(px), 3))
|
||||
print(counts.most_common(1)[0][0].hex())
|
||||
" "$1" 2>/dev/null || echo none
|
||||
}
|
||||
|
||||
pokeTo() {
|
||||
# pokeTo <bank> <address> <byte>
|
||||
printf ' INIA 0d%d\n OUTA 0xE3\n INIA 0x%02X\n OUTA 0xE4\n INIA 0x%02X\n OUTA 0xE5\n INIA 0x%02X\n OUTA 0xE9\n' \
|
||||
@@ -1014,33 +1029,30 @@ python3 -c "open('$BUILD/flip.keys','wb').write(b'Flip\n' + b'\x00'*3000 + b' '
|
||||
timeout 30 "$EMU" --fast --cycles 200000000 --keyboard "$BUILD/flip.keys" \
|
||||
--screen "$BUILD/flip.ppm" --disk "$ROOT/Tests/build/disks/cosmos.img" \
|
||||
--ram-disk 2048 "$BUILD/cosmos.bin" > "$BUILD/flip.out" 2>&1 || true
|
||||
FLIPPED="$(python3 -c "
|
||||
d = open('$BUILD/flip.ppm', 'rb').read()
|
||||
px = d[d.index(b'255\n') + 4:]
|
||||
print(len({px[o:o + 3] for o in range(0, len(px), 3)}))
|
||||
" 2>/dev/null || echo 0)"
|
||||
[ "$FLIPPED" = "1" ] \
|
||||
&& result ok "a program shows the other screen" "the whole picture is the one it filled" \
|
||||
|| result no "a program shows the other screen" "$FLIPPED colours, not a filled screen"
|
||||
FLIPPED="$(commonest "$BUILD/flip.ppm")"
|
||||
[ "$FLIPPED" = "50c050" ] \
|
||||
&& result ok "a program shows the other screen" "green, which is the paper it filled with" \
|
||||
|| result no "a program shows the other screen" "commonest colour $FLIPPED, not the fill"
|
||||
|
||||
# ---- And the system takes it back ----
|
||||
#
|
||||
# The shell's scrollback, its prompt and every line the person typed are in screen NOUGHT.
|
||||
# A program that exited while showing screen one would hand back a shell drawing perfectly
|
||||
# onto a screen nobody had ever written to - blank, and looking for all the world like the
|
||||
# machine had lost everything. Compared cell by cell against the same session without Flip
|
||||
# in it, which is the same way Grid's restore is checked.
|
||||
python3 -c "open('$BUILD/flipbefore.keys','wb').write(b'dir\n' + b'Say a line to come back to\n' + b'\x00'*200)"
|
||||
python3 -c "open('$BUILD/flipafter.keys','wb').write(b'dir\n' + b'Say a line to come back to\n' + b'Flip\n' + b'\x00'*3000 + b' ' + b'\x00'*3000 + b' ' + b'\x00'*3000)"
|
||||
for phase in flipbefore flipafter; 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
|
||||
BACK="$(python3 "$ROOT/Tests/samescreen.py" "$BUILD/flipbefore.ppm" "$BUILD/flipafter.ppm")"
|
||||
[ "$BACK" = "yes" ] \
|
||||
&& result ok "and the system puts the screen back" "screen nought, with what was on it" \
|
||||
|| result no "and the system puts the screen back" "$BACK"
|
||||
# onto a screen nobody had ever written to, and Flip does exit while flipped - deliberately,
|
||||
# because a program that FAULTED while flipped could not put it back either.
|
||||
#
|
||||
# What says so is a corner of the screen with nothing on it. The map Flip filled is one tile
|
||||
# and one attribute in every cell, so a screen still showing it is that colour EVERYWHERE; a
|
||||
# screen nought that came back is black where nobody has printed. Checking a corner rather
|
||||
# than comparing whole pictures, because Flip's own line is meant to survive on this one and
|
||||
# an equality check would call that a difference.
|
||||
python3 -c "open('$BUILD/flipafter.keys','wb').write(b'Say a line to come back to\n' + b'Flip\n' + b'\x00'*3000 + b' ' + b'\x00'*3000 + b' ' + b'\x00'*3000)"
|
||||
timeout 30 "$EMU" --fast --cycles 200000000 --keyboard "$BUILD/flipafter.keys" \
|
||||
--screen "$BUILD/flipafter.ppm" --disk "$ROOT/Tests/build/disks/cosmos.img" \
|
||||
--ram-disk 2048 "$BUILD/cosmos.bin" > "$BUILD/flipafter.out" 2>&1 || true
|
||||
[ "$(commonest "$BUILD/flipafter.ppm")" = "000000" ] \
|
||||
&& result ok "and the system puts the screen back" "black again, and not the filled screen" \
|
||||
|| result no "and the system puts the screen back" "commonest colour $(commonest "$BUILD/flipafter.ppm")"
|
||||
|
||||
# ---- Clearing puts the cursor back at the top ----
|
||||
#
|
||||
|
||||
Reference in New Issue
Block a user