The host node starts in its ROM (entry 12), and the boot feeds it the system's source through the console: capsules/v4/sys/map-64.f18, the fourteen .f18 blobs and end.f18, each found, hash-checked and signature-checked as any capsule, then EOT. The ROM assembles the system and starts it at (IDLE); the host reads the image record (v4_image_from_node) for what only the assembled system knows. A ROM error is reported with its blob, line and meaning, then PARITY:FAIL. Deleted: v4/tools/mkimage.c, capsules/v4/nucleus-64.f18, v4/capsule/*.v4, v4/tools/v4tof18.py. The .f18 files are the source now. - text.c speaks the rest of the ROM's language (set, here, store, start; v4_text_value, v4_text_start), so the oracle reads the same source: test_host_rom_nucleus compares the ROM against text.c on the .f18 files, word for word, image record included. Host tests load the .f18 files. - mkmap image writes v4_map_image (the map's description of the system); hosted and the kernel link the ROM and the map instead of v4_image_64.c. - Hera (Captain Bob's ruling, option 1): births stream the system the ROM assembled, as assembled code; hera.4th is unchanged. test_host_unit's host builds the system with the ROM. - New parity lines: PARITY:V4_F18 per blob, PARITY:V4_ROM words=2049 rom_hash=0xa6c792b5821010b7 instructions=60725216. Acceptance: amd64, aarch64, riscv64 boot to ok> with PARITY:V4_POST tests=538 pass=538 fail=0, POST: PASSED, and PARITY:V4_SYSTEM word_count=317 dict_hash=0xe5a57f3eb72ff94a on all three -- the same hash as the prebuilt nucleus gave. make -C v4 test test-32 hosted-check: all pass. Logs: logs/20261015-141648, -141938, -142350. Startup cost under QEMU TCG, the ROM's assembly (last V4_F18 line to V4_ROM): amd64 26.7 s of 132 s to ok>; aarch64 41.0 s of 195 s; riscv64 20.5 s of 101 s. Hosted native: +0.85 s. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
128 lines
5.9 KiB
Plaintext
128 lines
5.9 KiB
Plaintext
\ blocks.f18 -- mass storage: blocks of 1024 characters, and text loaded from them.
|
|
\
|
|
\ DECOMPOSITION.md 5.11, FORTH-79: BLOCK BUFFER UPDATE SAVE-BUFFERS
|
|
\ EMPTY-BUFFERS LIST LOAD SCR BLK, and v3's FLUSH THRU and --> . Part of the
|
|
\ compiler capsule; rests on everything before it.
|
|
\
|
|
\ STORAGE IS THE KERNEL'S (docs/v4.0.0/MESH.md section 8, ENGINE.md 3.3), as
|
|
\ it is for a v3 VM. A node only ever asks for a block by number, and it
|
|
\ asks its kernel: it writes a request to port 0, where its kernel is, and
|
|
\ when the write has been served the answer is on the data stack. The
|
|
\ node has a window in its memory, four slots of 256 cells; the kernel
|
|
\ keeps the record of which block is in which slot, does the copying, and
|
|
\ decides when a block is written. The requests (v4/include/v4/blocks.h):
|
|
\ BLOCK# ( n -- waddr status ) the slot holding block n
|
|
\ BUFFER# ( n -- waddr status ) a slot for block n, not read
|
|
\ UPDATE# ( -- status ) the block last asked for is changed
|
|
\ SAVE-BUFFERS# ( -- status ) every changed block is written
|
|
\ EMPTY-BUFFERS# ( -- ) every slot is let go
|
|
\ The status is 0, or 2 storage refused (error 17), or 3 there is no such
|
|
\ block (error 13). BLOCK and BUFFER give a byte address, as PAD and TIB
|
|
\ are: what C@ CMOVE and TYPE take.
|
|
\
|
|
\ Constants the loader supplies:
|
|
\ BLOCK# BUFFER# UPDATE# SAVE-BUFFERS# EMPTY-BUFFERS# the requests' numbers
|
|
\ SCR word address of the variable: the block LIST showed last
|
|
\ BLK (SRC) (SRC-HOOK) see input.f18
|
|
|
|
set HDR-NFA here ", SCR #, 8 #, HDR-NFA #, HDR-LINK set HDR-LINK here : SCR' SCR ;
|
|
set HDR-NFA here ", BLK #, 8 #, HDR-NFA #, HDR-LINK set HDR-LINK here : BLK' BLK ;
|
|
|
|
\ ( status -- ) a request that did not work is an error
|
|
: (B-ERR)
|
|
if FINE -2 + if E17 drop NODE-ERROR b! 13 !b ;
|
|
E17: drop NODE-ERROR b! 17 !b ;
|
|
FINE: drop ;
|
|
|
|
\ ( waddr status -- baddr ) the slot's byte address, or the error
|
|
: (B-GOT)
|
|
if OK SWAP drop jump (B-ERR)
|
|
OK: drop 2* 2* ;
|
|
|
|
\ ( n -- baddr ) FORTH-79: the address of a buffer assigned to block n.
|
|
\ What the buffer holds is not read from storage.
|
|
set HDR-NFA here ", BUFFER #, 0 #, HDR-NFA #, HDR-LINK set HDR-LINK here
|
|
: BUFFER BUFFER# (PORT) b! !b jump (B-GOT)
|
|
|
|
\ ( n -- baddr ) FORTH-79: the address of a buffer that holds block n,
|
|
\ read from storage if it is not already in one.
|
|
set HDR-NFA here ", BLOCK #, 0 #, HDR-NFA #, HDR-LINK set HDR-LINK here
|
|
: BLOCK BLOCK# (PORT) b! !b jump (B-GOT)
|
|
|
|
\ FORTH-79: mark the block most recently asked for as changed, so that it is
|
|
\ written before its buffer is used for another.
|
|
set HDR-NFA here ", UPDATE #, 0 #, HDR-NFA #, HDR-LINK set HDR-LINK here
|
|
: UPDATE UPDATE# (PORT) b! !b jump (B-ERR)
|
|
|
|
\ FORTH-79: write every block that has been UPDATEd.
|
|
set HDR-NFA here ", SAVE-BUFFERS #, 0 #, HDR-NFA #, HDR-LINK set HDR-LINK here
|
|
: SAVE-BUFFERS SAVE-BUFFERS# (PORT) b! !b jump (B-ERR)
|
|
\ As v3: the same.
|
|
set HDR-NFA here ", FLUSH #, 0 #, HDR-NFA #, HDR-LINK set HDR-LINK here
|
|
: FLUSH jump SAVE-BUFFERS
|
|
\ FORTH-79: forget what is in the buffers; nothing is written.
|
|
set HDR-NFA here ", EMPTY-BUFFERS #, 0 #, HDR-NFA #, HDR-LINK set HDR-LINK here
|
|
: EMPTY-BUFFERS EMPTY-BUFFERS# (PORT) b! !b ;
|
|
|
|
\ ---- LIST ----------------------------------------------------------------------
|
|
\ ( n -- ) as v3: a new line, "Block n", then sixteen lines of 64
|
|
\ characters, each after its number, and an empty line. SCR is left holding n. A character
|
|
\ that is not printable is shown as a blank. (Q)+0 is the line, (Q)+1 the
|
|
\ column, (Q)+2 the block's number.
|
|
set HDR-NFA here ", LIST #, 0 #, HDR-NFA #, HDR-LINK set HDR-LINK here
|
|
: LIST
|
|
dup (Q)+2 a! ! BLOCK drop \ an error here leaves nothing behind
|
|
(Q)+2 a! @ dup SCR a! !
|
|
CR $636F6C42 (EMIT4) $206B (EMIT4) 0 DOT-R CR \ "Block "
|
|
0 (Q) a! !
|
|
LN: (Q) a! @ 0 <# # # #> TYPE 58 EMIT SPACE
|
|
0 (Q)+1 a! !
|
|
CH: SCR a! @ BLOCK (Q) a! @ 2* 2* 2* 2* 2* 2* + (Q)+1 a! @ + C@
|
|
dup -32 + -if GE drop drop 32 jump EM
|
|
GE: drop dup -127 + -if BIG drop jump EM
|
|
BIG: drop drop 32
|
|
EM: EMIT
|
|
(Q)+1 a! @ 1 + dup ! -64 + if EOL drop jump CH
|
|
EOL: drop CR
|
|
(Q) a! @ 1 + dup ! -16 + if DONE drop jump LN
|
|
DONE: drop jump CR
|
|
|
|
\ ---- LOAD ----------------------------------------------------------------------
|
|
\ The text being interpreted is at (SRC), SPAN characters of it, >IN the
|
|
\ place in it. LOAD saves those and BLK on the return stack, points them at
|
|
\ the block, interprets it, and puts them back; so a block may LOAD another,
|
|
\ and the rest of the line LOAD was on is interpreted afterwards. (v3's
|
|
\ LOAD loses the rest of its line.)
|
|
|
|
\ ( -- ) what WORD calls before it reads: while a block is being loaded,
|
|
\ make sure it is in a buffer and (SRC) is that buffer.
|
|
: (BLK-SRC)
|
|
BLK a! @ if TERM BLOCK (SRC) a! ! ;
|
|
TERM: drop ;
|
|
|
|
\ ( n -- ) FORTH-79: interpret block n, then go on with what follows.
|
|
set HDR-NFA here ", LOAD #, 0 #, HDR-NFA #, HDR-LINK set HDR-LINK here
|
|
: LOAD
|
|
-if POS jump BAD
|
|
POS: if BAD
|
|
BLK a! @ push >IN a! @ push SPAN a! @ push (SRC) a! @ push
|
|
BLK a! ! 0 >IN a! ! 1024 SPAN a! !
|
|
&(BLK-SRC) (SRC-HOOK) a! !
|
|
INTERPRET
|
|
pop (SRC) a! ! pop SPAN a! ! pop >IN a! ! pop BLK a! ! ;
|
|
BAD: drop NODE-ERROR b! 13 !b ;
|
|
|
|
\ ( -- ) go on with the next block. Only in a block being loaded: at the
|
|
\ terminal it is an error (code 14).
|
|
set HDR-NFA here ", --> #, 1 #, HDR-NFA #, HDR-LINK set HDR-LINK here
|
|
: NEXT-BLOCK
|
|
BLK a! @ if TERM 1 + ! 0 >IN a! ! ;
|
|
TERM: drop NODE-ERROR b! 14 !b ;
|
|
|
|
\ ( first last -- ) as v3: LOAD each block from first to last.
|
|
set HDR-NFA here ", THRU #, 0 #, HDR-NFA #, HDR-LINK set HDR-LINK here
|
|
: THRU
|
|
push
|
|
L: dup inv pop dup push + 1 + -if GO drop drop pop drop ; \ last - first
|
|
GO: drop dup push LOAD pop 1 + jump L
|