fee2b1ef1007e3863ae3bc39761d0ec6b416aca8
59
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
b04e4b7d1c |
Finish making the tune a program
The user's conversion, which I reverted while I was working out whether it was half done or broken. It was half done: an sbx application wants its #Include above #Program, because services.asm ends in a #Vectors block and a #Base written after that has no segment to be the base of. So the include moves up, the bases move a page with everything else, and the test starts it from the shell instead of booting it. It plays for 9,469,987 cycles, 9,423,527 of them waiting, which is the same 567 frames of music it played as a boot image. BEING A PROGRAM MEANS ITS VECTOR IS THE SYSTEM'S TO INSTALL. It brings the screen's, so that it has a beat to play to, and CosmOS puts it in when the tune starts and takes it back out when it stops - a thing a boot image never had to have right, and the second program here to exercise the version two format at all. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01E2JrLzFvuFX9fgi1LDRjrW |
||
|
|
fd9c4c75f8 |
Tell the person where it hurts
A fault stopped the machine and printed a line to standard error. On a terminal that is a diagnosis. Behind a window it is a frozen picture and no reason at all, because the message went somewhere nobody was looking - the machine looked hung and was not. It had stopped, and said so invisibly. CosmOS catches all five faults now and says what happened on the screen, with the address, in red. A FAULT ENDS THE PROGRAM, NOT THE MACHINE. That is the answer to "carry on or start again", and it is not a compromise: a bare RETI from most of these meets the instruction that failed and fails again, so carrying on was never on offer. But the machine is almost never what is broken. Everything the shell puts back when a program exits - the Stack, its vectors, the drive, the working directory, the console, the screen - is exactly what wants putting back after one dies, so the handler sets a status and joins handleExit. You are back at the prompt, and the program is recorded as having STOPPED rather than finished, because saying "finished" under a red fault message would be the shell contradicting itself. A fault below where programs load is the system's own, and there is nothing to go back to. That one says so and stops. THE SCREEN GOES BACK TO A MODE TEXT CAN BE SEEN IN, and that is the part that matters rather than the part that is prettiest. A program that faulted in bitmap mode left the console with no text rows, so it draws nothing at all: the message would be perfectly correct and completely invisible, which is the one thing it must never be. Two palette entries go back for the same reason, since a program that wrote its own colours can leave every ink the same as every paper. Only the two the message needs, so the rest of what the program chose is left alone. Both halves are checked by looking at the PICTURE, because the serial line was never where the problem was. Crash blind ruins the palette and drops into bitmap mode before it faults; without the mode the screen comes back 320 by 200 with nothing on it, and without the palette it is the right size with the message present and unreadable. Each break loses the red on its own. Crash is also a program worth having: it breaks in whichever of the five ways you name, so a fault screen can be looked at without having written a bug first. Two things found on the way: The native assembler keeps its OWN copy of the reserved vector names, so it did not know NoHandler or NoDevice and built a cosmos.bin that differed from the host assembler's. Caught by native.sh, which is exactly the drift that test exists for. And cosmosMonitor had dead input. It assembles code into 0x8000 and runs it, and that code faults - which used to kill the machine, so everything after it in the file had never run. It runs now, and the recording grew by sixty lines of monitor session that had been unreachable since the day the fault was put there. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01E2JrLzFvuFX9fgi1LDRjrW |
||
|
|
81e544eb3d |
Load a program that has no data
A five instruction program that writes one port and exits has no Data Segment at all, and the loader stopped the machine dead on it. It asked the memory controller to move a segment of no bytes, and a length of zero asks for the whole 64K - which is the machine's rule, and a reasonable one, since two bytes cannot say 65536 and a transfer of nothing is not usually what anybody meant. It is exactly what was meant here. 64K did not fit, the controller refused, and the load stopped half done. ON A TERMINAL THAT PRINTS A FAULT WITH AN ADDRESS. Behind a window it is a frozen picture and no reason at all, which is how it was found and is a separate problem from this one. The header says how long each segment is, so the loader knows before it asks. Both bytes are already in hand, so the test costs one OR. Nothing is lost by skipping the transfer: a blit leaves the controller's addresses past whatever it touched, and a blit of nothing would have left them where they already are, which is where the vectors are read from next. Guarded for the code segment too. A program with no code is equally assemblable and would have stopped in exactly the same place. Mode.sbx is the fix's test and a program worth having on its own: forty columns or eighty, whichever the screen is not in, which is what a person wanting Snake drawn twice the size actually needs. Ten instructions and no data, deliberately - it prints its two digits a register at a time rather than from a string, so it stays the smallest shape a loadable program can take. Nothing else on that disk had ever been that shape, which is why nothing had ever tried it. Reported by the user, who wrote the program. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01E2JrLzFvuFX9fgi1LDRjrW |
||
|
|
736037462e |
The shell edits the line it is given
Three different things used to do this job, and which one you got depended on where the machine was running. On a terminal the host held the line and did the echoing and the backspacing; behind a window the console's own gatherer did it; from a file nothing did it at all. One job, three implementations, none of them in the system - which is why there was no way to move about in a line and nowhere for a history to live. So editLine does it. Key mode while a line is being read and line mode straight after, so nothing else in the system and no program calling osReadLine notices anything changed. Left and Right, Home and End, Backspace for the character before the cursor and Delete for the one under it, and anything typed goes in where the cursor is with the rest of the line moving along. Ctrl-D means the end of input again, on an empty line, because that was a thing the terminal did while it was holding the line and it is not holding it now. Same trade as the echoing. MOST KEYSTROKES DRAW NOTHING BUT THEMSELVES. A character typed at the end of a line needs no cursor moved: printing it is the whole change, and a backspace there is three ordinary bytes. That matters beyond speed - moving the cursor by hand is what a terminal is TOLD about, in an escape sequence, so redrawing on every keypress would fill every recorded transcript in this suite with them. The line is only reprinted when something happened in the middle of it. Where the line STARTS is worked out backwards from where printing ended, rather than trusted from what was remembered. That is what makes it survive the screen scrolling: a line printed on the bottom row moves everything up by one, and a remembered row would be one too low from then on. The command line holds 127 characters, up from 63. The limit started to be felt the moment a line could be moved about in. 58 recordings changed, and every one of them by the echo. THE PROOF IS NOT A HEURISTIC: a CosmOS built with the echo silenced reproduces 187 of the 188 recordings byte for byte. The one exception is cosmosTyped, the backspace test, where the rub-out marks now come from the shell instead of from the console's gatherer - same marks, different author. cosmosEditKeys is the new test, and every line in it is typed wrong and then corrected with a different key. Its last line is eighty six characters at a prompt in column two on an eighty column screen, so the line runs onto the row below and the shell has to find the start of something it can no longer see; breaking either half of that arithmetic fails it. Also: agree.sh looked for "> the same", anchored to a prompt that no longer precedes what a command prints. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01E2JrLzFvuFX9fgi1LDRjrW |
||
|
|
b3726c950a |
Deliver the keys that are not characters
An arrow key has never reached this machine. Voyager threw it away for want of anywhere to put it, and a terminal sent ESC [ A, which arrived in the middle of whatever was being read and made it unrecognisable - typing Up at the CosmOS prompt put three bytes in the command line and got "I do not know". So the console names them: one byte each, 0x80 upward, above ASCII so nothing written before them can collide. Up, Down, Left, Right, Home, End and forward Delete, with room above for the paging and function keys. The console normalises, which is what it already does. Behind a window it turns the key somebody pressed into a byte; on a terminal it turns the sequence into the same byte. That is the act it has always performed on Return and Backspace, one layer further along, and it is why a program need not know which of the two it is talking to. What a key MEANS is not the console's business - that belongs to whoever is reading, the same way what is on a disk belongs to the system and what a drive is belongs to the machine. Translated only when standard input really is a terminal. Nothing else sends these sequences, a pipe holds exactly the bytes somebody put in it, and it keeps the Escape-or-Up timing problem out of every test here: a test writes the key values themselves. Line mode drops them, in both front ends, because line mode delivers characters and a line somebody else has finished editing cannot be moved about in. Press.sbx says what it was handed, in hexadecimal and by name, and reads a line before it reads keys so both halves of that rule are checked. Two recordings, one fed as standard input and one as a keyboard, agreeing byte for byte; each break fails exactly one of them. Three checks in terminal.sh type real escape sequences at a pseudo-terminal, which is the only place they are ever read as sequences: that they arrive as keys, that Escape alone is still Escape, and that a character typed straight after an escape is held rather than swallowed. Five recordings re-blessed for Press.sbx appearing on the shared disk, and the whole of that diff is the file's own line and the counts above it. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01E2JrLzFvuFX9fgi1LDRjrW |
||
|
|
2a29cebc6b |
Make the screen come back on the machine people actually run
Found by running it: Grid exits and the shell prints its prompt into the grid, with the view up to seven pixels out of alignment. Three faults, and the first is the one that made the other two visible. MAKE RUN-VOYAGER HAD NO SCRATCH DRIVE. It gives drive 1 to Disks/personal.img, which is a file and not volatile, so there was nowhere to keep a screen - osTakeScreen answered no and the whole feature silently did not happen. It was tested with --ram-disk and shipped without one, which is as good a description of testing the wrong machine as I can write. There is now a RAM disk in drive 2, after the personal disk so that drive 1 stays the one that is yours. A PROGRAM TOLD NO MUST COPE. A refusal is not a fault, it means doing what the program did before there was anywhere to save a screen. Grid deleted its own tidying up when it started asking, so being refused left the grid on screen with a prompt written into it. It clears up again when refused, and only then. AND THE SYSTEM ALWAYS LEAVES THE SCREEN USABLE. The fine scroll registers go back to zero at every program exit, whether or not the picture could be saved: the console draws in whole cells, so a view three pixels into one puts every character three pixels out for ever. That is not part of saving a screen and should never have depended on it. Both paths are checked now. With a scratch drive the screen comes back cell for cell; without one, no grid is left behind. Breaking either fails one of them and not the other. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01E2JrLzFvuFX9fgi1LDRjrW |
||
|
|
ab72443b99 |
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
|
||
|
|
e4f4bae762 |
Work across two disks: copy between them, and run a program from one on
files from the other Two things anybody expects of a second disk, and each needed something different. COPYING NEEDED TWO THINGS TO REMEMBER A DRIVE. The write stream is the only thing here that lives across service calls, so it is the only thing whose drive can change underneath it: every osFileBlock names its source path again and goes back to the source drive, and then osFileWrite has to come home. It records the drive it was opened on and returns there. And the file lookup CACHE. It keeps the last path resolved so a reader walking a file does not re-walk the directory for every block - and skipping the walk skipped the drive the path named, so block one of a cross-drive copy read the source's block numbers off the DESTINATION disk. It only showed on files of more than one block, because a file of one is never looked up twice. One block worked and two did not, which is a suspicious enough shape to have suspected sooner. RUNNING A PROGRAM FROM ELSEWHERE NEEDED A THIRD PLACE TO LOOK, and two restorations. The shell tried where you are and /Apps on the disk you are on. It now tries /Apps on drive 0 as well, which is what makes the system's programs work from a disk of your own - one with your files on it and no system, which is most of the point of having a second disk. The drive goes back after the load, because by then the program is in memory and the blocks it came from mean nothing; and again when it exits, because a program that copies between disks moves the drive as its own paths need to and being left wherever it finished is not what was asked for. Copy 1:/a 0:/b now leaves you exactly where you were. The fixture disk grew an /Apps, because it kept its programs at the root and so could not exercise the third place at all. Two hours of the debugging above were spent on a stale disk image. The machine boots the system that is ON the image, so a rebuilt cosmos.bin means nothing until the image is rebuilt too - and the trace said my new code never ran, which was true. Third time this project has been misled by one. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01E2JrLzFvuFX9fgi1LDRjrW |
||
|
|
3b650cabcd |
Grid took the disk's bank number, and gave the screen back untidy
Found by playing with it: after running Grid, the shell could not start anything by name and dir said the disk was empty. Several commands after the program that did it had exited, and nothing had said a word. BANK NUMBERS ARE ONE NAMESPACE FOR THE WHOLE MACHINE. Grid registered video memory as bank 3, which is the number CosmOS gives the disk's buffer when it mounts - and that does not fail, it succeeds. Every read the filesystem made afterwards came out of video memory. Grid uses 4 now, and the CosmOS README has a table of who owns what, because the one place this was written down was a line in a service description about sbfsMount. Nothing hands bank numbers out and nothing refuses one that is taken. If programs start wanting banks routinely, a service that allocates them is what should exist rather than a longer table - noted there rather than built, since one program wanting one bank is not yet a system. Also puts the cursor home on the way out. The map was emptied and the console was not told, so the shell carried on writing from wherever the cursor had been standing when Grid started - twelve rows down a screen with nothing on it. Clearing is what homes a cursor and it costs one write. The regression test runs a program by name, then Grid, then the same program again; the second one is the check. Putting Grid back on bank 3 fails it. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01E2JrLzFvuFX9fgi1LDRjrW |