diff --git a/Programs/CosmOS/Source/cosmos.asm b/Programs/CosmOS/Source/cosmos.asm index ed509aa..64020c8 100644 --- a/Programs/CosmOS/Source/cosmos.asm +++ b/Programs/CosmOS/Source/cosmos.asm @@ -146,6 +146,16 @@ bootStartup: CALL newLine bootReady: + ; ---- Where the Stack is when nothing is happening ---- + ; + ; Taken once, here, and put back at the top of every turn of the loop below. SystemStack is + ; not this: that is taken when a PROGRAM starts, to be given back when it stops, so it + ; holds wherever the shell had got to at that moment - which is the value that needs + ; correcting rather than the one to correct from. + MVSD.0 + SETD.1 ShellStack + STD.0.1 + ; ---- The loop ---- ; ; The shell has two modes and one prompt that says which. Ordinary mode runs programs; @@ -158,6 +168,25 @@ bootReady: ; shell. Only saying so leaves the monitor, or a program breaking the machine badly enough ; to need starting again. prompt: + ; ---- The Stack, back where it was when nothing was happening ---- + ; + ; EVERY FAILURE IN THIS SHELL ABANDONS A FRAME. commandFailed is reached with CALL and + ; never returns: it marks the line and branches here, which is the idiom every command + ; uses and is why a failure needs no unwinding. What it costs is the frame of that call and + ; of everything between here and it - twenty bytes for a name that was never set, more from + ; somewhere deeper - and nothing ever gave them back. Twenty failed lines moved the Stack + ; Pointer from FFFD to FE6D, and it only ever went one way. + ; + ; Nothing had noticed because it takes thousands of failures to reach anything, and nobody + ; types thousands of anything. A loop in a script would. + ; + ; So the loop starts each turn from a known place. This is the second use of MVDS in the + ; system and it earns it for the same reason as the first: a Stack that is right by + ; construction beats one that is right by everybody remembering. + SETD.1 ShellStack + LDD.0.1 + MVDS.0 + ; ---- A script stops at the first line that did not work ---- ; ; Checked here, before the next line is read, because this is the one place every command @@ -7226,6 +7255,9 @@ DumpBytes: ; region a program owns, so that a program has to go looking to break it. SystemStack: 0x00 0x00 +; And where it is when the shell is between lines, which is not the same thing. See prompt. +ShellStack: + 0x00 0x00 DirSeen: 0x00 DirSize: diff --git a/SplitBit Test Manual.md b/SplitBit Test Manual.md index a19d23f..8724b17 100644 --- a/SplitBit Test Manual.md +++ b/SplitBit Test Manual.md @@ -79,7 +79,7 @@ from `make`, not from here. ### 1. Recorded output `Tests/run.sh` assembles each program named in `Tests/manifest`, runs it, and compares -everything it printed against a file in `Tests/expected`. 200 tests, of which 138 run, 35 +everything it printed against a file in `Tests/expected`. 201 tests, of which 139 run, 35 only assemble, 16 are expected to fail to assemble, and 11 boot from ROM with no image given at all. diff --git a/Tests/expected/cosmosStack.out b/Tests/expected/cosmosStack.out new file mode 100644 index 0000000..76580d3 --- /dev/null +++ b/Tests/expected/cosmosStack.out @@ -0,0 +1,47 @@ +CosmOS +> Break +two stops, and what the registers were at each +break at 5016 +A 11 B 22 Q 00 status 00 +DP0 3030 DP1 3000 DP2 3037 DP3 5000 SP FFFF +press a key +break at 5034 +A 44 B 55 Q 00 status 00 +DP0 3000 DP1 3037 DP2 3030 DP3 5000 SP FFF5 +press a key +carried on to the end +finished +> ho $nope +nothing is set called nope +> echo $nope +nothing is set called nope +> echo $nope +nothing is set called nope +> echo $nope +nothing is set called nope +> echo $nope +nothing is set called nope +> echo $nope +nothing is set called nope +> echo $nope +nothing is set called nope +> echo $nope +nothing is set called nope +> Break +two stops, and what the registers were at each +break at 5016 +A 11 B 22 Q 00 status 00 +DP0 3030 DP1 3000 DP2 3037 DP3 5000 SP FFFF +press a key +break at 5034 +A 44 B 55 Q 00 status 00 +DP0 3000 DP1 3037 DP2 3030 DP3 5000 SP FFF5 +press a key +carried on to the end +finished +> it +I do not know: it +> +halted +Execution halted. +[exit 0] diff --git a/Tests/input/cosmosStack.in b/Tests/input/cosmosStack.in new file mode 100644 index 0000000..ba73f26 --- /dev/null +++ b/Tests/input/cosmosStack.in @@ -0,0 +1,11 @@ +Break +echo $nope +echo $nope +echo $nope +echo $nope +echo $nope +echo $nope +echo $nope +echo $nope +Break +exit diff --git a/Tests/manifest b/Tests/manifest index cf1d7e1..02a1d38 100644 --- a/Tests/manifest +++ b/Tests/manifest @@ -414,6 +414,17 @@ cosmosTabPath | CosmOS/Source/cosmos.asm | run | cosmosTab # refusing. Somebody who wants an empty value writes "set name" and gets one - the escape # hatch exists and has to be asked for. cosmosVars | CosmOS/Source/cosmos.asm | run | cosmosVars.in | - | disks/cosmos.img +# The Stack is where it was, after eight lines that failed. +# +# EVERY FAILURE IN THIS SHELL ABANDONS A FRAME: commandFailed is reached with CALL and never +# returns, which is the idiom every command uses and is why a failure needs no unwinding. +# Nothing gave those frames back, so the Stack Pointer only ever moved one way - FFFD to FE6D +# over twenty failures. It took thousands to reach anything, which is why nobody had noticed; +# a loop in a script would have got there. +# +# Break is what makes it visible, because it prints the registers. The two dumps have to +# agree, and the failures between them are what would move it. +cosmosStack | CosmOS/Source/cosmos.asm | run | cosmosStack.in | - | disks/cosmos.img # The same editing offered to a PROGRAM, through osReadLine. Edit reads its lines that way, # so a word typed with two letters the wrong way round is put right without starting the line # again - which is the whole of what A4 buys.