- The boot left the source's last new line in the console input, and the first KEY after the boot read it. What the ROM has not read when it starts the system is taken back (boot.c, rom_harness.h). hosted-check: KEY after the boot reads the key typed. - A comment or macro left open at the end of a blob ran on into the next, and the ROM accepted source text.c refuses. The loader ends each blob with FS (V4_ROM_BLOB_END) after its new line; the ROM ends a blob there as text.c ends a file: an open comment or macro is an error, and the word being assembled ends. test_host_rom_asm: seven blob pairs against text.c. - store to an address outside RAM faulted the ROM with no message. It is now refused, as text.c refuses it: ERR-RANGE, "address out of range". - The kernel build did not regenerate capsules/v4/sys/map-<w>.f18 before packing the capsule directory; it now does. ROM: 2084 words, rom_hash 0x4c458c6e48b35456. dict_hash unchanged, 0xe5a57f3eb72ff94a. make -C v4 test test-32 hosted-check pass. QEMU: amd64, aarch64, riscv64 to ok>, POST 538/538, POST: PASSED. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
119 lines
3.9 KiB
Plaintext
119 lines
3.9 KiB
Plaintext
\ in.f18 -- the ROM's input: characters from the console, and tokens.
|
|
\
|
|
\ The text the ROM assembles arrives at the console's receive registers,
|
|
\ a character at a time. Each blob of it ends with a new line and FS (28,
|
|
\ V4_ROM_BLOB_END), where a file ends for text.c: a comment still open there
|
|
\ is an error, and (TOKEN) gives 0 there as at the end. The end of all of
|
|
\ it is EOT (4), which the loader sends after the last blob. A token is what v4/src/text.c's next_token makes
|
|
\ of the same text: blanks are space, tab, CR and LF; a token is at most 63
|
|
\ characters; `\` as a whole token skips to the end of the line, and `(` as a
|
|
\ whole token to the next `)`.
|
|
\
|
|
\ State, in the ROM's area of the memory map (MACHINE.md 2.1):
|
|
\ (TOK) the token, as a counted string: its count byte, then its
|
|
\ characters, four to a cell, low byte first, zero-padded --
|
|
\ the form `",` lays down and (FIND) compares; 16 cells
|
|
\ (TOKN) its length
|
|
\ (PEEK) a character put back, plus one; 0: none
|
|
\ (LINE) how many new lines have been read
|
|
\ (EOF) non-zero once EOT has been read
|
|
\ (FAILED) 0, or the code of the error that stopped the ROM
|
|
\ (ERRLINE) (LINE) when it failed
|
|
\ (RAW) 1 while a token is read raw: ( and \ are then names
|
|
\ Every routine here uses A.
|
|
|
|
\ ( -- c ) wait for a character, then take it
|
|
: (KEY)
|
|
W: CONSOLE-STATUS a! @ if Z drop CONSOLE-RX a! @ ;
|
|
Z: drop jump W
|
|
|
|
\ ( -- c ) the character put back, if there is one; else the next
|
|
: (GETC)
|
|
(PEEK) a! @ if NONE 0 ! -1 + ;
|
|
NONE: drop jump (KEY)
|
|
|
|
\ ( c -- ) put a character back, to be the next one read
|
|
: (BACK) 1 + (PEEK) a! ! ;
|
|
|
|
\ ( -- ) one more new line
|
|
: (LF+) (LINE) a! @ 1 + ! ;
|
|
|
|
\ ( code -- ) stop with an error, noting the line
|
|
: (FAIL) (FAILED) a! ! (LINE) a! @ (ERRLINE) a! ! ;
|
|
|
|
\ ( c -- ) one more character of the token: byte (TOKN)+1 of (TOK), into
|
|
\ a cell whose byte there is still zero
|
|
: (PUT)
|
|
(TOKN) a! @ 1 +
|
|
dup 2/ 2/ (TOK) + push
|
|
3 and
|
|
S: if SD push 2* 2* 2* 2* 2* 2* 2* 2* pop -1 + jump S
|
|
SD: drop pop a! @ xor !
|
|
(TOKN) a! @ 1 + ! ;
|
|
|
|
\ ( i -- c ) character i of the token, from 0
|
|
: (CHAR@)
|
|
1 + dup 2/ 2/ (TOK) + a! @
|
|
push 3 and
|
|
S: if SD -1 + pop 2/ 2/ 2/ 2/ 2/ 2/ 2/ 2/ push jump S
|
|
SD: drop pop 255 and ;
|
|
|
|
\ ( -- len ) the next token into (TOK), its length into (TOKN). 0: the end
|
|
\ of a blob, the end of all ((EOF) set), or an error, which is in (FAILED).
|
|
: (TOKEN)
|
|
(EOF) a! @ if GO drop 0 ;
|
|
GO: drop
|
|
SKIP: (GETC)
|
|
dup 4 xor if END
|
|
drop dup 28 xor if BLOB
|
|
drop dup 10 xor if NL
|
|
drop dup 32 xor if SP
|
|
drop dup 9 xor if SP
|
|
drop dup 13 xor if SP
|
|
drop 0 (TOKN) a! !
|
|
(TOK) a! 15 FOR 0 !+ NEXT
|
|
READ: (TOKN) a! @ 63 xor if LONG
|
|
drop (PUT) (GETC)
|
|
dup 4 xor if TEND
|
|
drop dup 28 xor if TEND
|
|
drop dup 10 xor if TEND
|
|
drop dup 32 xor if TEND
|
|
drop dup 9 xor if TEND
|
|
drop dup 13 xor if TEND
|
|
drop jump READ
|
|
TEND: drop (BACK)
|
|
(TOKN) a! @ (TOK) a! @ xor !
|
|
(RAW) a! @ if COOKED drop (TOKN) a! @ ;
|
|
COOKED: drop
|
|
(TOKN) a! @ 1 xor if ONE
|
|
drop (TOKN) a! @ ;
|
|
ONE: drop 0 (CHAR@)
|
|
dup 92 xor if BSL
|
|
drop dup 40 xor if PAREN
|
|
drop drop 1 ;
|
|
BSL: drop drop
|
|
B1: (GETC)
|
|
dup 10 xor if BEND
|
|
drop dup 28 xor if BEND
|
|
drop dup 4 xor if BEND
|
|
drop drop jump B1
|
|
BEND: drop (BACK) jump SKIP
|
|
PAREN: drop drop
|
|
P1: (GETC)
|
|
dup 41 xor if PCLOSE
|
|
drop dup 10 xor if PNL
|
|
drop dup 28 xor if PEOF
|
|
drop dup 4 xor if PEOF
|
|
drop drop jump P1
|
|
PNL: drop drop (LF+) jump P1
|
|
PCLOSE: drop drop jump SKIP
|
|
PEOF: drop drop ERR-COMMENT (FAIL) 0 ;
|
|
END: drop drop 1 (EOF) a! ! 0 ;
|
|
BLOB: drop drop 0 ;
|
|
NL: drop drop (LF+) jump SKIP
|
|
SP: drop drop jump SKIP
|
|
LONG: drop drop ERR-TOO-LONG (FAIL) 0 ;
|
|
|
|
\ ( -- len ) the next token, raw: ( and \ are names, not comments
|
|
: (RAW-TOKEN) 1 (RAW) a! ! (TOKEN) 0 (RAW) a! ! ;
|