diff --git a/Programs/CosmOS/README.md b/Programs/CosmOS/README.md index ebb2e4f..b839084 100644 --- a/Programs/CosmOS/README.md +++ b/Programs/CosmOS/README.md @@ -836,10 +836,28 @@ tells the two apart. `2things` is a directory; `2:` is a drive. A drive the machine cannot read makes the whole path unfindable, and says so as `no such file` - which it is, since there is nowhere for the rest of it to be. -**Copying between two disks is still not one command.** Each path resolves on its own drive -and the drive stays where the last path left it, so a copy would read from one and write to -the other with only one of them selected. That wants the copy itself to change drives between -blocks, which is a change to `Copy` rather than to paths. +**Copying between two disks is one command**: `Copy 1:/notes.txt 0:/keep.txt`. Every +`osFileBlock` names its path again and so goes back to the source drive; the write stream +remembers the drive it was opened on and returns there for each block. Between them the copy +walks back and forth without `Copy` itself knowing there is more than one disk. + +### Where A Program Is Looked For: + +Three places, tried in order: + +1. Where you are. +2. `/Apps` on the disk you are on. +3. `/Apps` on drive 0. + +The first makes a program you are working on the one that runs. The second makes `Snake` work +from any directory. **The third 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. + +**Fetching a program does not move you, and neither does running one.** The drive is put back +after the load, because by then the program is in memory and the block numbers it came from +mean nothing; and put back again when the program exits, because a program that copies between +two disks moves the drive as its own paths need it to and being left wherever it finished is +not what anybody asked for. So `Copy 1:/a 0:/b` leaves you exactly where you were. ### Bank Numbers Are One Namespace: diff --git a/Programs/CosmOS/Source/cosmos.asm b/Programs/CosmOS/Source/cosmos.asm index c6931f8..6124339 100644 --- a/Programs/CosmOS/Source/cosmos.asm +++ b/Programs/CosmOS/Source/cosmos.asm @@ -437,14 +437,24 @@ promptUnknown: LDA.0 BRA promptSayUnknown ; No filesystem, so there is nothing to look through. - ; TWO PLACES, TRIED IN ORDER: where you are, and then the system's own place for - ; programs. The first is what makes a program you are working on the one that runs; the - ; second is what makes Snake work from anywhere without a copy of it in every directory. - ; Neither is stored anywhere, so there is nothing to configure and nothing to go stale. + ; THREE PLACES, TRIED IN ORDER: where you are, the system's own place for programs on the + ; disk you are on, and then that same place on drive 0. The first is what makes a program + ; you are working on the one that runs; the second is what makes Snake work from anywhere + ; without a copy of it in every directory; the third is what makes it work from a disk of + ; your own, which has your files on it and no system. + ; + ; None of them is stored anywhere, so there is nothing to configure and nothing to go + ; stale. RSTA SETD.0 NamePrefix STA.0 + ; Where the person is, kept so it can be given back. A program is fetched from wherever it + ; lives and then runs on the files of whoever ran it. + INA 0x24 + SETD.0 SearchDrive + STA.0 + promptSearch: CALL nameProgram SETD.0 NameOk @@ -454,7 +464,22 @@ promptSearch: CALL loadProgram SETD.0 LoadStatus LDA.0 - BRA runLoaded ; It loaded, and the machine is its now. + BNA promptNotLoaded + + ; ---- Loaded, so the drive goes back to the person ---- + ; + ; The program is in memory now and the block numbers it came from mean nothing any more, + ; which is what makes this safe here and not in the middle of a path. A program fetched + ; from the system disk then runs on the disk its user was standing on - which is the whole + ; point of being able to keep a disk of your own. + SETD.0 SearchDrive + LDA.0 + CALL sbfsUse + BRI runLoaded ; It loaded, and the machine is its now. + +promptNotLoaded: + SETD.0 LoadStatus + LDA.0 ; No file of that name is not a fault. It is the ordinary case of a word this shell does ; not know, and it is the only answer worth looking somewhere else for. Anything else @@ -467,10 +492,13 @@ promptSearch: BNQ loadFailed promptElsewhere: - ; Was that already the second place? + ; Was that the last place there is? SETD.0 NamePrefix LDA.0 - BNA promptSayUnknown + INIB 0d2 + CCF + SUB + BRQ promptGaveUp ; A word beginning with a separator has said where to look, and looking somewhere else ; would be answering a different question from the one asked. @@ -481,11 +509,19 @@ promptElsewhere: SUB BRQ promptSayUnknown - INIA 0x01 SETD.0 NamePrefix + LDA.0 + INCA STA.0 BRI promptSearch +promptGaveUp: + ; Every place has been tried, and the drive is put back before anybody is told anything: + ; the search moved it, and a word the shell does not know should not move somebody either. + SETD.0 SearchDrive + LDA.0 + CALL sbfsUse + promptSayUnknown: ; Saying which word was not understood is worth the four instructions: it tells somebody ; who mistyped what they actually typed. @@ -760,7 +796,15 @@ nameProgram: SETD.0 NamePrefix LDA.0 BRA nameFromLine + ; One is the system's place on this disk; two is the same place on drive 0. + INIB 0d2 + CCF + SUB + BRQ nameSystemApps SETD.0 AppsPrefix + BRI namePrefixCopy +nameSystemApps: + SETD.0 SystemAppsPrefix namePrefixCopy: LDA.0 BRA nameFromLine @@ -1789,6 +1833,13 @@ scriptNoName: SETD.0 ScriptUsage BRI fileComplain +; Where the person was standing when a program was started, so it can be given back when the +; program has finished with the machine. A program that copies between two disks moves the +; drive as its own paths need it to; that is its business, and being left on the disk it +; happened to finish with is not what the person asked for. +; +; SET WHEREVER A PROGRAM STARTS, of which there are two: run, and typing a program's name. +; Restored in handleExit, which is the one place they both come back through. ; ---- run ---- ; ; Hands the machine to whatever was loaded. Where the Stack is now is written down first, @@ -1805,6 +1856,9 @@ doRun: ; program's own name it is what followed the name, which is the same thing meaning the ; same thing. runLoaded: + INA 0x24 + SETD.0 RunDrive + STA.0 MVSD.0 SETD.1 SystemStack STD.0.1 @@ -2151,9 +2205,20 @@ fileLookup: CALL textSame BNQ fileLookupSearch - ; The same file as last time. The description still has to be put back, because anything - ; that went to the disk in between - a directory listing, a program being loaded - left - ; its own answer in those three. + ; ---- The same file as last time, and possibly not the same disk ---- + ; + ; The description has to be put back, because anything that went to the disk in between - a + ; directory listing, a program being loaded - left its own answer in those three. + ; + ; AND THE DRIVE WITH IT. Skipping the walk skips the drive the path named, so a cache hit + ; on a machine that had moved read the right block numbers off the wrong disk. Copying + ; between two disks is exactly that: block 0 walks and goes to the source, the write goes to + ; the destination, and block 1 hits this cache. It only showed on files of more than one + ; block, because a file of one is never looked up twice. + SETD.0 FileCacheDrive + LDA.0 + CALL sbfsUse + SETD.0 SbfsFileStart SETD.2 FileCacheStart CALL sbfsSetWord @@ -2196,6 +2261,14 @@ fileLookupSearch: SETD.0 FileCacheTail STA.0 + ; ---- And which disk those block numbers are on ---- + ; + ; A start block means nothing without it. The walk above went to whatever drive the path + ; named, so the answer is the drive now. + INA 0x24 + SETD.0 FileCacheDrive + STA.0 + ; Marked good last, so that a cache half filled is never a cache believed. INIA 0d1 SETD.0 FileCacheValid @@ -2622,6 +2695,13 @@ handleExit: SETD.1 LastStatus STA.1 + ; The drive the person was on, whatever the program did with it. + PSHA + SETD.1 RunDrive + LDA.1 + CALL sbfsUse + POPA + ; And the line that started it failed, if the program says it did. The script reader asks ; one question - did this line work - and a program answering "no" is one of the ways it ; can be answered. @@ -3831,6 +3911,8 @@ Separator: ; next, and there is no such place yet. AppsPrefix: "/Apps/" +SystemAppsPrefix: +"0:/Apps/" IsDirectory: "that is a directory" AndText: @@ -4106,6 +4188,12 @@ PrintNumber: ; ; The name is twenty three bytes for a name of twenty two, so that a name filling the ; field still has a zero after it and can be compared as a string. +FileCacheDrive: + 0x00 +SearchDrive: + 0x00 +RunDrive: + 0x00 FileCacheValid: 0x00 FileCacheName: diff --git a/Programs/CosmOS/Source/sbfs.asm b/Programs/CosmOS/Source/sbfs.asm index 0f9b5e6..35d5d99 100644 --- a/Programs/CosmOS/Source/sbfs.asm +++ b/Programs/CosmOS/Source/sbfs.asm @@ -2932,6 +2932,16 @@ sbfsStreamNoTemp: SETD.2 SbfsFileStart CALL sbfsSetWord + ; ---- And which disk all of that is on ---- + ; + ; A write stream is the one thing here that lives across service calls, so it is the one + ; thing that can have the drive changed underneath it. Copying between two disks is exactly + ; that: every osFileBlock re-resolves the SOURCE path and goes to its drive, and then + ; osFileWrite has to come back here. The path was walked above, so the drive is right now. + INA 0x24 + SETD.0 SbfsStreamDrive + STA.0 + INIA 0x01 SETD.0 SbfsStreamOpen STA.0 @@ -2941,6 +2951,13 @@ sbfsStreamNoTemp: ADD RET +; Back to the disk the open stream belongs to, whatever has been read in between. +sbfsStreamHere: + SETD.0 SbfsStreamDrive + LDA.0 + CALL sbfsUse + RET + sbfsStreamNo: RSTA INIB 0d1 @@ -2954,6 +2971,7 @@ sbfsStreamWrite: SETD.0 SbfsStreamOpen LDA.0 BRA sbfsStreamNo + CALL sbfsStreamHere ; Where the file is and how big it is, said again rather than looked up: all three were ; settled when the temporary was made, and everything since has been describing whatever @@ -2980,6 +2998,7 @@ sbfsStreamFetch: SETD.0 SbfsStreamOpen LDA.0 BRA sbfsStreamNo + CALL sbfsStreamHere SETD.0 SbfsStreamTo STD.1.0 @@ -3016,6 +3035,7 @@ sbfsStreamDone: SETD.0 SbfsStreamOpen LDA.0 BRA sbfsStreamNo + CALL sbfsStreamHere ; What it really came to, put aside before anything walks the disk. SETD.0 SbfsStreamNewBlocks @@ -3639,6 +3659,8 @@ SbfsTempName: "sbfs.part" ; ---- What a file being written a block at a time keeps ---- +SbfsStreamDrive: + 0x00 SbfsStreamOpen: 0x00 SbfsStreamPath: diff --git a/SplitBit Test Manual.md b/SplitBit Test Manual.md index 250b27e..0848619 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`. 181 tests, of which 119 run, 35 +everything it printed against a file in `Tests/expected`. 182 tests, of which 120 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/cosmosCrossDisk.out b/Tests/expected/cosmosCrossDisk.out new file mode 100644 index 0000000..77d9c60 --- /dev/null +++ b/Tests/expected/cosmosCrossDisk.out @@ -0,0 +1,30 @@ +CosmOS +> > copied +finished +> 1 +> it says: from drive one +finished +> 1 +> > greet.sbx 211 +hello.sbx 53 +Life.sbx 1396 +Snake.sbx 2164 +Keys.sbx 664 +Say.sbx 156 +Break.sbx 149 +Grid.sbx 543 +notes.txt 21 +Apps