S2: the assembler writes the file as it makes it

The output image is gone. It was eighteen kilobytes and it is now one block of
window, because the file was always produced in order and only ever needed to
be written that way.

Everything works in FILE OFFSETS now. A cursor is a two byte number counting
from the front of the file, and since a block is two hundred and fifty six
bytes, the block it lands in is the offset's high byte and the place within that
block is its low one - so there is no division anywhere, and ImgWalk, ProgPut
and DataPut needed no change but where they start.

ONE WINDOW RATHER THAN THREE. The plan said three: one per segment, and a third
for the block where the program ends and the data begins, which belongs to both.
Fetching a block back instead makes all of that one case. The header is patched
after every byte is out, the boundary block is written by both cursors, and both
are simply revisits - a revisit is what fetching handles. osFileFetch is the
service that allows it, and is the read side of the write.

A run of bytes in one segment costs nothing extra; a switch between segments
costs two block operations, and a source file has a few dozen switches and
several thousand bytes.

Two bugs, both a pointer meaning two things:

putAt took the cursor to advance in DP2 and then wanted DP2 for the window's
address. A call puts DP2 back the way it was AT THE CALL, so the step at the end
moved whatever the last call had left there - the window walked off across
memory while the cursor stood still. It goes in memory now, like the block did
in S1, and for the same reason.

The size the file is created at could not be right. How many vectors are
actually installed is not known until the second pass has resolved their
handlers, and by then the file must already exist to be written into - so Keys,
which brings one vector, came out four bytes short. Teaching the first pass to
count them meant teaching it about devices, and about a Boot line in a loadable
program not being installed at all, which is two ways to disagree with the
second pass about what a file contains.

So osFileDone is told the size instead. A writer asks for as much as the file
could possibly come to - the whole of it plus four bytes for every vector
DECLARED, which no file can exceed - and says what it really came to at the end.
The blocks it did not use go back to the free count. Asking for too much costs a
moment; asking for too little writes off the end of a file.

That is a better service for it, not a workaround. A writer that cannot know its
size until the last byte is the ordinary case, and it is exactly the case this
whole rung exists for.

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-25 16:58:17 -04:00
co-authored by Claude Opus 5
parent 9f7dffdeca
commit fb7b224bbb
8 changed files with 505 additions and 46 deletions
+13 -6
View File
@@ -17,7 +17,8 @@
;
; 0x4000 6144 the label index, 1536 entries of four
; 0x5800 16384 the label names, packed end to end
; 0x9800 18432 the output file being built
; 0x9800 256 one block of the output file, on its way to the disk
; 0x9900 18176 free
; 0xE000 1792 the vector names, 64 entries of twenty eight
; 0xE700 2048 the reader's stack, six levels of 301
; 0xEF00 368 which files have been included, sixteen names of 23
@@ -43,10 +44,16 @@
; index doubled, and the output given what is left, which is still four and a half thousand
; bytes more than CosmOS needs today.
;
; The output's share is temporary. It exists only because the assembler holds a whole
; finished file in memory before writing it, and that is the next thing to go - the file is
; produced in order and could be written as it is made, which would leave this needing three
; blocks rather than eighteen kilobytes.
; THE OUTPUT IS NO LONGER HELD AT ALL. It used to be built whole in memory and handed over
; at the end, which is what made a buffer of eighteen kilobytes the largest thing this
; machine could assemble. The file is produced in order, so it is written as it is made,
; through one block of window - and the eighteen kilobytes that were its share are free.
;
; What to do with them is not obvious and does not have to be decided today. Nothing here
; is close to full: the names are at half, the index at a third, and the output has no
; ceiling of its own any more. Leaving the room unclaimed is better than sharing it out
; among buffers that do not need it, because an unclaimed page is available to whichever
; one turns out to want it.
;
; That ends at 0xF070, with the Stack coming down from 0xFFFF above it - nearly four
; kilobytes, against the tens of bytes of CALL frames this ever nests.
@@ -65,7 +72,7 @@ ScratchLabIndex:
0x40 0x00
ScratchLabArena:
0x58 0x00
ScratchImage:
ScratchWindow:
0x98 0x00
ScratchVecNames:
0xE0 0x00