diff --git a/Programs/CosmOS/README.md b/Programs/CosmOS/README.md index 0fc426f..ec1aef7 100644 --- a/Programs/CosmOS/README.md +++ b/Programs/CosmOS/README.md @@ -776,6 +776,33 @@ cent, where without it the same change costs sixty eight - which is the point: * that reads ahead stops caring very much how fast its disk is.** The three per cent it costs at zero is the bookkeeping, paid when there is nothing to hide behind it. +### And Waiting For What Is Left: + +Read ahead hides most of the wait and cannot hide all of it. What remained was a loop +asking the disk's status port over and over, which is work the machine is doing and memory +it is touching to find out that nothing has happened yet. + +`sbfsWaitDisk` uses `WAIT` now. It tests the status port, and only if the disk is still +busy does it stop - the CPU is put down until a device raises a line, and the disk raises +one when it finishes. **Asking first is what makes it safe:** if the disk finished in the +gap between the test and the `WAIT`, its line is already standing and the `WAIT` does +nothing rather than sleeping through the answer. + +There is no handler and no vector. The shell keeps the Interrupt Flag down, and a `WAIT` +wakes on a line whether or not anybody intends to answer it, taking it down on the way +past. Printing the same fourteen kilobyte file: + +| Cycles a block | Total | Of that, the bus | Waiting | +| -- | -- | -- | -- | +| 0 | 922,570 | 922,570 | 0 | +| 2,000 | 946,474 | 922,702 | 23,772 | +| 10,000 | 1,042,474 | 922,702 | 119,772 | + +**The middle column stops moving.** What the program costs in memory is now the same +whatever the disk does, and the difference is time spent with the bus quiet. On this +emulator that changes nothing anybody can see; on hardware it is the difference between a +CPU contending for memory with everything else and a CPU standing out of the way. + ### Saving Something Twice: Which is why saving a document is not the same as writing a file, and why sbfsSaveFile exists rather than each tool doing it. A file that has grown will usually not fit where it was, so saving it means putting it somewhere else and letting go of where it was - and **the obvious order is a trap**: diff --git a/Programs/CosmOS/Source/sbfs.asm b/Programs/CosmOS/Source/sbfs.asm index 30f6ffe..0044e5d 100644 --- a/Programs/CosmOS/Source/sbfs.asm +++ b/Programs/CosmOS/Source/sbfs.asm @@ -1892,12 +1892,23 @@ sbfsForgetBuffer: ; settled status, and CALL would put A back the way it found it - so the one thing this ; exists to hand over is the one thing an ordinary call cannot carry. Two bytes of Stack ; instead of ten, as well, in a routine that runs on every block the machine ever touches. +; ASKED FIRST, THEN WAITED ON, and that order is the whole of what makes this safe. The +; disk raises its line when it finishes, so if it finished between the test and the WAIT +; the line is already standing and the WAIT does nothing rather than sleeping through the +; answer. Testing after waiting would have exactly the opposite property. +; +; No handler and no vector: the shell keeps the Interrupt Flag down, and a WAIT wakes on a +; line whether or not anybody is going to answer it. It takes the line down on the way +; past, which is what stops the next wait finding this one's line and returning at once. sbfsWaitDisk: INA 0x23 INIB 0x01 AND - BNQ sbfsWaitDisk ; The busy bit is up, so round again. - RRET ; A is the status, with the busy bit down. + BRQ sbfsWaitDone ; The busy bit is down, so there is nothing to wait for. + WAIT + BRI sbfsWaitDisk +sbfsWaitDone: + RRET ; A is the status, with the busy bit down: AND leaves A alone. ; Copies the disk's buffer, a whole block of it, to Data Memory at DP1. sbfsBufferOut: