CosmOS knows about all four drives

A mounted disk is EIGHT BYTES - where its directory starts, how many
blocks it is, how big the disk is, and where you are on it. They now sit
together in the data segment, and changing drives is one copy out and one
copy in. The other three thousand lines of filesystem go on reading the
same four names they always have and never learn there is more than one
disk, which is the whole reason this was affordable.

The version is not in the record. It is checked at mount and thrown away,
because a version one disk's zero parent already reads as "in the root".

Every drive is mounted at boot: the controller says how many are plugged
in and each is tried in turn. One with nothing in it, or a disk this
cannot read, is left unmounted rather than stopping the others, so a
machine with a good disk in drive 0 and a blank in drive 1 starts.

'drive' says which one, 'drive 1' goes to another, and the working
directory goes with it - where you are on a disk is part of which disk you
are on. A drive the machine has not got is refused, and refused
differently from one that is there with nothing readable in it.

Three things the assembly caught me on, all the same misunderstanding of
what survives a call:

  - OR reads A and B, and the bit came back from sbfsDriveBit in Q, which
    RET does not disturb - but RET does put A back. The mounted mask never
    got set and drive 0 was reported unmountable.
  - MVQA then RSTA throws away the copy it just made, so doubling a bit
    doubled nothing. SHL does it in one instruction, because A and B are
    one register to it.
  - There is no move from A to B. INB reads a port straight into B, which
    is what the drive count comparison wanted.

run.sh takes more than one image now, separated by a plus, since the
machine has four drives and a test that could only name one could not
check any of this.

The buffer note is forgotten on a drive change and that is DELIBERATELY
kept although nothing can currently reach it: only the file read-ahead
consults it, a directory scan does not, and finding a file requires a
scan which overwrites the note on the way past. Two disks were built with
the same file at the same block to try to catch it and the answer was
right either way. Three instructions to hold an invariant rather than a
story about a bug - and the comment says so instead of claiming a fix.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01E2JrLzFvuFX9fgi1LDRjrW
This commit is contained in:
Anachronaut
2026-08-31 12:30:09 -04:00
co-authored by Claude Opus 5
parent b1538e0618
commit 5644c24113
9 changed files with 435 additions and 10 deletions
+27
View File
@@ -0,0 +1,27 @@
CosmOS
> 0
> 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
hi.script 121
bad.script 45
plain.script 24
cross.script 280
nonl.script 38
outer.script 376
inner.script 44
loop.script 35
17 files
> > other.txt 28
notes <dir>
1 file, 1 directory
> /notes> > /notes> > /notes> drive: this machine has no such drive
/notes> halted
Execution halted.
[exit 0]
+11
View File
@@ -0,0 +1,11 @@
drive
dir
drive 1
dir
cd /notes
drive 0
drive 1
drive 0
drive 1
drive 3
exit
+10
View File
@@ -115,6 +115,16 @@ for i in 1 2 3 4 5 6 7 8; do "$TOOL" put "$DISKS/sbfs.img" "filler$i.txt" >/dev/
printf 'this is not a program' > notes.txt
"$TOOL" put "$DISKS/cosmos.img" notes.txt >/dev/null
# ---- A second disk, for the second drive ----
#
# Deliberately nothing like the first: its own file and its own directory, so that a test
# looking at one cannot be looking at the other by accident. Small, because what is on it
# matters and how much does not.
"$TOOL" format "$DISKS/other.img" 512 4 >/dev/null
printf 'this lives on the other disk' > other.txt
"$TOOL" put "$DISKS/other.img" other.txt >/dev/null
"$TOOL" mkdir "$DISKS/other.img" /notes >/dev/null
# ---- Scripts, including the ones that are meant to go wrong ----
#
# Built here rather than committed, because two of them are about BYTE POSITIONS and a
+12
View File
@@ -808,6 +808,18 @@ cosmosGrid | CosmOS/Source/cosmos.asm | run | cosmosGri
# drive that exists with nothing in it - selectable, and failing to read, like an empty
# floppy drive.
driveSelectTest | testPrograms/driveSelectTest.asm | run | - | 200000 | disks/sbfs.img
# ---- Two disks ----
#
# The first thing on this machine to have more than one. drive says which, and going to the
# other shows a disk with nothing in common with the first - so a listing that looked right
# could not have come from the wrong one.
#
# THE WORKING DIRECTORY GOES WITH THE DRIVE, which is the whole point of the mount record.
# Drive 1 is left standing in /notes and drive 0 at the root, and the prompt says which on
# every trip between them - three times each way, because a record that is copied one way
# and not the other would still look right once. A drive this machine has not got is
# refused.
cosmosDrives | CosmOS/Source/cosmos.asm | run | cosmosDrives.in | 60000000 | disks/cosmos.img+disks/other.img
printDecimalTest | testPrograms/printDecimalTest.asm | xfail | - | -
printDigitTest | testPrograms/printDigitTest.asm | xfail | - | -
printHexTest | testPrograms/printHexTest.asm | xfail | - | -
+10 -3
View File
@@ -251,10 +251,16 @@ while IFS='|' read -r name src mode stdin limit disk keys; do
# A disk starts fresh for every run, so a test cannot pass because of what a
# previous one left lying on it. The emulator makes the image if it is
# missing, which is what removing it first arranges for.
if [ "$disk" != "-" ]; then
# ---- More than one, separated by a plus ----
#
# The machine has four drives, so a test may name up to four images and they
# become drives 0 upwards in the order written. Each keeps its own :ro and @N,
# because those are properties of a disk rather than of the machine.
for onedisk in ${disk//+/ }; do
if [ "$onedisk" != "-" ]; then
# A trailing :ro attaches the image write protected, so that a test can
# check the device bars writes rather than the filesystem asking nicely.
DISKFILE="${disk%:ro}"
DISKFILE="${onedisk%:ro}"
# And a trailing @N gives the disk a latency, so that a test can check the
# filesystem waits for it. Every other test runs with the answer there
# before the next instruction, which is the one condition under which not
@@ -273,8 +279,9 @@ while IFS='|' read -r name src mode stdin limit disk keys; do
esac
EMUARGS+=(--disk "$BUILD/$DISKFILE")
[ -n "$DISKWAIT" ] && EMUARGS+=(--disk-cycles "$DISKWAIT")
case "$disk" in *:ro) EMUARGS+=(--write-protect) ;; esac
case "$onedisk" in *:ro) EMUARGS+=(--write-protect) ;; esac
fi
done
# A rom test names no image. The emulator then shadows its built in stage
# one into Program Memory and reads the disk for everything else, which is
# what a machine with no debugger attached does.