; The services the system offers, named and numbered. ; ; Both sides include this. The system follows it with handlers for the ones it implements. ; A program that only calls them includes this and nothing else, and can then say them by ; name, because a line with a name and nothing after it declares what a vector is called ; and what number it has without claiming to implement it. ; ; THE NUMBERS ARE WRITTEN DOWN HERE, and that is the only place they are written. They ; used to be decided by the order of the lines, which worked and was quietly fragile: a ; service inserted in the middle renumbered everything after it, and a program already ; assembled against the old numbers would go on calling the number rather than the name. ; Worse, the numbers a program got for its OWN traps moved depending on whether it had ; included this file, and a program that had not was given 16 - which is osPrintString. ; ; So these are pinned. They come from the range set aside for numbers that two separately ; assembled programs have to agree about; everything a program names for itself is drawn ; from higher up and cannot collide with these however it is built. Adding a service takes ; the next free number here and disturbs nothing. ; ; Written by Anachronaut #Vectors osPrintString 0d16 ; DP0 names a string. Prints it. osReadLine 0d17 ; DP0 names somewhere to put a line read from the console. osExit 0d18 ; Give the machine back to the system. osArgument 0d19 ; DP0 names somewhere to put the rest of the run command. ; ---- What the system does with the disk on a program's behalf ---- ; ; A loaded program that wanted a file used to include the whole filesystem, which is two ; and a half kilobytes of it carrying a private copy of code the system already has ; running. These are that code, reachable. ; ; NOTHING HERE MOUNTS ANYTHING. The system mounted the disk before it read the prompt, and ; there is one disk with one buffer registered as one bank; a program mounting it again was ; only ever an artefact of having its own copy of the library. ; ; Sizes are in bytes and fit the registers exactly. A file that can be read into Data ; Memory is under 64K by definition, so its length is sixteen bits: coming back it is DP3, ; going out it is A and B together, and neither direction needs a record in memory that ; both sides have to agree on the shape of. osFileRead 0d20 ; DP0 names it, DP1 says where. Q is zero if it read, DP3 is how many bytes. osFileSave 0d21 ; DP0 names it, DP1 is the bytes, A and B are how many. Q is zero if it saved. osFileDelete 0d22 ; DP0 names it. Q is zero if it went. osFileRename 0d23 ; DP0 is the name it has, DP1 the name it should have. Q is zero if it moved. ; ---- Reading a file that will not fit ---- ; ; osFileRead answers with a whole file in Data Memory, which settles it for anything under ; 64K and settles nothing above. These two are the other way of asking: how big is it, and ; then give me one block of it at a time. Nothing is kept between the calls but the number ; of the block wanted, so there is no handle to open, none to close, and nothing left ; behind by a program that stops in the middle. The system remembers where the last file it ; was asked about lives, so asking for four hundred blocks of one file costs one search of ; the directory rather than four hundred; that is a speed, not a promise, and a caller ; never has to know about it. ; ; THESE TWO SAY WHY WHEN THE ANSWER IS NO, which the others do not. Everywhere else the ; only useful thing to do about a failure is to give up, so one value is enough. These ; exist to be asked questions with - is it there, is there any more of it - and the ; difference between "no disk", "no such file" and "that was the last block" is the answer ; rather than an excuse. ; ; 1 there is no disk ; 2 there is no file of that name ; 3 that block is past the end of the file (osFileBlock only) ; 4 the disk would not read it (osFileBlock only) osFileInfo 0d26 ; DP0 names it. Q is zero if it is there, DP3 is how many blocks. osFileBlock 0d27 ; DP0 names it, DP1 says where, A and B are which block from zero. ; ---- Moving about ---- ; ; DP0 names a directory. Q is zero if the machine is now in it. ; ; WHAT A PROGRAM CHANGES HERE, THE SHELL PUTS BACK when the program stops - the same ; discipline the Stack and the vector table are held to, and for the same reason. A program ; is entitled to move about; the shell is entitled to find itself where it left off. ; ; This is what makes a bare name mean something to a program: everything a program opens is ; relative to here, so a program given a directory to work in can say "notes.txt" and mean ; the one in it. osChangeDir 0d28 ; ---- Writing a file a block at a time ---- ; ; The mirror of osFileInfo and osFileBlock, and the way to write something too big to hold ; in memory. osFileSave stays for a whole document handed over at once, which is what a ; text editor has and what most programs want. ; ; ONE WRITE IS OPEN AT A TIME AND THE SYSTEM HOLDS IT. Reading needs no state - a name and ; an index are the whole question - but writing safely does, because the new file has to ; exist before the old one is thrown away and something must remember which temporary ; belongs to which name. Keeping that here means the careful order is written once instead ; of in every program that streams. ; ; Nothing that already exists is touched until osFileDone, so a disk without room says so ; while the old file is still there. ; ; osFileStart is told the size the way an entry holds one, blocks and a tail, rather than a ; count of bytes - so it reaches the whole disk. osFileSave is handed a byte count in two ; registers and cannot write more than 65,535. osFileStart 0d29 ; DP0 names it, DP3 is whole blocks, A is bytes in the tail. osFileWrite 0d30 ; DP1 is the block, A and B together are which one, from zero. osFileDone 0d31 ; DP3 is whole blocks and A the tail: how big it turned out to be. osFileFetch 0d32 ; DP1 is where it goes, A and B are which block. Reads one back. ; osFileFetch is what lets a program keep only ONE block of a file in hand while writing ; it. Anything producing two parts of a file at once - an assembler, whose source says ; #Program and #Data in whatever order it likes - has to be able to put a block down, go ; and write somewhere else, and pick it up again where it left off. ; Q is zero if it read, DP3 is how many of its bytes are the file's: ; a whole 0d256 except in a last block that is short. That count is ; why DP3 answers and not a register - 0d256 does not fit in a byte, ; and a count that lied about a full block would make every reader ; treat the end of a file as a special case. ; ---- And with the console ---- ; ; printString is already up there. This is the other half of what a program prints: a ; number, in decimal, without leading zeroes. A and B together, so one service covers both ; a line number and a byte count and there is no need for two. osPrintNumber 0d24 ; ---- Stopping to look ---- ; ; A breakpoint. Put SWI osBreak anywhere in a program and the system shows every register as ; the program had them, waits for a key, and carries on. ; ; NOTHING IS OVERWRITTEN, which is what makes this simple. A breakpoint that replaced an ; instruction would have to put it back to continue, and putting it back disarms the ; breakpoint - so firing twice would need the instruction to be stepped over and the ; breakpoint replaced behind it, and this machine has no way to step one instruction. An SWI ; costs two bytes of the program and fires for ever, because there was never anything to ; restore. The price is that it is part of the program: a build with breakpoints in it has ; different addresses from one without. osBreak 0d25 ; ---- How the last start went ---- ; ; The loader marks the disk before it hands over and the system clears the mark on reaching ; its prompt, so a mark still set is a start that never arrived. See the boot state in ; sbfs.h for what the numbers mean. ; ; osBootState answers in Q: 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. ; ; THE ONLY WRITE A PROGRAM GETS IS SETTLING. 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 has no way to check. osBootState 0d33 osBootSettle 0d34 ; ---- What a program made of it ---- ; ; osExit takes a status in A: zero if the program did what it was asked, and a number of ; its own choosing if it did not. IN A RATHER THAN Q, which is not a departure from the ; rule that a service answers in Q - this one takes an argument, the way osPrintNumber ; does, and never returns to answer anything. A is free precisely because a return would ; have put it back, and Q is the ALU's output, so a small number costs four instructions ; there and one in A. ; ; osLastStatus answers in Q with what the last program exited with. The shell does not ; 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. osLastStatus 0d35