feat(v4.0.0): the block words are the kernel's -- v3's way in full
Ruled 2026-10-07. BLOCK, BUFFER, UPDATE, SAVE-BUFFERS and EMPTY-BUFFERS are each one kernel request on port 0, by block number only. The node has a window of four slots in its memory, as a v3 VM has; the kernel copies blocks into it, keeps the record of which block is in which slot, and decides when a block is written (v4/system/blocks.c). The node keeps no record and gives the kernel no address, so a request cannot overwrite the node's code. When a block is written stays FORTH-79's: UPDATE marks it. When the chain of devices changes the slots are let go, as in v3. The window is 512 cells more than the two buffers were; the dictionary space ends that much lower, at 13824. MESH.md 8.5 had said, from the review, that a v3 VM's BLOCK is the kernel's buffer. It is not, and the section now says what was reported, what v3 does, and what was ruled. make -C v4 test, sanitize and hosted-check pass; amd64, aarch64 and riscv64 boot, POST 538 of 538, the same hashes on all six: logs/20261007-092835, -093112, -093456. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
7f4d946d2e
commit
9bfd5071d2
+29
-67
@@ -4,103 +4,65 @@
|
||||
\ 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). A
|
||||
\ node only ever asks for a block by number, and it asks its kernel: with
|
||||
\ the number and the word address of 256 cells on the data stack it writes
|
||||
\ the request to port 0, where its kernel is, and when the write has been
|
||||
\ served the status is on the stack in their place -- 0 it worked, 2 it was
|
||||
\ refused, 3 there is no such block.
|
||||
\
|
||||
\ THE BUFFERS. There are two, of 256 cells each, so two blocks can be in
|
||||
\ memory at once -- one can be copied to another. A buffer is given to the
|
||||
\ block that asks for one, turn about; if it held a block that was UPDATEd,
|
||||
\ that block is written first. BLOCK and BUFFER give a byte address, as PAD
|
||||
\ and TIB are: what C@ CMOVE and TYPE take.
|
||||
\ 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-READ# BLOCK-WRITE# the numbers of the kernel's two requests
|
||||
\ BUF0 BUF1 word addresses of the two buffers
|
||||
\ (B) word address of six cells: (B)+0 the block in buffer 0, or 0
|
||||
\ (B)+1 whether it has been UPDATEd (B)+2 (B)+3 the same for
|
||||
\ buffer 1 (B)+4 which buffer was asked for last, 0 or 2
|
||||
\ (B)+5 the block number while a buffer is found for it
|
||||
\ 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.v4
|
||||
|
||||
header SCR inline : SCR' SCR ;
|
||||
header BLK inline : BLK' BLK ;
|
||||
|
||||
\ ( i -- addr ) the word address of buffer i, where i is 0 or 2
|
||||
: (BUF) if Z drop BUF1 ; Z: drop BUF0 ;
|
||||
|
||||
\ ( command i -- ) read buffer i's block from storage, command 1, or
|
||||
\ write it, command 2: a request of this node's kernel ( n waddr -- status ).
|
||||
\ If it did not work nothing is in the buffer, and it is an error: 17 if
|
||||
\ storage refused, 13 if there is no such block.
|
||||
: (DEVICE)
|
||||
dup push SWAP push \ i R: i command
|
||||
dup (B) + a! @ SWAP (BUF) \ n waddr
|
||||
pop -1 + if RD drop BLOCK-WRITE# jump ASK
|
||||
RD: drop BLOCK-READ#
|
||||
ASK: (PORT) b! !b \ status
|
||||
pop SWAP \ i status
|
||||
if FINE
|
||||
push (B) + a! 0 !+ 0 ! pop
|
||||
-2 + if E17 drop NODE-ERROR b! 13 !b ;
|
||||
\ ( 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 drop ;
|
||||
FINE: drop ;
|
||||
|
||||
\ ( i -- ) if buffer i's block has been UPDATEd, write it
|
||||
: (SAVE)
|
||||
dup (B) + 1 + a! @ if CLEAN
|
||||
drop 0 ! 2 SWAP jump (DEVICE)
|
||||
CLEAN: drop drop ;
|
||||
|
||||
\ ( n -- i flag ) the buffer for block n: the one that has it, flag -1; or
|
||||
\ the other of the one asked for last, its old block written if need be and
|
||||
\ n's number put on it, flag 0 -- what it holds is not block n yet. A block
|
||||
\ number below 1 is an error (code 13).
|
||||
: (FIND-BUF)
|
||||
-if POS jump BAD
|
||||
POS: if BAD
|
||||
(B)+5 a! !
|
||||
(B) a! @ (B)+5 a! @ xor if HIT0 drop
|
||||
(B)+2 a! @ (B)+5 a! @ xor if HIT2 drop
|
||||
(B)+4 a! @ 2 xor dup ! \ the other one
|
||||
dup (SAVE)
|
||||
dup (B) + a! (B)+5 b! @b !+ 0 ! \ its block now, not updated
|
||||
0 ;
|
||||
HIT0: drop 0 (B)+4 a! ! 0 -1 ;
|
||||
HIT2: drop 2 (B)+4 a! ! 2 -1 ;
|
||||
BAD: drop NODE-ERROR b! 13 !b 0 -1 ;
|
||||
\ ( 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.
|
||||
header BUFFER
|
||||
: BUFFER (FIND-BUF) drop (BUF) 2* 2* ;
|
||||
: 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.
|
||||
header BLOCK
|
||||
: BLOCK
|
||||
(FIND-BUF) if READ drop (BUF) 2* 2* ;
|
||||
READ: drop drop \ which buffer is in (B)+4: nothing waits on the stack
|
||||
1 (B)+4 a! @ (DEVICE) (B)+4 a! @ (BUF) 2* 2* ;
|
||||
: 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.
|
||||
header UPDATE
|
||||
: UPDATE (B)+4 a! @ (B) + a! @+ if NONE drop -1 ! ; NONE: drop ;
|
||||
: UPDATE UPDATE# (PORT) b! !b jump (B-ERR)
|
||||
|
||||
\ FORTH-79: write every block that has been UPDATEd.
|
||||
header SAVE-BUFFERS
|
||||
: SAVE-BUFFERS 0 (SAVE) 2 jump (SAVE)
|
||||
: SAVE-BUFFERS SAVE-BUFFERS# (PORT) b! !b jump (B-ERR)
|
||||
\ As v3: the same.
|
||||
header FLUSH
|
||||
: FLUSH jump SAVE-BUFFERS
|
||||
\ FORTH-79: forget what is in the buffers; nothing is written.
|
||||
header EMPTY-BUFFERS
|
||||
: EMPTY-BUFFERS (B) a! 0 !+ 0 !+ 0 !+ 0 ! ;
|
||||
: EMPTY-BUFFERS EMPTY-BUFFERS# (PORT) b! !b ;
|
||||
|
||||
\ ---- LIST ----------------------------------------------------------------------
|
||||
\ ( n -- ) as v3: a new line, "Block n", then sixteen lines of 64
|
||||
|
||||
Reference in New Issue
Block a user