diff --git a/capsules/BLOCK_MAP.md b/capsules/BLOCK_MAP.md
index 2ab3a33f..530c8dd7 100644
--- a/capsules/BLOCK_MAP.md
+++ b/capsules/BLOCK_MAP.md
@@ -1,5 +1,5 @@
# Capsule Block Manifest — Auto-generated
-
+
@@ -30,6 +30,7 @@
| `turtle.4th` | 5100, 5101, 5102, 5103, 5104, 5105, 5106, 5107, 5108 | `0x4d470418ca543365` | n/a |
| `user-font-demo.4th` | 4200, 4201, 4202 | `0xce1fd7d1b581a56d` | n/a |
| `v4:forth79.4th` | 6000 | `0xa4b74bdc7deaf204` | n/a |
+| `v4:post79.4th` | 7000, 7001, 7002, 7003, 7004, 7005, 7006, 7007, 7008, 7009, 7010, 7011, 7012, 7013, 7014, 7015, 7016, 7017, 7018, 7019, 7020, 7021, 7022, 7023, 7024, 7025, 7026, 7027, 7028, 7029, 7030, 7031, 7032, 7033, 7034, 7035, 7036, 7037, 7038, 7039, 7040, 7041, 7042, 7043, 7044, 7045, 7046, 7047, 7048, 7049, 7050, 7051, 7052, 7053, 7054, 7055, 7056, 7057, 7058, 7059, 7060, 7061, 7062, 7063 | `0x24df7b11992128ed` | n/a |
| `workload-0.4th` | 2200, 2201 | `0x93f86f60aeba8feb` | n/a |
| `workload-1-lite.4th` | 5058, 5059 | `0x44a7a7e3176dcc8d` | n/a |
| `workload-1.4th` | 4406, 4415, 4425, 4435 | `0x63e251adb0a03613` | n/a |
@@ -368,10 +369,74 @@
| 5114 | `sdk.4th` | `0x008fdbbb62c94a3a` | ok |
| 5115 | `sdk.4th` | `0x008fdbbb62c94a3a` | ok |
| 6000 | `v4:forth79.4th` | `0xa4b74bdc7deaf204` | ok |
+| 7000 | `v4:post79.4th` | `0x24df7b11992128ed` | ok |
+| 7001 | `v4:post79.4th` | `0x24df7b11992128ed` | ok |
+| 7002 | `v4:post79.4th` | `0x24df7b11992128ed` | ok |
+| 7003 | `v4:post79.4th` | `0x24df7b11992128ed` | ok |
+| 7004 | `v4:post79.4th` | `0x24df7b11992128ed` | ok |
+| 7005 | `v4:post79.4th` | `0x24df7b11992128ed` | ok |
+| 7006 | `v4:post79.4th` | `0x24df7b11992128ed` | ok |
+| 7007 | `v4:post79.4th` | `0x24df7b11992128ed` | ok |
+| 7008 | `v4:post79.4th` | `0x24df7b11992128ed` | ok |
+| 7009 | `v4:post79.4th` | `0x24df7b11992128ed` | ok |
+| 7010 | `v4:post79.4th` | `0x24df7b11992128ed` | ok |
+| 7011 | `v4:post79.4th` | `0x24df7b11992128ed` | ok |
+| 7012 | `v4:post79.4th` | `0x24df7b11992128ed` | ok |
+| 7013 | `v4:post79.4th` | `0x24df7b11992128ed` | ok |
+| 7014 | `v4:post79.4th` | `0x24df7b11992128ed` | ok |
+| 7015 | `v4:post79.4th` | `0x24df7b11992128ed` | ok |
+| 7016 | `v4:post79.4th` | `0x24df7b11992128ed` | ok |
+| 7017 | `v4:post79.4th` | `0x24df7b11992128ed` | ok |
+| 7018 | `v4:post79.4th` | `0x24df7b11992128ed` | ok |
+| 7019 | `v4:post79.4th` | `0x24df7b11992128ed` | ok |
+| 7020 | `v4:post79.4th` | `0x24df7b11992128ed` | ok |
+| 7021 | `v4:post79.4th` | `0x24df7b11992128ed` | ok |
+| 7022 | `v4:post79.4th` | `0x24df7b11992128ed` | ok |
+| 7023 | `v4:post79.4th` | `0x24df7b11992128ed` | ok |
+| 7024 | `v4:post79.4th` | `0x24df7b11992128ed` | ok |
+| 7025 | `v4:post79.4th` | `0x24df7b11992128ed` | ok |
+| 7026 | `v4:post79.4th` | `0x24df7b11992128ed` | ok |
+| 7027 | `v4:post79.4th` | `0x24df7b11992128ed` | ok |
+| 7028 | `v4:post79.4th` | `0x24df7b11992128ed` | ok |
+| 7029 | `v4:post79.4th` | `0x24df7b11992128ed` | ok |
+| 7030 | `v4:post79.4th` | `0x24df7b11992128ed` | ok |
+| 7031 | `v4:post79.4th` | `0x24df7b11992128ed` | ok |
+| 7032 | `v4:post79.4th` | `0x24df7b11992128ed` | ok |
+| 7033 | `v4:post79.4th` | `0x24df7b11992128ed` | ok |
+| 7034 | `v4:post79.4th` | `0x24df7b11992128ed` | ok |
+| 7035 | `v4:post79.4th` | `0x24df7b11992128ed` | ok |
+| 7036 | `v4:post79.4th` | `0x24df7b11992128ed` | ok |
+| 7037 | `v4:post79.4th` | `0x24df7b11992128ed` | ok |
+| 7038 | `v4:post79.4th` | `0x24df7b11992128ed` | ok |
+| 7039 | `v4:post79.4th` | `0x24df7b11992128ed` | ok |
+| 7040 | `v4:post79.4th` | `0x24df7b11992128ed` | ok |
+| 7041 | `v4:post79.4th` | `0x24df7b11992128ed` | ok |
+| 7042 | `v4:post79.4th` | `0x24df7b11992128ed` | ok |
+| 7043 | `v4:post79.4th` | `0x24df7b11992128ed` | ok |
+| 7044 | `v4:post79.4th` | `0x24df7b11992128ed` | ok |
+| 7045 | `v4:post79.4th` | `0x24df7b11992128ed` | ok |
+| 7046 | `v4:post79.4th` | `0x24df7b11992128ed` | ok |
+| 7047 | `v4:post79.4th` | `0x24df7b11992128ed` | ok |
+| 7048 | `v4:post79.4th` | `0x24df7b11992128ed` | ok |
+| 7049 | `v4:post79.4th` | `0x24df7b11992128ed` | ok |
+| 7050 | `v4:post79.4th` | `0x24df7b11992128ed` | ok |
+| 7051 | `v4:post79.4th` | `0x24df7b11992128ed` | ok |
+| 7052 | `v4:post79.4th` | `0x24df7b11992128ed` | ok |
+| 7053 | `v4:post79.4th` | `0x24df7b11992128ed` | ok |
+| 7054 | `v4:post79.4th` | `0x24df7b11992128ed` | ok |
+| 7055 | `v4:post79.4th` | `0x24df7b11992128ed` | ok |
+| 7056 | `v4:post79.4th` | `0x24df7b11992128ed` | ok |
+| 7057 | `v4:post79.4th` | `0x24df7b11992128ed` | ok |
+| 7058 | `v4:post79.4th` | `0x24df7b11992128ed` | ok |
+| 7059 | `v4:post79.4th` | `0x24df7b11992128ed` | ok |
+| 7060 | `v4:post79.4th` | `0x24df7b11992128ed` | ok |
+| 7061 | `v4:post79.4th` | `0x24df7b11992128ed` | ok |
+| 7062 | `v4:post79.4th` | `0x24df7b11992128ed` | ok |
+| 7063 | `v4:post79.4th` | `0x24df7b11992128ed` | ok |
## Conflicts
None.
---
-*37 capsule(s) scanned. Re-run `mkcapsule --manifest
` to refresh.*
+*38 capsule(s) scanned. Re-run `mkcapsule --manifest ` to refresh.*
diff --git a/capsules/v4/post79.4th b/capsules/v4/post79.4th
new file mode 100644
index 00000000..d8d01355
--- /dev/null
+++ b/capsules/v4/post79.4th
@@ -0,0 +1,1787 @@
+Block 7000
+( post79.4th -- POST for the FORTH-79 Required Word Set on v4. )
+( Generated by v4/tools/mkpost.py from v3's POST cases: do not )
+( edit. docs/v4.0.0/NUCLEUS.md section 6. )
+VARIABLE T# VARIABLE TPASS VARIABLE TFAIL VARIABLE TOPEN
+VARIABLE TBAD VARIABLE TWANT VARIABLE TLEN VARIABLE TSUM
+VARIABLE TDEP VARIABLE TBASE
+CREATE TBUF 64 ALLOT CREATE TSTK 16 ALLOT CREATE TNAME 8 ALLOT
+0 T# ! 0 TPASS ! 0 TFAIL ! 0 TOPEN ! 10 TBASE !
+: TB ( -- baddr ) TBUF 4 * ;
+: TN ( -- baddr ) TNAME 4 * ;
+( T-EMIT is given every character a case prints: the first 255 )
+( are kept, all are counted and summed. )
+: T-EMIT ( c -- )
+ DUP TSUM @ 31 * + 16777215 AND TSUM !
+ TLEN @ 255 < IF TB TLEN @ + C! ELSE DROP THEN 1 TLEN +! ;
+Block 7001
+: T-CLEAR ( i*x -- ) BEGIN DEPTH WHILE DROP REPEAT ;
+: T. ( n -- ) 0 <# #S #> TYPE ;
+( what a failing case printed, and the stack it left )
+: T-SHOW ( -- )
+ ." out<" TB TLEN @ 255 MIN TYPE ." > stack<"
+ TDEP @ BEGIN DUP WHILE 1- DUP TSTK + @ . REPEAT DROP ." >" ;
+( the verdict on the case that is open, if one is )
+: T-CLOSE ( -- )
+ TOPEN @ IF
+ (CATCH) @ -1 = TWANT @ = 0= IF 1 TBAD ! THEN
+ TBAD @ IF 1 TFAIL +!
+ ." POST FAIL: " TN COUNT TYPE T-SHOW CR
+ ELSE 1 TPASS +! THEN
+ 0 TOPEN ! 0 (CATCH) ! TBASE @ BASE !
+ THEN ;
+Block 7002
+( T{ name begin a case: clean stack, errors caught )
+: T{ ( i*x -- ) T-CLOSE T-CLEAR
+ BL WORD COUNT 31 MIN DUP TN C! TN 1+ SWAP CMOVE
+ 1 T# +! 1 TOPEN ! 0 TBAD ! 0 TWANT ! 0 TLEN ! 0 TSUM !
+ 0 TDEP ! 1 (CATCH) ! ;
+( T| ... a line of the case, what it prints captured )
+: T| ' T-EMIT (EMIT-HOOK) ! ; IMMEDIATE
+: T-END ( -- ) 0 (EMIT-HOOK) ! BASE @ TBASE ! DECIMAL ;
+( -> ... the case is over: set its stack aside, top first )
+: -> ( i*x -- ) T-END 0
+ BEGIN DEPTH 1 > WHILE
+ DUP 16 < IF SWAP OVER TSTK + ! ELSE SWAP DROP 1 TBAD ! THEN
+ 1+ REPEAT
+ 16 MIN TDEP ! ;
+( ->ERR the case is over, and must have ended in an error )
+: ->ERR ( i*x -- ) T-END -1 TWANT ! T-CLEAR ;
+Block 7003
+( ... }T the stack the case must have left, in order )
+: }T ( i*x -- )
+ DEPTH TDEP @ = 0= IF 1 TBAD ! T-CLEAR EXIT THEN
+ 0 BEGIN DEPTH 1 > WHILE
+ SWAP OVER TSTK + @ = 0= IF 1 TBAD ! THEN 1+ REPEAT DROP ;
+( len sum T= what the case must have printed )
+: T= ( len sum -- ) TSUM @ = 0= IF 1 TBAD ! THEN
+ TLEN @ = 0= IF 1 TBAD ! THEN ;
+( the tally; a failure is an error, which ends the boot )
+: T-REPORT ( -- ) T-CLOSE 0 (CATCH) ! DECIMAL
+ ." PARITY:V4_POST tests=" T# @ T. ." pass=" TPASS @ T.
+ ." fail=" TFAIL @ T. CR
+ TFAIL @ IF -1 NODE-ERROR ! THEN ;
+Block 7004
+T{ DUP.basic
+T| 5 DUP . . CR
+-> }T 5 16397428 T=
+T{ DUP.zero
+T| 0 DUP . . CR
+-> }T 5 11775018 T=
+T{ DUP.negative
+T| -42 DUP . . CR
+-> }T 9 15322016 T=
+T{ DUP.max_int
+T| 2147483647 DUP . . CR
+-> }T 23 2334858 T=
+T{ DUP.min_int
+T| -2147483648 DUP . . CR
+-> }T 25 386046 T=
+Block 7005
+T{ DUP.empty_stack
+T| DUP
+->ERR
+T{ DROP.basic
+T| 5 7 DROP . CR
+-> }T 3 51935 T=
+T{ DROP.zero
+T| 42 0 DROP . CR
+-> }T 4 1598184 T=
+T{ DROP.negative
+T| 10 -5 DROP . CR
+-> }T 4 1506889 T=
+T{ DROP.double_drop
+T| 1 2 3 DROP DROP . CR
+-> }T 3 48091 T=
+Block 7006
+T{ DROP.triple_drop
+T| 1 2 3 4 DROP DROP DROP . CR
+-> }T 3 48091 T=
+T{ DROP.sequential
+T| 5 DROP 6 DROP 7 . CR
+-> }T 3 53857 T=
+T{ DROP.single_item
+T| 99 DROP DEPTH . CR
+-> }T 3 47130 T=
+T{ DROP.depth_change
+T| DEPTH 1 2 DROP DEPTH SWAP - . CR
+-> 0 }T 3 48091 T=
+T{ DROP.preserve_depth
+T| DEPTH 5 6 DROP DROP DEPTH = . CR
+-> }T 3 47130 T=
+Block 7007
+T{ DROP.max_int
+T| 2147483647 DROP DEPTH . CR
+-> }T 3 47130 T=
+T{ DROP.min_int
+T| -2147483648 DROP DEPTH . CR
+-> }T 3 47130 T=
+T{ DROP.with_dup
+T| 5 DUP DROP . CR
+-> }T 3 51935 T=
+T{ DROP.with_swap
+T| 1 2 SWAP DROP . CR
+-> }T 3 49052 T=
+T{ DROP.complex
+T| 1 2 3 ROT DROP SWAP DROP . CR
+-> }T 3 50013 T=
+Block 7008
+T{ DROP.empty_stack
+T| DROP
+->ERR
+T{ SWAP.basic
+T| 5 7 SWAP . . CR
+-> }T 5 16399350 T=
+T{ SWAP.same_values
+T| 42 42 SWAP . . CR
+-> }T 7 15838026 T=
+T{ SWAP.zero_nonzero
+T| 0 99 SWAP . . CR
+-> }T 6 12996858 T=
+T{ SWAP.negative
+T| -5 10 SWAP . . CR
+-> }T 7 12792257 T=
+Block 7009
+T{ SWAP.one_item
+T| 42 SWAP
+->ERR
+T{ SWAP.empty_stack
+T| SWAP
+->ERR
+T{ OVER.basic
+T| 5 7 OVER . . . CR
+-> }T 7 6011851 T=
+T{ OVER.zeros
+T| 0 0 OVER . . . CR
+-> }T 7 7986234 T=
+T{ OVER.mixed
+T| -1 42 OVER . . . CR
+-> }T 10 1455732 T=
+Block 7010
+T{ OVER.one_item
+T| 42 OVER
+->ERR
+T{ OVER.empty_stack
+T| OVER
+->ERR
+T{ ROT.basic
+T| 1 2 3 ROT . . . CR
+-> }T 7 9069952 T=
+T{ ROT.zeros
+T| 0 0 0 ROT . . . CR
+-> }T 7 7986234 T=
+T{ ROT.mixed
+T| -1 0 1 ROT . . . CR
+-> }T 8 201263 T=
+Block 7011
+T{ ROT.two_items
+T| 1 2 ROT
+->ERR
+T{ ROT.one_item
+T| 42 ROT
+->ERR
+T{ ROT.empty_stack
+T| ROT
+->ERR
+T{ DEPTH.empty
+T| DEPTH . CR
+-> }T 3 47130 T=
+T{ DEPTH.one_item
+T| 42 DEPTH . CR
+-> 42 }T 3 48091 T=
+Block 7012
+T{ DEPTH.multiple
+T| 1 2 3 DEPTH . CR
+-> 1 2 3 }T 3 50013 T=
+T{ PICK.pick_0
+T| 1 2 3 0 PICK . CR
+-> 1 2 3 }T 3 50013 T=
+T{ PICK.pick_1
+T| 1 2 3 1 PICK . CR
+-> 1 2 3 }T 3 49052 T=
+T{ PICK.pick_2
+T| 1 2 3 2 PICK . CR
+-> 1 2 3 }T 3 48091 T=
+T{ ROLL.roll_1
+T| 1 2 3 1 ROLL . . . CR
+-> }T 7 9069952 T=
+Block 7013
+T{ ROLL.roll_2
+T| 1 2 3 2 ROLL . . . CR
+-> }T 7 7380224 T=
+T{ ?DUP.nonzero
+T| 42 ?DUP . . CR
+-> }T 7 15838026 T=
+T{ ?DUP.negative
+T| -5 ?DUP . . CR
+-> }T 7 12677898 T=
+T{ ?DUP.zero
+T| 0 ?DUP DEPTH . CR
+-> 0 }T 3 48091 T=
+T{ ?DUP.empty_stack
+T| ?DUP
+->ERR
+Block 7014
+T{ >R.basic
+T| 42 >R R@ . R> . CR
+-> }T 7 15838026 T=
+T{ >R.zero
+T| 0 >R R@ . R> . CR
+-> }T 5 11775018 T=
+T{ >R.negative
+T| -123 >R R@ . R> . CR
+-> }T 11 14101290 T=
+T{ >R.multiple
+T| 1 2 >R >R R@ . R> . R@ . R> . CR
+-> }T 9 12265744 T=
+T{ >R.empty_stack
+T| >R
+->ERR
+Block 7015
+T{ R>.basic
+T| 42 >R R> . CR
+-> }T 4 1598184 T=
+T{ R>.lifo_order
+T| 1 2 >R >R R> . R> . CR
+-> }T 5 12700461 T=
+T{ R>.empty_rstack
+T| R>
+->ERR
+T{ R@.basic
+T| 42 >R R@ . R> DROP CR
+-> }T 4 1598184 T=
+T{ R@.non_destructive
+T| 99 >R R@ R@ = . R> DROP CR
+-> }T 4 1388686 T=
+Block 7016
+T{ R@.empty_rstack
+T| R@
+->ERR
+T{ !.basic
+T| 42 HERE ! HERE @ . CR
+-> }T 4 1598184 T=
+T{ !.zero
+T| 0 HERE ! HERE @ . CR
+-> }T 3 47130 T=
+T{ !.negative
+T| -999 HERE ! HERE @ . CR
+-> }T 6 529078 T=
+T{ !.overwrite
+T| 111 HERE ! 222 HERE ! HERE @ . CR
+-> }T 5 14160220 T=
+Block 7017
+T{ !.max_int
+T| 2147483647 HERE ! HERE @ . CR
+-> }T 12 4848918 T=
+T{ !.min_int
+T| -2147483648 HERE ! HERE @ . CR
+-> }T 13 5383556 T=
+T{ !.empty_stack
+T| !
+->ERR
+T{ !.one_item
+T| 42 !
+->ERR
+T{ @.after_store
+T| 123 HERE ! HERE @ . CR
+-> }T 5 13237660 T=
+Block 7018
+T{ @.multiple_reads
+T| 456 HERE ! HERE @ HERE @ = . CR
+-> }T 4 1388686 T=
+T{ @.empty_stack
+T| @
+->ERR
+T{ C!.basic
+T| 65 HERE C! HERE C@ . CR
+-> }T 4 1660649 T=
+T{ C!.zero
+T| 0 HERE C! HERE C@ . CR
+-> }T 3 47130 T=
+T{ C!.high_byte
+T| 255 HERE C! HERE C@ . CR
+-> }T 5 14252476 T=
+Block 7019
+T{ C!.truncation
+T| 256 HERE C! HERE C@ . CR
+-> }T 3 47130 T=
+T{ C@.after_cstore
+T| 97 HERE C! HERE C@ . CR
+-> }T 4 1751944 T=
+T{ C@.zero_byte
+T| 0 HERE C! HERE C@ . CR
+-> }T 3 47130 T=
+T{ ,.basic
+T| 42 , HERE 8 - @ . CR
+-> }T 4 1598184 T=
+T{ ,.negative
+T| -999 , HERE 8 - @ . CR
+-> }T 6 529078 T=
+Block 7020
+T{ HERE.basic
+T| HERE HERE = . CR
+-> }T 4 1388686 T=
+T{ HERE.after_comma
+T| HERE 42 , HERE SWAP - 1 CELLS = 0 SWAP /
+-> 0 }T 0 0 T=
+T{ ALLOT.basic
+T| HERE 10 ALLOT HERE SWAP - . CR
+-> }T 4 1506889 T=
+T{ ALLOT.zero
+T| HERE 0 ALLOT HERE SWAP - . CR
+-> }T 3 47130 T=
+T{ ALLOT.negative
+T| HERE -4 ALLOT HERE SWAP - . CR
+-> }T 4 1391569 T=
+Block 7021
+T{ PAD.basic
+T| PAD PAD = . CR
+-> }T 4 1388686 T=
+T{ PAD.different_from_here
+T| PAD HERE = . CR
+-> }T 3 47130 T=
+T{ +!.basic
+T| 10 HERE ! 5 HERE +! HERE @ . CR
+->ERR
+T{ +!.by_zero
+T| 42 HERE ! 0 HERE +! HERE @ . CR
+->ERR
+T{ +!.negative
+T| 10 HERE ! -3 HERE +! HERE @ . CR
+->ERR
+Block 7022
+T{ +!.accumulate
+T| 0 HERE ! 1 HERE +! 2 HERE +! 3 HERE +! HERE @ . CR
+->ERR
+T{ +!.empty_stack
+T| +!
+->ERR
+T{ FILL.basic
+T| HERE 8 65 FILL HERE C@ . HERE 1+ C@ . CR
+-> }T 7 14524330 T=
+T{ FILL.zero_n
+T| HERE 0 88 FILL
+-> }T 0 0 T=
+T{ FILL.zero_byte
+T| HERE 4 0 FILL HERE C@ . CR
+-> }T 3 47130 T=
+Block 7023
+T{ FILL.empty_stack
+T| FILL
+->ERR
+T{ MOVE.basic
+T| HERE 65 OVER C! HERE 1+ 66 OVER C! HERE HERE 16 + 2 MOVE HERE
+T| 16 + C@ . HERE 17 + C@ . CR
+-> 302 303 }T 7 14525291 T=
+T{ MOVE.zero_n
+T| HERE HERE 8 + 0 MOVE
+-> }T 0 0 T=
+T{ MOVE.empty_stack
+T| MOVE
+->ERR
+T{ +.basic
+T| 5 7 + . CR
+-> }T 4 1508811 T=
+Block 7024
+T{ +.zero_add
+T| 42 0 + . CR
+-> }T 4 1598184 T=
+T{ +.negative
+T| -5 3 + . CR
+-> }T 4 1389647 T=
+T{ +.both_negative
+T| -5 -3 + . CR
+-> }T 4 1395413 T=
+T{ +.overflow
+T| 2147483647 1 + . CR
+-> }T 12 4849879 T=
+T{ +.underflow
+T| -2147483648 -1 + . CR
+-> }T 13 5384517 T=
+Block 7025
+T{ +.empty_stack
+T| +
+->ERR
+T{ +.one_item
+T| 42 +
+->ERR
+T{ -.basic
+T| 10 3 - . CR
+-> }T 3 53857 T=
+T{ -.zero_sub
+T| 42 0 - . CR
+-> }T 4 1598184 T=
+T{ -.from_zero
+T| 0 5 - . CR
+-> }T 4 1392530 T=
+Block 7026
+T{ -.negative
+T| 5 -3 - . CR
+-> }T 3 54818 T=
+T{ -.same_values
+T| 42 42 - . CR
+-> }T 3 47130 T=
+T{ -.overflow
+T| -2147483648 1 - . CR
+-> }T 13 5384517 T=
+T{ -.underflow
+T| 2147483647 -1 - . CR
+-> }T 12 4849879 T=
+T{ -.empty_stack
+T| -
+->ERR
+Block 7027
+T{ -.one_item
+T| 42 -
+->ERR
+T{ *.basic
+T| 6 7 * . CR
+-> }T 4 1598184 T=
+T{ *.by_zero
+T| 42 0 * . CR
+-> }T 3 47130 T=
+T{ *.by_one
+T| 42 1 * . CR
+-> }T 4 1598184 T=
+T{ *.by_negative
+T| 6 -7 * . CR
+-> }T 5 9602197 T=
+Block 7028
+T{ *.negative_negative
+T| -6 -7 * . CR
+-> }T 4 1598184 T=
+T{ *.large_numbers
+T| 32767 2 * . CR
+-> }T 7 273505 T=
+T{ *.overflow
+T| 65536 65536 * . CR
+-> }T 12 6984600 T=
+T{ *.empty_stack
+T| *
+->ERR
+T{ *.one_item
+T| 42 *
+->ERR
+Block 7029
+T{ /.basic
+T| 15 3 / . CR
+-> }T 3 51935 T=
+T{ /.by_one
+T| 42 1 / . CR
+-> }T 4 1598184 T=
+T{ /.negative_dividend
+T| -15 3 / . CR
+-> }T 4 1392530 T=
+T{ /.negative_divisor
+T| 15 -3 / . CR
+-> }T 4 1392530 T=
+T{ /.both_negative
+T| -15 -3 / . CR
+-> }T 3 51935 T=
+Block 7030
+T{ /.truncation
+T| 7 3 / . CR
+-> }T 3 49052 T=
+T{ /.by_zero
+T| 42 0 /
+->ERR
+T{ /.empty_stack
+T| /
+->ERR
+T{ /.one_item
+T| 42 /
+->ERR
+T{ MOD.basic
+T| 17 5 MOD . CR
+-> }T 3 49052 T=
+Block 7031
+T{ MOD.exact_division
+T| 15 3 MOD . CR
+-> }T 3 47130 T=
+T{ MOD.by_one
+T| 42 1 MOD . CR
+-> }T 3 47130 T=
+T{ MOD.negative_dividend
+T| -17 5 MOD . CR
+-> }T 4 1389647 T=
+T{ MOD.negative_divisor
+T| 17 -5 MOD . CR
+-> }T 3 49052 T=
+T{ MOD.small_by_large
+T| 3 7 MOD . CR
+-> }T 3 50013 T=
+Block 7032
+T{ MOD.by_zero
+T| 42 0 MOD
+->ERR
+T{ MOD.empty_stack
+T| MOD
+->ERR
+T{ MOD.one_item
+T| 42 MOD
+->ERR
+T{ /MOD.basic
+T| 17 5 /MOD . . CR
+-> }T 5 14547503 T=
+T{ /MOD.exact
+T| 15 3 /MOD . . CR
+-> }T 5 16392623 T=
+Block 7033
+T{ /MOD.negative
+T| -17 5 /MOD . . CR
+-> }T 7 5748361 T=
+T{ /MOD.by_zero
+T| 42 0 /MOD
+->ERR
+T{ /MOD.empty_stack
+T| /MOD
+->ERR
+T{ /MOD.one_item
+T| 42 /MOD
+->ERR
+T{ ABS.positive
+T| 42 ABS . CR
+-> }T 4 1598184 T=
+Block 7034
+T{ ABS.negative
+T| -42 ABS . CR
+-> }T 4 1598184 T=
+T{ ABS.zero
+T| 0 ABS . CR
+-> }T 3 47130 T=
+T{ ABS.min_int
+T| -2147483648 ABS . CR
+-> }T 12 4849879 T=
+T{ ABS.empty_stack
+T| ABS
+->ERR
+T{ NEGATE.positive
+T| 42 NEGATE . CR
+-> }T 5 9602197 T=
+Block 7035
+T{ NEGATE.negative
+T| -42 NEGATE . CR
+-> }T 4 1598184 T=
+T{ NEGATE.zero
+T| 0 NEGATE . CR
+-> }T 3 47130 T=
+T{ NEGATE.min_int
+T| -2147483648 NEGATE . CR
+-> }T 12 4849879 T=
+T{ NEGATE.empty_stack
+T| NEGATE
+->ERR
+T{ MIN.basic
+T| 5 3 MIN . CR
+-> }T 3 50013 T=
+Block 7036
+T{ MIN.equal
+T| 42 42 MIN . CR
+-> }T 4 1598184 T=
+T{ MIN.negative
+T| -5 -3 MIN . CR
+-> }T 4 1392530 T=
+T{ MIN.mixed
+T| -1 1 MIN . CR
+-> }T 4 1388686 T=
+T{ MIN.one_item
+T| 42 MIN
+->ERR
+T{ MIN.empty_stack
+T| MIN
+->ERR
+Block 7037
+T{ MAX.basic
+T| 5 3 MAX . CR
+-> }T 3 51935 T=
+T{ MAX.equal
+T| 42 42 MAX . CR
+-> }T 4 1598184 T=
+T{ MAX.negative
+T| -5 -3 MAX . CR
+-> }T 4 1390608 T=
+T{ MAX.mixed
+T| -1 1 MAX . CR
+-> }T 3 48091 T=
+T{ MAX.one_item
+T| 42 MAX
+->ERR
+Block 7038
+T{ MAX.empty_stack
+T| MAX
+->ERR
+T{ 1+.basic
+T| 5 1+ . CR
+-> }T 3 52896 T=
+T{ 1+.zero
+T| 0 1+ . CR
+-> }T 3 48091 T=
+T{ 1+.negative
+T| -1 1+ . CR
+-> }T 3 47130 T=
+T{ 1+.chain
+T| 3 1+ 1+ 1+ . CR
+-> }T 3 52896 T=
+Block 7039
+T{ 1+.overflow
+T| 2147483647 1+ . CR
+-> }T 12 4849879 T=
+T{ 1+.empty_stack
+T| 1+
+->ERR
+T{ 1-.basic
+T| 5 1- . CR
+-> }T 3 50974 T=
+T{ 1-.to_zero
+T| 1 1- . CR
+-> }T 3 47130 T=
+T{ 1-.to_negative
+T| 0 1- . CR
+-> }T 4 1388686 T=
+Block 7040
+T{ 1-.chain
+T| 6 1- 1- 1- . CR
+-> }T 3 50013 T=
+T{ 1-.underflow
+T| -2147483648 1- . CR
+-> }T 13 5384517 T=
+T{ 1-.empty_stack
+T| 1-
+->ERR
+T{ 2+.basic
+T| 5 2+ . CR
+-> }T 3 53857 T=
+T{ 2+.zero
+T| 0 2+ . CR
+-> }T 3 49052 T=
+Block 7041
+T{ 2+.negative
+T| -3 2+ . CR
+-> }T 4 1388686 T=
+T{ 2+.empty_stack
+T| 2+
+->ERR
+T{ 2-.basic
+T| 7 2- . CR
+-> }T 3 51935 T=
+T{ 2-.zero
+T| 2 2- . CR
+-> }T 3 47130 T=
+T{ 2-.negative
+T| 0 2- . CR
+-> }T 4 1389647 T=
+Block 7042
+T{ 2-.empty_stack
+T| 2-
+->ERR
+T{ AND.both_true
+T| -1 -1 AND . CR
+-> }T 4 1388686 T=
+T{ AND.first_false
+T| 0 -1 AND . CR
+-> }T 3 47130 T=
+T{ AND.second_false
+T| -1 0 AND . CR
+-> }T 3 47130 T=
+T{ AND.both_false
+T| 0 0 AND . CR
+-> }T 3 47130 T=
+Block 7043
+T{ AND.bitwise
+T| 85 51 AND . CR
+-> }T 4 1513616 T=
+T{ AND.empty_stack
+T| AND
+->ERR
+T{ AND.one_item
+T| 42 AND
+->ERR
+T{ OR.both_true
+T| -1 -1 OR . CR
+-> }T 4 1388686 T=
+T{ OR.first_false
+T| 0 -1 OR . CR
+-> }T 4 1388686 T=
+Block 7044
+T{ OR.second_false
+T| -1 0 OR . CR
+-> }T 4 1388686 T=
+T{ OR.both_false
+T| 0 0 OR . CR
+-> }T 3 47130 T=
+T{ OR.bitwise
+T| 85 51 OR . CR
+-> }T 5 13213635 T=
+T{ OR.empty_stack
+T| OR
+->ERR
+T{ OR.one_item
+T| 42 OR
+->ERR
+Block 7045
+T{ XOR.both_true
+T| -1 -1 XOR . CR
+-> }T 3 47130 T=
+T{ XOR.first_false
+T| 0 -1 XOR . CR
+-> }T 4 1388686 T=
+T{ XOR.second_false
+T| -1 0 XOR . CR
+-> }T 4 1388686 T=
+T{ XOR.both_false
+T| 0 0 XOR . CR
+-> }T 3 47130 T=
+T{ XOR.bitwise
+T| 85 51 XOR . CR
+-> }T 5 13177117 T=
+Block 7046
+T{ XOR.empty_stack
+T| XOR
+->ERR
+T{ XOR.one_item
+T| 42 XOR
+->ERR
+T{ NOT.true
+T| -1 NOT . CR
+-> }T 3 47130 T=
+T{ NOT.false
+T| 0 NOT . CR
+-> }T 4 1388686 T=
+T{ NOT.positive
+T| 42 NOT . CR
+-> }T 3 47130 T=
+Block 7047
+T{ NOT.negative
+T| -42 NOT . CR
+-> }T 3 47130 T=
+T{ NOT.empty_stack
+T| NOT
+->ERR
+T{ =.equal
+T| 42 42 = . CR
+-> }T 4 1388686 T=
+T{ =.not_equal
+T| 42 43 = . CR
+-> }T 3 47130 T=
+T{ =.zero_equal
+T| 0 0 = . CR
+-> }T 4 1388686 T=
+Block 7048
+T{ =.negative_equal
+T| -42 -42 = . CR
+-> }T 4 1388686 T=
+T{ =.negative_positive
+T| -42 42 = . CR
+-> }T 3 47130 T=
+T{ =.empty_stack
+T| =
+->ERR
+T{ =.one_item
+T| 42 =
+->ERR
+T{ <.less_than
+T| 5 7 < . CR
+-> }T 4 1388686 T=
+Block 7049
+T{ <.greater_than
+T| 7 5 < . CR
+-> }T 3 47130 T=
+T{ <.equal
+T| 5 5 < . CR
+-> }T 3 47130 T=
+T{ <.negative_positive
+T| -5 5 < . CR
+-> }T 4 1388686 T=
+T{ <.negative_negative
+T| -7 -5 < . CR
+-> }T 4 1388686 T=
+T{ <.empty_stack
+T| <
+->ERR
+Block 7050
+T{ <.one_item
+T| 42 <
+->ERR
+T{ >.greater_than
+T| 7 5 > . CR
+-> }T 4 1388686 T=
+T{ >.less_than
+T| 5 7 > . CR
+-> }T 3 47130 T=
+T{ >.equal
+T| 5 5 > . CR
+-> }T 3 47130 T=
+T{ >.positive_negative
+T| 5 -5 > . CR
+-> }T 4 1388686 T=
+Block 7051
+T{ >.negative_negative
+T| -5 -7 > . CR
+-> }T 4 1388686 T=
+T{ >.empty_stack
+T| >
+->ERR
+T{ >.one_item
+T| 42 >
+->ERR
+T{ 0=.zero
+T| 0 0= . CR
+-> }T 4 1388686 T=
+T{ 0=.positive
+T| 42 0= . CR
+-> }T 3 47130 T=
+Block 7052
+T{ 0=.negative
+T| -42 0= . CR
+-> }T 3 47130 T=
+T{ 0=.empty_stack
+T| 0=
+->ERR
+T{ 0<.negative
+T| -42 0< . CR
+-> }T 4 1388686 T=
+T{ 0<.zero
+T| 0 0< . CR
+-> }T 3 47130 T=
+T{ 0<.positive
+T| 42 0< . CR
+-> }T 3 47130 T=
+Block 7053
+T{ 0<.empty_stack
+T| 0<
+->ERR
+T{ 0>.positive
+T| 42 0> . CR
+-> }T 4 1388686 T=
+T{ 0>.zero
+T| 0 0> . CR
+-> }T 3 47130 T=
+T{ 0>.negative
+T| -42 0> . CR
+-> }T 3 47130 T=
+T{ 0>.empty_stack
+T| 0>
+->ERR
+Block 7054
+T{ U<.less
+T| 3 5 U< . CR
+-> }T 4 1388686 T=
+T{ U<.equal
+T| 5 5 U< . CR
+-> }T 3 47130 T=
+T{ U<.greater
+T| 7 5 U< . CR
+-> }T 3 47130 T=
+T{ U<.zero_one
+T| 0 1 U< . CR
+-> }T 4 1388686 T=
+T{ U<.empty_stack
+T| U<
+->ERR
+Block 7055
+T{ */.basic
+T| 6 7 4 */ . CR
+-> }T 4 1506889 T=
+T{ */.exact_division
+T| 12 5 3 */ . CR
+-> }T 4 1536680 T=
+T{ */.zero_multiply
+T| 0 999 123 */ . CR
+-> }T 3 47130 T=
+T{ */.by_one
+T| 42 5 1 */ . CR
+-> }T 5 14128507 T=
+T{ */.truncation
+T| 7 3 2 */ . CR
+-> }T 4 1506889 T=
+Block 7056
+T{ */.negative_multiply
+T| -6 7 4 */ . CR
+-> }T 5 9510902 T=
+T{ */.negative_divisor
+T| 6 7 -4 */ . CR
+-> }T 5 9510902 T=
+T{ */.div_by_zero
+T| 6 7 0 */
+->ERR
+T{ */.empty_stack
+T| */
+->ERR
+T{ */.two_items
+T| 1 2 */
+->ERR
+Block 7057
+T{ */MOD.basic
+T| 17 3 5 */MOD . . CR
+-> }T 6 5318234 T=
+T{ */MOD.exact_division
+T| 15 4 3 */MOD . . CR
+-> }T 6 391992 T=
+T{ */MOD.zero_multiply
+T| 0 999 123 */MOD . . CR
+-> }T 5 11775018 T=
+T{ */MOD.by_one
+T| 42 5 1 */MOD . . CR
+-> }T 7 4765003 T=
+T{ */MOD.remainder
+T| 7 8 5 */MOD . . CR
+-> }T 6 6241755 T=
+Block 7058
+T{ */MOD.negative
+T| -7 3 4 */MOD . . CR
+-> }T 7 12674054 T=
+T{ */MOD.div_by_zero
+T| 6 7 0 */MOD
+->ERR
+T{ */MOD.empty_stack
+T| */MOD
+->ERR
+T{ D+.basic
+T| 100 200 300 400 D+ . . CR
+-> }T 9 6378548 T=
+T{ D+.zero_add
+T| 42 99 0 0 D+ . . CR
+-> }T 7 6471656 T=
+Block 7059
+T{ D+.negative
+T| -100 -200 50 75 D+ . . CR
+-> }T 10 13971193 T=
+T{ D+.carry
+T| 2147483647 0 1 0 D+ . . CR
+-> }T 14 4234951 T=
+T{ D+.both_negative
+T| -100 -200 -300 -400 D+ . . CR
+-> }T 11 5003369 T=
+T{ D+.three_items
+T| 1 2 3 D+
+->ERR
+T{ D+.empty_stack
+T| D+
+->ERR
+Block 7060
+T{ DNEGATE.positive
+T| 100 200 DNEGATE . . CR
+-> }T 11 13922440 T=
+T{ DNEGATE.negative
+T| -100 -200 DNEGATE . . CR
+-> }T 9 14912460 T=
+T{ DNEGATE.zero
+T| 0 0 DNEGATE . . CR
+-> }T 5 11775018 T=
+T{ DNEGATE.max_positive
+T| 2147483647 0 DNEGATE . . CR
+-> }T 16 11447367 T=
+T{ DNEGATE.one_item
+T| 42 DNEGATE
+->ERR
+Block 7061
+T{ DNEGATE.empty_stack
+T| DNEGATE
+->ERR
+T{ D<.less_than
+T| 100 200 300 400 D< . CR
+-> }T 4 1388686 T=
+T{ D<.greater_than
+T| 300 400 100 200 D< . CR
+-> }T 3 47130 T=
+T{ D<.equal
+T| 100 200 100 200 D< . CR
+-> }T 3 47130 T=
+T{ D<.negative_positive
+T| -100 -1 100 0 D< . CR
+-> }T 4 1388686 T=
+Block 7062
+T{ D<.negative_negative
+T| -300 -1 -100 -1 D< . CR
+-> }T 4 1388686 T=
+T{ D<.high_word_diff
+T| 100 200 100 300 D< . CR
+-> }T 4 1388686 T=
+T{ D<.three_items
+T| 1 2 3 D<
+->ERR
+T{ D<.empty_stack
+T| D<
+->ERR
+T{ BASE.decimal
+T| DECIMAL 42 . CR
+-> }T 4 1598184 T=
+Block 7063
+T{ BASE.hex
+T| HEX FF . CR
+-> }T 4 2153642 T=
+T{ BASE.octal
+T| OCTAL 52 . CR
+-> }T 4 1627975 T=
+T{ BASE.base_store
+T| 16 BASE ! 255 . CR
+-> }T 5 16131231 T=
+T{ BASE.base_fetch
+T| BASE @ . CR
+-> }T 4 1510733 T=
+T{ DECIMAL.from_hex
+T| HEX FF DECIMAL . CR
+-> }T 5 14252476 T=
+Block 7064
+T{ DECIMAL.from_octal
+T| OCTAL 52 DECIMAL . CR
+-> }T 4 1598184 T=
+T{ DECIMAL.state_persist
+T| DECIMAL 42 . CR 42 . CR HEX 42 . CR
+-> }T 12 9440440 T=
+T{ <#.basic
+T| DECIMAL 42 S>D <# #S #> TYPE CR
+-> }T 22 14470350 T=
+T{ <#.empty
+T| 0 <# #> TYPE CR
+-> 0 }T 1 10 T=
+T{ <#.negative
+T| -42 <# #S #> TYPE CR
+-> }T 3 51532 T=
+Block 7065
+T{ #.single_digit
+T| 15 <# # #> TYPE CR
+-> }T 2 1653 T=
+T{ #.multiple
+T| 15 <# # # #> TYPE CR
+-> }T 3 48742 T=
+T{ #.zero_pad
+T| 5 <# # 0 # #> TYPE CR
+-> 0 }T 3 47781 T=
+T{ #S.basic
+T| 42 <# #S #> TYPE CR
+-> }T 3 51532 T=
+T{ #S.zero
+T| 0 <# #S #> TYPE CR
+-> }T 2 1498 T=
+Block 7066
+T{ #S.large
+T| 1234567890 <# #S #> TYPE CR
+-> }T 11 7265487 T=
+T{ SIGN.negative
+T| -42 ABS <# #S SIGN #> TYPE CR
+-> 0 }T 3 51532 T=
+T{ SIGN.positive
+T| 42 <# #S SIGN #> TYPE CR
+-> 0 }T 3 51532 T=
+T{ SIGN.zero
+T| 0 <# #S SIGN #> TYPE CR
+-> 0 }T 2 1498 T=
+T{ #>.normal
+T| 42 <# #S #> TYPE CR
+-> }T 3 51532 T=
+Block 7067
+T{ #>.empty
+T| 0 <# #> TYPE CR
+-> 0 }T 1 10 T=
+T{ #>.stack_effect
+T| 42 <# #S #> SWAP . . CR
+-> }T 6 4087998 T=
+T{ HOLD.basic
+T| 42 <# 46 HOLD #S #> TYPE CR
+-> }T 4 1598618 T=
+T{ HOLD.overflow
+T| <# 257 HOLD #>
+->ERR
+T{ COUNT.basic
+T| HERE S" Test" DROP COUNT . . CR
+-> 302 }T 8 8794556 T=
+Block 7068
+T{ COUNT.empty
+T| HERE 0 OVER C! COUNT . . CR
+-> }T 7 11241141 T=
+T{ COUNT.max_length
+T| HERE 255 OVER C! COUNT . . CR
+-> }T 9 2533207 T=
+T{ COUNT.string_bounds
+T| HERE COUNT SWAP 1- = . CR
+-> }T 3 47130 T=
+T{ COUNT.empty_stack
+T| COUNT
+->ERR
+T{ -TRAILING.basic
+T| HERE S" Test " -TRAILING TYPE CR
+-> 307 }T 6 6975864 T=
+Block 7069
+T{ -TRAILING.all_spaces
+T| HERE S" " -TRAILING TYPE CR
+-> 315 }T 1 10 T=
+T{ -TRAILING.no_spaces
+T| HERE S" Test" -TRAILING TYPE CR
+-> 320 }T 5 13589912 T=
+T{ -TRAILING.empty
+T| HERE 0 -TRAILING TYPE CR
+-> }T 1 10 T=
+T{ CMOVE.basic
+T| HERE S" Test" DUP >R HERE 10 + SWAP CMOVE CR
+-> 325 }T 1 10 T=
+T{ CMOVE.empty
+T| HERE HERE 10 + 0 CMOVE
+-> }T 0 0 T=
+Block 7070
+T{ CMOVE.overlap
+T| HERE DUP 1+ 5 CMOVE
+-> }T 0 0 T=
+T{ CMOVE.bounds
+T| HERE PAD 1000 CMOVE
+->ERR
+T{ >IN.initial
+T| >IN @ . CR
+-> }T 11 6895390 T=
+T{ >IN.advances
+T| : TWIN >IN @ >IN @ - . CR ; TWIN
+-> }T 3 47130 T=
+T{ ..positive
+T| 42 . CR
+-> }T 4 1598184 T=
+Block 7071
+T{ ..negative
+T| -42 . CR
+-> }T 5 9602197 T=
+T{ ..zero
+T| 0 . CR
+-> }T 3 47130 T=
+T{ ..max_int
+T| 2147483647 . CR
+-> }T 12 4848918 T=
+T{ ..min_int
+T| -2147483648 . CR
+-> }T 13 5383556 T=
+T{ ..multiple
+T| 1 2 3 . . . CR
+-> }T 7 4767936 T=
+Block 7072
+T{ ..empty_stack
+T| .
+->ERR
+T{ CR.basic
+T| 42 . CR 43 . CR
+-> }T 8 16061841 T=
+T{ CR.multiple
+T| CR CR CR
+-> }T 3 9930 T=
+T{ CR.no_stack_effect
+T| DEPTH CR DEPTH = . CR
+-> }T 4 345040 T=
+T{ CR.after_output
+T| 1 2 3 . . . CR
+-> }T 7 4767936 T=
+Block 7073
+T{ SPACE.basic
+T| 42 . SPACE 43 . CR
+-> }T 8 2824871 T=
+T{ SPACE.multiple
+T| SPACE SPACE SPACE
+-> }T 3 31776 T=
+T{ SPACE.no_stack_effect
+T| DEPTH SPACE DEPTH = . CR
+-> }T 4 1000442 T=
+T{ SPACE.with_text
+T| 65 EMIT SPACE 66 EMIT CR
+-> }T 4 1969223 T=
+T{ SPACES.zero
+T| 0 SPACES
+-> }T 0 0 T=
+Block 7074
+T{ SPACES.one
+T| 1 SPACES
+-> }T 1 32 T=
+T{ SPACES.multiple
+T| 5 SPACES
+-> }T 5 13760544 T=
+T{ SPACES.large
+T| 20 SPACES
+-> }T 20 10692608 T=
+T{ SPACES.negative
+T| -5 SPACES
+-> }T 0 0 T=
+T{ SPACES.with_output
+T| 42 . 3 SPACES 43 . CR
+-> }T 10 11278119 T=
+Block 7075
+T{ SPACES.empty_stack
+T| SPACES
+->ERR
+T{ EMIT.letter_A
+T| 65 EMIT CR
+-> }T 2 2025 T=
+T{ EMIT.letter_Z
+T| 90 EMIT CR
+-> }T 2 2800 T=
+T{ EMIT.digit
+T| 48 EMIT CR
+-> }T 2 1498 T=
+T{ EMIT.space_char
+T| 32 EMIT CR
+-> }T 2 1002 T=
+Block 7076
+T{ EMIT.newline
+T| 10 EMIT
+-> }T 1 10 T=
+T{ EMIT.high_ascii
+T| 127 EMIT CR
+-> }T 2 3947 T=
+T{ EMIT.truncation
+T| 321 EMIT CR
+-> }T 2 2025 T=
+T{ EMIT.negative
+T| -1 EMIT CR
+-> }T 2 1963 T=
+T{ EMIT.sequence
+T| 72 EMIT 73 EMIT 10 EMIT
+-> }T 3 71465 T=
+Block 7077
+T{ EMIT.empty_stack
+T| EMIT
+->ERR
+T{ TYPE.basic_string
+T| HERE S" Hello" DUP >R HERE SWAP CMOVE HERE R> TYPE CR
+-> 400 }T 6 10415512 T=
+T{ TYPE.empty_string
+T| HERE 0 TYPE CR
+-> }T 1 10 T=
+T{ TYPE.single_char
+T| HERE 65 OVER C! 1 TYPE CR
+-> }T 2 2025 T=
+T{ TYPE.numbers
+T| HERE S" 12345" DUP >R HERE SWAP CMOVE HERE R> TYPE CR
+-> 406 }T 6 7734839 T=
+Block 7078
+T{ TYPE.zero_length
+T| PAD 0 TYPE
+-> }T 0 0 T=
+T{ TYPE.one_item
+T| PAD TYPE
+->ERR
+T{ TYPE.empty_stack
+T| TYPE
+->ERR
+T{ COUNT.basic~2
+T| HERE S" Test" DROP C@ HERE 1+ SWAP COUNT . . CR
+-> 412 418 }T 6 12963223 T=
+T{ COUNT.empty~2
+T| HERE 0 OVER C! COUNT . . CR
+-> }T 7 12194453 T=
+Block 7079
+T{ COUNT.max_length~2
+T| HERE 255 OVER C! COUNT . . CR
+-> }T 9 3486519 T=
+T{ COUNT.zero_addr_plus_one
+T| HERE COUNT SWAP 1- = . CR
+-> }T 3 47130 T=
+T{ COUNT.empty_stack~2
+T| COUNT
+->ERR
+T{ WORD.empty_input
+T| BL WORD COUNT . CR
+-> 113 }T 3 47130 T=
+T{ WORD.space_delim
+T| 32 WORD DROP
+-> }T 0 0 T=
+Block 7080
+T{ WORD.newline_delim
+T| 10 WORD DROP
+-> }T 0 0 T=
+T{ WORD.tab_delim
+T| 9 WORD DROP
+-> }T 0 0 T=
+T{ WORD.comma_delim
+T| 44 WORD DROP
+-> }T 0 0 T=
+T{ WORD.skip_leading
+T| BL WORD DROP
+-> }T 0 0 T=
+T{ WORD.single_char
+T| BL WORD COUNT . CR
+-> 113 }T 3 47130 T=
+Block 7081
+T{ WORD.long_word
+T| BL WORD COUNT 0 > . CR
+-> 113 }T 3 47130 T=
+T{ WORD.zero_delim
+T| 0 WORD DROP
+-> }T 0 0 T=
+T{ WORD.high_ascii
+T| 127 WORD DROP
+-> }T 0 0 T=
+T{ WORD.count_format
+T| BL WORD C@ . CR
+-> }T 3 47130 T=
+T{ WORD.count_value
+T| BL WORD COUNT SWAP DROP . CR
+-> }T 3 47130 T=
+Block 7082
+T{ WORD.empty_stack
+T| WORD
+->ERR
+T{ WORD.multi_delim
+T| BL WORD DROP BL WORD DROP
+-> }T 0 0 T=
+T{ BLOCK.basic
+T| 1 BLOCK DUP . CR
+-> 5238784 }T 9 11810843 T=
+T{ BLOCK.zero_block
+T| 0 BLOCK
+->ERR
+T{ BLOCK.large_block
+T| 65536 BLOCK
+->ERR
+Block 7083
+T{ BLOCK.negative
+T| -1 BLOCK
+->ERR
+T{ BLOCK.empty_stack
+T| BLOCK
+->ERR
+T{ BUFFER.basic
+T| 1 BUFFER DUP . CR
+-> 5238784 }T 9 11810843 T=
+T{ BUFFER.zero_block
+T| 0 BUFFER
+->ERR
+T{ BUFFER.flush_dirty
+T| 2 BLOCK 1+ 2 BUFFER
+-> 5239809 5239808 }T 0 0 T=
+Block 7084
+T{ BUFFER.empty_stack
+T| BUFFER
+->ERR
+T{ UPDATE.basic
+T| 1 BLOCK UPDATE
+-> 5238784 }T 0 0 T=
+T{ UPDATE.multiple
+T| 1 BLOCK UPDATE UPDATE
+-> 5238784 }T 0 0 T=
+T{ UPDATE.no_block
+T| 0 SCR ! UPDATE
+->ERR
+T{ SAVE-BUFFERS.basic
+T| SAVE-BUFFERS
+-> }T 0 0 T=
+Block 7085
+T{ SAVE-BUFFERS.dirty_blocks
+T| 1 BLOCK UPDATE SAVE-BUFFERS
+-> 5238784 }T 0 0 T=
+T{ SAVE-BUFFERS.no_dirty
+T| SAVE-BUFFERS
+-> }T 0 0 T=
+T{ EMPTY-BUFFERS.basic
+T| EMPTY-BUFFERS
+-> }T 0 0 T=
+T{ EMPTY-BUFFERS.after_use
+T| 1 BLOCK EMPTY-BUFFERS
+-> 5238784 }T 0 0 T=
+T{ EMPTY-BUFFERS.dirty_blocks
+T| 1 BLOCK UPDATE EMPTY-BUFFERS
+-> 5238784 }T 0 0 T=
+Block 7086
+T{ LOAD.basic
+T| 1 LOAD
+-> }T 0 0 T=
+T{ LOAD.zero_block
+T| 0 LOAD
+->ERR
+T{ LOAD.nonexistent
+T| 9999 LOAD
+->ERR
+T{ LOAD.empty_stack
+T| LOAD
+->ERR
+T{ LIST.basic
+T| 1 LIST
+-> }T 1114 997788 T=
+Block 7087
+T{ LIST.zero_block
+T| 0 LIST
+->ERR
+T{ LIST.nonexistent
+T| 9999 LIST
+->ERR
+T{ LIST.empty_stack
+T| LIST
+->ERR
+T{ SCR.basic
+T| SCR @ . CR
+-> }T 3 48091 T=
+T{ SCR.after_list
+T| 1 LIST SCR @ . CR
+-> }T 1117 12700863 T=
+Block 7088
+T{ SCR.after_load
+T| 1 LOAD SCR @ . CR
+-> }T 0 0 T=
+T{ HERE.basic~2
+T| HERE HERE = . CR
+-> }T 4 1388686 T=
+T{ HERE.after_comma~2
+T| HERE 42 , HERE SWAP - 1 CELLS = 0 SWAP /
+->ERR
+T{ HERE.after_c_comma
+T| HERE 65 C, HERE SWAP - . CR
+-> }T 3 48091 T=
+T{ HERE.after_allot
+T| HERE 10 ALLOT HERE SWAP - . CR
+-> }T 4 1506889 T=
+Block 7089
+T{ HERE.stability
+T| HERE DUP HERE = . CR
+-> 443 }T 4 1388686 T=
+T{ ALLOT.basic~2
+T| HERE 10 ALLOT HERE SWAP - . CR
+-> }T 4 1506889 T=
+T{ ALLOT.zero~2
+T| HERE 0 ALLOT HERE SWAP - . CR
+-> }T 3 47130 T=
+T{ ALLOT.negative~2
+T| HERE -4 ALLOT HERE SWAP - . CR
+-> }T 4 1391569 T=
+T{ ALLOT.large
+T| HERE 100 ALLOT HERE SWAP - . CR
+-> }T 5 13175195 T=
+Block 7090
+T{ ALLOT.after_use
+T| ALIGN HERE 10 ALLOT 42 OVER ! @ . CR
+-> }T 4 1598184 T=
+T{ ALLOT.empty_stack
+T| ALLOT
+->ERR
+T{ ,.basic~2
+T| 42 , HERE 1 CELLS - @ . CR
+-> }T 4 1598184 T=
+T{ ,.negative~2
+T| -999 , HERE 1 CELLS - @ . CR
+-> }T 6 529078 T=
+T{ ,.zero
+T| 0 , HERE 1 CELLS - @ . CR
+-> }T 3 47130 T=
+Block 7091
+T{ ,.max_int
+T| 2147483647 , HERE 1 CELLS - @ . CR
+-> }T 12 4848918 T=
+T{ ,.min_int
+T| -2147483648 , HERE 1 CELLS - @ . CR
+-> }T 13 5383556 T=
+T{ ,.multiple
+T| 10 , 20 , HERE 1 CELLS - @ . HERE 1 CELLS - @ . CR
+-> }T 7 12227402 T=
+T{ ,.empty_stack
+T| ,
+->ERR
+T{ PAD.basic~2
+T| PAD PAD = . CR
+-> }T 4 1388686 T=
+Block 7092
+T{ PAD.different_from_here~2
+T| PAD HERE = . CR
+-> }T 3 47130 T=
+T{ PAD.stability
+T| PAD DUP PAD = . CR
+-> 5242368 }T 4 1388686 T=
+T{ PAD.usable
+T| PAD 42 OVER ! @ . CR
+-> }T 4 1598184 T=
+T{ CREATE.basic
+T| CREATE test1 42 , test1 @ . CR
+-> }T 4 1598184 T=
+T{ CREATE.empty_name
+T| CREATE
+->ERR
+Block 7093
+T{ CREATE.redefine_shadows
+T| CREATE T 1 , CREATE T 2 , T @ . CR
+-> }T 3 49052 T=
+T{ CREATE.duplicate
+T| CREATE test2 CREATE test2
+-> }T 0 0 T=
+T{ CREATE.long_name
+T| CREATE abcdefghijklmnopqrstuvwxyz
+-> }T 0 0 T=
+T{ FORGET.basic
+T| CREATE temp1 FORGET temp1
+-> }T 0 0 T=
+T{ IMMEDIATE.basic
+T| : test3 42 ; IMMEDIATE test3 . CR
+-> }T 4 1598184 T=
+Block 7094
+T{ IMMEDIATE.already_immediate
+T| : test4 43 ; IMMEDIATE IMMEDIATE
+-> }T 0 0 T=
+T{ FIND.existing
+T| FIND DUP . CR
+-> }T 11 15395591 T=
+T{ FIND.user_word
+T| : test5 44 ; FIND test5 . CR
+-> }T 11 8385165 T=
+T{ FIND.nonexistent
+T| FIND nonexistent . CR
+-> }T 3 47130 T=
+T{ FIND.empty
+T| FIND
+->ERR
+Block 7095
+T{ DEFINITIONS.basic
+T| FORTH DEFINITIONS
+-> }T 0 0 T=
+T{ DEFINITIONS.multiple
+T| FORTH DEFINITIONS DEFINITIONS
+-> }T 0 0 T=
+T{ VOCABULARY.basic
+T| VOCABULARY TEST-VOC1 TEST-VOC1 DEFINITIONS
+-> }T 0 0 T=
+T{ VOCABULARY.create_and_switch
+T| VOCABULARY MYVOC MYVOC DEFINITIONS CONTEXT @ . CR
+-> }T 11 11526440 T=
+T{ VOCABULARY.word_isolation
+T| VOCABULARY ISOLATED ISOLATED DEFINITIONS : ISOWORD 99 ; FORTH
+T| DEFINITIONS
+-> }T 0 0 T=
+Block 7096
+T{ VOCABULARY.cross_vocab_access
+T| VOCABULARY V1 V1 DEFINITIONS : V1WORD 11 ; FORTH V1WORD . CR
+-> }T 4 1507850 T=
+T{ VOCABULARY.multiple_vocabs
+T| VOCABULARY VA VOCABULARY VB VOCABULARY VC VA DEFINITIONS
+-> }T 0 0 T=
+T{ VOCABULARY.duplicate
+T| VOCABULARY TESTVOC VOCABULARY TESTVOC
+->ERR
+T{ VOCABULARY.empty_name
+T| VOCABULARY
+->ERR
+T{ FORTH.basic
+T| FORTH DEFINITIONS
+-> }T 0 0 T=
+Block 7097
+T{ FORTH.persistence
+T| FORTH : TEST1 42 ; TEST1 . CR
+-> }T 4 1598184 T=
+T{ FORTH.from_other
+T| VOCABULARY OTHER-VOC OTHER-VOC FORTH
+-> }T 0 0 T=
+T{ DEFINITIONS.basic~2
+T| FORTH DEFINITIONS
+-> }T 0 0 T=
+T{ DEFINITIONS.new_vocab
+T| VOCABULARY TEST-VOC6 TEST-VOC6 DEFINITIONS
+-> }T 0 0 T=
+T{ DEFINITIONS.word_creation
+T| VOCABULARY TEST-VOC7 TEST-VOC7 DEFINITIONS : TEST2 43 ;
+-> }T 0 0 T=
+Block 7098
+T{ CONTEXT.basic
+T| CONTEXT @ . CR
+-> }T 11 8729384 T=
+T{ CONTEXT.initial
+T| FORTH CONTEXT @ . CR
+-> }T 11 2699444 T=
+T{ CURRENT.basic
+T| CURRENT @ . CR
+-> }T 11 8729384 T=
+T{ CURRENT.after_def
+T| VOCABULARY TEST-VOC8 TEST-VOC8 DEFINITIONS CURRENT @ . CR
+-> }T 11 14389674 T=
+T{ ABORT.basic
+T| ABORT
+-> }T 0 0 T=
+Block 7099
+T{ ABORT.with_data
+T| 1 2 3 ABORT DEPTH . CR
+-> }T 0 0 T=
+T{ ABORT.in_definition_runtime
+T| : BAD-WORD ABORT ; 123 BAD-WORD DEPTH . CR
+-> }T 0 0 T=
+T{ :.basic
+T| : TEST1 42 ; TEST1 . CR
+-> }T 4 1598184 T=
+T{ :.empty_name
+T| :
+->ERR
+T{ ;.alone
+T| ;
+->ERR
+Block 7100
+T{ ;.immediate
+T| : TEST4 42 ; IMMEDIATE TEST4 . CR
+-> }T 4 1598184 T=
+T{ CONSTANT.basic
+T| 42 CONSTANT MEANING MEANING . CR
+-> }T 4 1598184 T=
+T{ CONSTANT.zero
+T| 0 CONSTANT ZERO ZERO . CR
+-> }T 3 47130 T=
+T{ CONSTANT.negative
+T| -1 CONSTANT MINUS MINUS . CR
+-> }T 4 1388686 T=
+T{ CONSTANT.empty_stack
+T| CONSTANT
+->ERR
+Block 7101
+T{ VARIABLE.basic
+T| VARIABLE VAR1 42 VAR1 ! VAR1 @ . CR
+-> }T 4 1598184 T=
+T{ VARIABLE.multiple
+T| VARIABLE VAR2 VARIABLE VAR3
+-> }T 0 0 T=
+T{ VARIABLE.store_fetch
+T| VARIABLE VAR4 -99 VAR4 ! VAR4 @ . CR
+-> }T 5 9757879 T=
+T{ CREATE.basic~2
+T| CREATE OBJ1
+-> }T 0 0 T=
+T{ CREATE.with_data
+T| CREATE OBJ2 42 , OBJ2 @ . CR
+-> }T 4 1598184 T=
+Block 7102
+T{ CREATE.empty_name~2
+T| CREATE
+->ERR
+T{ DOES>.basic
+T| : CONST CREATE , DOES> @ ; 42 CONST MEANING MEANING . CR
+-> }T 4 1598184 T=
+T{ DOES>.multiple
+T| : ARRAY CREATE DOES> SWAP CELLS + ; CREATE ARR 10 CELLS ALLOT
+-> }T 0 0 T=
+T{ DOES>.outside
+T| DOES>
+->ERR
+T{ [.basic
+T| : TEST5 [ 42 ] LITERAL ; TEST5 . CR
+-> }T 4 1598184 T=
+Block 7103
+T{ [.outside
+T| [
+-> }T 0 0 T=
+T{ ].nested
+T| : TEST6 [ ] 42 ; TEST6 . CR
+-> }T 4 1598184 T=
+T{ IF.true
+T| : TEST1 IF 42 ELSE 24 THEN ; -1 TEST1 . CR
+-> -1 }T 4 1598184 T=
+T{ IF.false
+T| : TEST2 IF 42 ELSE 24 THEN ; 0 TEST2 . CR
+-> 0 }T 4 1599145 T=
+T{ IF.nested
+T| : TEST3 IF IF 1 ELSE 2 THEN ELSE 3 THEN ; -1 -1 TEST3 . CR
+-> }T 3 48091 T=
+Block 7104
+T{ IF.no_else
+T| : TEST4 IF 42 THEN ; -1 TEST4 . CR
+-> }T 4 1598184 T=
+T{ IF.empty_stack
+T| IF
+->ERR
+T{ ELSE.alone
+T| ELSE
+->ERR
+T{ THEN.alone
+T| THEN
+->ERR
+T{ BEGIN.until
+T| : TEST5 0 BEGIN 1+ DUP 5 = UNTIL ; TEST5 . CR
+-> }T 3 51935 T=
+Block 7105
+T{ BEGIN.while
+T| : TEST6 0 BEGIN DUP 5 < WHILE 1+ REPEAT ; TEST6 . CR
+-> }T 3 51935 T=
+T{ BEGIN.alone
+T| BEGIN
+->ERR
+T{ UNTIL.basic
+T| : TEST8 BEGIN DUP 1- DUP 0= UNTIL ; 5 TEST8 . CR
+-> 5 4 3 2 1 }T 3 47130 T=
+T{ UNTIL.immediate
+T| : TEST9 BEGIN 1 UNTIL ; IMMEDIATE
+-> }T 0 0 T=
+T{ UNTIL.no_begin
+T| UNTIL
+->ERR
+Block 7106
+T{ WHILE.basic
+T| : TEST10 BEGIN DUP 5 < WHILE 1+ REPEAT ; 0 TEST10 . CR
+-> }T 3 51935 T=
+T{ WHILE.zero_times
+T| : TEST11 BEGIN DUP 0< WHILE 1+ REPEAT ; 0 TEST11 . CR
+-> }T 3 47130 T=
+T{ WHILE.no_begin
+T| WHILE
+->ERR
+T{ REPEAT.basic
+T| : TEST12 BEGIN DUP 5 < WHILE 1+ REPEAT ; 0 TEST12 . CR
+-> }T 3 51935 T=
+T{ REPEAT.no_while
+T| REPEAT
+->ERR
+Block 7107
+T{ DO.basic
+T| : TEST13 5 0 DO I . LOOP ; TEST13 CR
+-> }T 11 12528484 T=
+T{ DO.negative
+T| : TEST14 -1 -5 DO I . LOOP ; TEST14 CR
+-> }T 13 11696776 T=
+T{ DO.empty
+T| : TEST15 0 0 DO LOOP ;
+-> }T 0 0 T=
+T{ DO.nested
+T| : TEST16 3 0 DO 3 0 DO J I + . LOOP LOOP ; TEST16 CR
+-> }T 19 14426156 T=
+T{ LOOP.basic
+T| : TEST20 5 0 DO I . LOOP ; TEST20 CR
+-> }T 11 12528484 T=
+Block 7108
+T{ LOOP.no_do
+T| LOOP
+->ERR
+T{ +LOOP.basic
+T| : TEST21 10 0 DO I . 2 +LOOP ; TEST21 CR
+-> }T 11 16410222 T=
+T{ +LOOP.negative
+T| : TEST22 0 10 DO I . -1 +LOOP ; TEST22 CR
+-> }T 24 15411990 T=
+T{ +LOOP.variable
+T| : TEST23 10 0 DO I . DUP +LOOP ; 3 TEST23 CR
+-> 3 }T 9 8104156 T=
+T{ I.basic
+T| : TI 4 0 DO I . LOOP CR ; TI
+-> }T 9 7781840 T=
+Block 7109
+T{ I.single
+T| : TI1 1 0 DO I . LOOP CR ; TI1
+-> }T 3 47130 T=
+T{ I.offset
+T| : TI2 5 3 DO I . LOOP CR ; TI2
+-> }T 5 14549425 T=
+T{ I.in_expr
+T| : TI3 3 0 DO I 2 * . LOOP CR ; TI3
+-> }T 7 9837120 T=
+T{ J.basic
+T| : TJ 2 0 DO 3 0 DO J . LOOP LOOP CR ; TJ
+-> }T 13 4074221 T=
+T{ J.paired
+T| : TJ2 2 0 DO 2 0 DO J I + . LOOP LOOP CR ; TJ2
+-> }T 9 6857358 T=
+Block 7110
+T{ EXIT.early_return
+T| : TEX 5 EXIT 99 ; TEX . CR
+-> }T 3 51935 T=
+T{ EXIT.cond_exit_pos
+T| : TEX2 DUP 0> IF EXIT THEN NEGATE ; 3 TEX2 . CR
+-> }T 3 50013 T=
+T{ EXIT.cond_exit_neg
+T| : TEX2 DUP 0> IF EXIT THEN NEGATE ; -4 TEX2 . CR
+-> }T 3 50974 T=
+T{ EXIT.no_skipped
+T| : TEX3 1 2 EXIT 3 ; TEX3 . . CR
+-> }T 5 13623021 T=
+T{ LEAVE.basic
+T| : TLV 0 5 0 DO I 3 = IF LEAVE THEN 1+ LOOP ; TLV . CR
+-> }T 3 50013 T=
+Block 7111
+T{ LEAVE.at_start
+T| : TLV2 0 5 0 DO LEAVE 1+ LOOP ; TLV2 . CR
+-> }T 3 47130 T=
+T{ LEAVE.qdloop
+T| : TLV3 0 5 0 ?DO I 2 = IF LEAVE THEN 1+ LOOP ; TLV3 . CR
+-> }T 3 49052 T=
+Block 7112
+T-REPORT
+FORGET T# DECIMAL
diff --git a/logs/20261005-160144/amd64/qemu-amd64-20261005-160144.log b/logs/20261005-160144/amd64/qemu-amd64-20261005-160144.log
new file mode 100644
index 00000000..a2c80e67
--- /dev/null
+++ b/logs/20261005-160144/amd64/qemu-amd64-20261005-160144.log
@@ -0,0 +1,108 @@
+[2J[001;001H[=3h[2J[001;001H[2J[001;001H[8;042;160t[2J[001;001H[2J[001;001H[8;056;240t[2J[001;001HBdsDxe: loading Boot0002 "UEFI QEMU DVD-ROM QM00005 " from PciRoot(0x0)/Pci(0x1F,0x2)/Sata(0x2,0xFFFF,0x0)
+BdsDxe: starting Boot0002 "UEFI QEMU DVD-ROM QM00005 " from PciRoot(0x0)/Pci(0x1F,0x2)/Sata(0x2,0xFFFF,0x0)
+[2J[001;001H[=3h[2J[001;001HStarKernel UEFI Loader
+Loading kernel from ESP...
+[CKPT 001] Entered efi_main - ConOut live
+RAW SERIAL UP
+[CKPT 002] Serial (COM1) initialized
+Monolithic build - kernel linked directly
+Collecting boot information...
+CmdLine: parsed OK
+[CKPT 004] Command line parsed
+[CKPT 005] Kernel stack allocation decided
+[CKPT 006] Boot info collected (ACPI table located)
+GOP: linear framebuffer found
+[CKPT 007] GOP: linear framebuffer found
+[CKPT 008] About to enter ExitBootServices retry loop
+EBS...
+EBS OK
+Calling kernel_main (monolithic)...
+
+
+ _____ _ _ __ _
+ / ____| | | |/ / | |
+ | (___ | |_ __ _ _ __| ' / ___ _ __ _ __ ___| |
+ \___ \| __/ _` | '__| < / _ \ '__| '_ \ / _ \ |
+ ____) | || (_| | | | . \ __/ | | | | | __/ |
+ |_____/ \__\__,_|_| |_|\_\___|_| |_| |_|\___|_|
+
+LithosAnanke v2.1.0
+Architecture: amd64
+Build: Oct 5 2026 16:01:18
+
+UEFI BootServices: EXITED
+
+=== StarKernel Boot Information ===
+Memory map entries: 131
+Total memory: 1023 MB
+Usable memory: 968 MB
+===================================
+
+PMM initialized.
+PMM statistics:
+ Total pages: 249248
+ Free pages : 247725
+ Used pages : 1523
+ Total MB : 973
+ Free MB : 967
+ Used MB : 5
+
+VMM initialized (mapped RAM, CR3 switched)
+VMM initialized (mapped RAM, CR3 switched)
+VMM self-test: mapped OK at 0xffff800000000000
+VMM self-test complete.
+
+IDT installed.
+
+APIC: init...
+APIC: IA32_APIC_BASE MSR=0x00000000fee00900
+APIC: stale-ISR drain: 0 EOI(s) issued
+APIC: initialized (xAPIC MMIO, TPR=0, SIVR=0x1FF, EOI-clear)
+APIC: init done
+
+I/O APIC: init...
+I/O APIC: base=0xfec00000, gsi_base=0, overrides=5
+ override: source=00 gsi=2 flags=0x0000
+ override: source=05 gsi=5 flags=0x000d
+ override: source=09 gsi=9 flags=0x000d
+ override: source=0a gsi=10 flags=0x000d
+ override: source=0b gsi=11 flags=0x000d
+i8042: keyboard ACKed enable-scanning
+i8042: IRQ1 enabled in controller config byte
+I/O APIC: keyboard IRQ1 routed (masked)
+
+Timer: init...
+Timer: init start
+Timer: PM_TMR_BLK discovered from FADT at port 1544
+Timer: VM mode detected (hypervisor present).
+Timer: HPET calibration disabled (VM-exit MMIO would poison timing).
+Timer: WARNING: invariant TSC not present under hypervisor.
+Timer: continuing in RELATIVE mode (no determinism guarantees).
+Timer: RDTSCP not present; using RDTSC (less serialized).
+Timer: CPUID frequency unavailable; trying PM Timer...
+Timer: trust=1 (0=NONE,1=REL,2=ABS), TSC=2102894063 Hz
+Timer: init done
+
+Kernel heap initialized.
+Heap statistics:
+ Total bytes: 536870872
+ Free bytes: 536870872
+ Used bytes: 0
+ Peak bytes: 0
+ Heap base addr: 24641536
+ Heap end addr: 561512448
+
+Heartbeat: init...
+APIC Timer: calibrating...
+APIC Timer: apic_hz=1010732930, tick_hz=100, initial_count=10107329
+APIC Timer: configured (masked, ready to start)
+Heartbeat: init done
+Kernel initialization complete.
+Boot successful!
+
+StarForth v4: one host node, the F18-derived engine
+PARITY:V4_NUCLEUS words=295 image_hash=0x3ed5d5fc83f0b026
+V4: capsule v4:forth79.4th signature: missing (unsigned)
+PARITY:V4_CAPSULE name=v4:forth79.4th capsule_id=0xa4b74bdc7deaf204 capsule_hash=0xa4b74bdc7deaf204 dict_hash=0x118de9d37e682ea4
+PARITY:OK
+ok>
\ No newline at end of file
diff --git a/logs/20261005-160234/aarch64/qemu-aarch64-20261005-160234.log b/logs/20261005-160234/aarch64/qemu-aarch64-20261005-160234.log
new file mode 100644
index 00000000..dcc257d0
--- /dev/null
+++ b/logs/20261005-160234/aarch64/qemu-aarch64-20261005-160234.log
@@ -0,0 +1,82 @@
+UEFI firmware (version 2025.11-3ubuntu7.3 built at 15:40:26 on Sep 23 2026)
+[2J[001;001H[=3h[2J[001;001H[2J[001;001H[8;031;100t[2J[001;001HBdsDxe: failed to load Boot0002 "UEFI Misc Device" from PciRoot(0x0)/Pci(0x2,0x0): Not Found
+BdsDxe: failed to load Boot0003 "UEFI QEMU QEMU USB HARDDRIVE 1-0000:00:04.0-1" from PciRoot(0x0)/Pci(0x4,0x0)/USB(0x0,0x0): Not Found
+BdsDxe: loading Boot0004 "UEFI Misc Device 2" from PciRoot(0x0)/Pci(0x6,0x0)
+BdsDxe: starting Boot0004 "UEFI Misc Device 2" from PciRoot(0x0)/Pci(0x6,0x0)
+[2J[001;001H[=3h[2J[001;001HStarKernel UEFI Loader
+Loading kernel from ESP...
+[CKPT 001] Entered efi_main - ConOut live
+Collecting boot information...
+[CKPT 004] Command line parsed
+[CKPT 005] Kernel stack allocation decided
+[CKPT 006] Boot info collected (ACPI table located)
+[CKPT 007] GOP: linear framebuffer found
+[CKPT 008] About to enter ExitBootServices retry loop
+
+
+ _____ _ _ __ _
+ / ____| | | |/ / | |
+ | (___ | |_ __ _ _ __| ' / ___ _ __ _ __ ___| |
+ \___ \| __/ _` | '__| < / _ \ '__| '_ \ / _ \ |
+ ____) | || (_| | | | . \ __/ | | | | | __/ |
+ |_____/ \__\__,_|_| |_|\_\___|_| |_| |_|\___|_|
+
+LithosAnanke v2.1.0
+Architecture: aarch64
+Build: Oct 5 2026 16:02:10
+
+UEFI BootServices: EXITED
+
+=== StarKernel Boot Information ===
+Memory map entries: 108
+Total memory: 4093 MB
+Usable memory: 4056 MB
+===================================
+
+PMM initialized.
+PMM statistics:
+ Total pages: 1039860
+ Free pages : 1038449
+ Used pages : 1411
+ Total MB : 4061
+ Free MB : 4056
+ Used MB : 5
+
+VMM initialized (mapped RAM, CR3 switched)
+VMM initialized (mapped RAM, CR3 switched)
+VMM self-test: mapped OK at 0xffff800000000000
+VMM self-test complete.
+
+AArch64: running at EL1
+IDT installed.
+
+APIC: init...
+PSCI: no DTB -- using HVC (QEMU virt-machine default)
+GICv2: no DTB GIC node -- using QEMU virt-machine defaults
+GICv2: distributor+CPU interface enabled, PPI 30
+APIC: init done
+
+Timer: init...
+Timer: AArch64 generic timer initialised.
+Timer: init done
+
+Kernel heap initialized.
+Heap statistics:
+ Total bytes: 2147483608
+ Free bytes: 2147483608
+ Used bytes: 0
+ Peak bytes: 0
+ Heap base addr: 1207959552
+ Heap end addr: 3355443200
+
+Heartbeat: init...
+Heartbeat: init done
+Kernel initialization complete.
+Boot successful!
+
+StarForth v4: one host node, the F18-derived engine
+PARITY:V4_NUCLEUS words=295 image_hash=0x3ed5d5fc83f0b026
+V4: capsule v4:forth79.4th signature: missing (unsigned)
+PARITY:V4_CAPSULE name=v4:forth79.4th capsule_id=0xa4b74bdc7deaf204 capsule_hash=0xa4b74bdc7deaf204 dict_hash=0x118de9d37e682ea4
+PARITY:OK
+ok>
\ No newline at end of file
diff --git a/logs/20261005-160400/riscv64/qemu-riscv64-20261005-160400.log b/logs/20261005-160400/riscv64/qemu-riscv64-20261005-160400.log
new file mode 100644
index 00000000..7bdc2c2c
--- /dev/null
+++ b/logs/20261005-160400/riscv64/qemu-riscv64-20261005-160400.log
@@ -0,0 +1,152 @@
+
+OpenSBI v1.8
+ ____ _____ ____ _____
+ / __ \ / ____| _ \_ _|
+ | | | |_ __ ___ _ __ | (___ | |_) || |
+ | | | | '_ \ / _ \ '_ \ \___ \| _ < | |
+ | |__| | |_) | __/ | | |____) | |_) || |_
+ \____/| .__/ \___|_| |_|_____/|____/_____|
+ | |
+ |_|
+
+Platform Name : riscv-virtio,qemu
+Platform Features : medeleg
+Platform HART Count : 1
+Platform HART Protection : pmp
+Platform IPI Device : aclint-mswi
+Platform Timer Device : aclint-mtimer @ 10000000Hz
+Platform Console Device : uart8250
+Platform HSM Device : ---
+Platform PMU Device : ---
+Platform Reboot Device : syscon-reboot
+Platform Shutdown Device : syscon-poweroff
+Platform Suspend Device : ---
+Platform CPPC Device : ---
+Firmware Base : 0x80000000
+Firmware Size : 321 KB
+Firmware RW Offset : 0x40000
+Firmware RW Size : 65 KB
+Firmware Heap Offset : 0x47000
+Firmware Heap Size : 37 KB (total), 0 KB (reserved), 12 KB (used), 23 KB (free)
+Firmware Scratch Size : 4096 B (total), 1464 B (used), 2632 B (free)
+Runtime SBI Version : 3.0
+Standard SBI Extensions : ipi,pmu,srst,sse,hsm,rfnc,fwft,time,base,legacy,dbcn,dbtr
+Experimental SBI Extensions : none
+
+Domain0 Name : root
+Domain0 Boot HART : 0
+Domain0 HARTs : 0*
+Domain0 Region00 : 0x0000000080040000-0x000000008005ffff M: (F,R,W) S/U: ()
+Domain0 Region01 : 0x0000000080000000-0x000000008003ffff M: (F,R,X) S/U: ()
+Domain0 Region02 : 0x0000000000100000-0x0000000000100fff M: (I,R,W) S/U: (R,W)
+Domain0 Region03 : 0x0000000010000000-0x0000000010000fff M: (I,R,W) S/U: (R,W)
+Domain0 Region04 : 0x0000000002000000-0x000000000200ffff M: (I,R,W) S/U: ()
+Domain0 Region05 : 0x000000000c400000-0x000000000c5fffff M: (I,R,W) S/U: (R,W)
+Domain0 Region06 : 0x000000000c000000-0x000000000c3fffff M: (I,R,W) S/U: (R,W)
+Domain0 Region07 : 0x0000000000000000-0xffffffffffffffff M: () S/U: (R,W,X)
+Domain0 Next Address : 0x0000000020000000
+Domain0 Next Arg1 : 0x00000000bfe00000
+Domain0 Next Mode : S-mode
+Domain0 SysReset : yes
+Domain0 SysSuspend : yes
+
+Boot HART ID : 0
+Boot HART Domain : root
+Boot HART Priv Version : v1.12
+Boot HART Base ISA : rv64imafdch
+Boot HART ISA Extensions : sstc,zicntr,zihpm,zicboz,zicbom,sdtrig,svadu
+Boot HART PMP Count : 16
+Boot HART PMP Granularity : 2 bits
+Boot HART PMP Address Bits : 54
+Boot HART MHPM Info : 16 (0x0007fff8)
+Boot HART Debug Triggers : 2 triggers
+Boot HART MIDELEG : 0x0000000000001666
+Boot HART MEDELEG : 0x0000000000f4b509
+[2J[004D[=3h[2J[009D[2J[004D[8;031;100t[2J[016DRISC-V EDK2 firmware version 2025.11-3ubuntu7.3
+Press ESCAPE within 5 seconds for boot options ERROR: C40000002:V03051002 I0 6D33944A-EC75-4855-A54D-809C75241F6C 83FFF850
+BdsDxe: failed to load Boot0001 "UEFI Misc Device" fr
+om PciRoot(0x0)/Pci(0x1,0x0): Not Found
+[2J[001;001H[=3h[2J[009DStarKernel UEFI Loader
+Loading kernel from ESP...
+[CKPT 001] Entered efi_main - ConOut live
+Monolithic build - kernel linked directly
+Collecting boot information...
+CmdLine: parsed OK
+[CKPT 004] Command line parsed
+[CKPT 005] Kernel stack allocation decided
+[CKPT 006] Boot info collected (ACPI table located)
+GOP: linear framebuffer found
+[CKPT 007] GOP: linear framebuffer found
+[CKPT 008] About to enter ExitBootServices retry loop
+Calling kernel_main (monolithic)...
+riscv64 item 4.3.5a: satp state at kernel entry (before switch)
+ satp.MODE = 0x000000000000000a
+ satp.PPN = 0x00000000000bf868
+ __kernel_start = 0x00000000bde99936
+riscv64: satp cleared -- Bare mode, explicit (item 4.3.5a)
+
+
+ _____ _ _ __ _
+ / ____| | | |/ / | |
+ | (___ | |_ __ _ _ __| ' / ___ _ __ _ __ ___| |
+ \___ \| __/ _` | '__| < / _ \ '__| '_ \ / _ \ |
+ ____) | || (_| | | | . \ __/ | | | | | __/ |
+ |_____/ \__\__,_|_| |_|\_\___|_| |_| |_|\___|_|
+
+LithosAnanke v2.1.0
+Architecture: riscv64
+Build: Oct 5 2026 16:03:23
+
+UEFI BootServices: EXITED
+
+=== StarKernel Boot Information ===
+Memory map entries: 100
+Total memory: 1020 MB
+Usable memory: 977 MB
+===================================
+
+PMM initialized.
+PMM statistics:
+ Total pages: 250775
+ Free pages : 250123
+ Used pages : 652
+ Total MB : 979
+ Free MB : 977
+ Used MB : 2
+
+VMM initialized (mapped RAM, CR3 switched)
+VMM initialized (mapped RAM, CR3 switched)
+VMM self-test: mapped OK at 0xffff800000000000
+VMM self-test complete.
+
+IDT installed.
+
+APIC: init...
+PLIC: no DTB PLIC node -- using QEMU virt-machine default (base=0x0c000000)
+PLIC: init (S-mode context 1, threshold=0)
+APIC: init done
+
+Timer: init...
+Timer: RISC-V time CSR @ 10000000 Hz (FALLBACK, no devicetree)
+Timer: init done
+
+Kernel heap initialized.
+Heap statistics:
+ Total bytes: 536870872
+ Free bytes: 536870872
+ Used bytes: 0
+ Peak bytes: 0
+ Heap base addr: 2214588416
+ Heap end addr: 2751459328
+
+Heartbeat: init...
+Heartbeat: init done
+Kernel initialization complete.
+Boot successful!
+
+StarForth v4: one host node, the F18-derived engine
+PARITY:V4_NUCLEUS words=295 image_hash=0x3ed5d5fc83f0b026
+V4: capsule v4:forth79.4th signature: missing (unsigned)
+PARITY:V4_CAPSULE name=v4:forth79.4th capsule_id=0xa4b74bdc7deaf204 capsule_hash=0xa4b74bdc7deaf204 dict_hash=0x118de9d37e682ea4
+PARITY:OK
+ok>
\ No newline at end of file
diff --git a/v4/Makefile b/v4/Makefile
index c5b983fa..52e571aa 100644
--- a/v4/Makefile
+++ b/v4/Makefile
@@ -129,6 +129,20 @@ $(BINDIR)/boot-$(1).txt: $(BINDIR)/starforth4-$(1)
endef
$(foreach i,$(HOSTED_ISAS),$(eval $(call HOSTED_RULE,$(i))))
+# `make post` builds the amd64 system with POST in its boot
+# (V4_POST_AT_BOOT=1, system/boot.c) and boots it: the POST capsule,
+# ../capsules/v4/post79.4th, is loaded after forth79.4th and must end with a
+# clean tally. `make post79` writes that capsule again from v3's cases
+# (tools/mkpost.py); it needs the hosted v3 binary.
+.PHONY: post post79
+$(BINDIR)/starforth4-post: $(HERE)/tools/hosted.c $(BINDIR)/v4_image_64.c $(CAPSULE_DIR_C) $(ENGINE_SRCS) $(SYSTEM_SRCS) $(wildcard $(HERE)/include/v4/*.h) $(HERE)/Makefile
+ $(CC_amd64) $(CFLAGS) -D_POSIX_C_SOURCE=200809L -I$(HERE)/include -DV4_CELL_BITS=64 $(HOST_DEFS) -c $(HERE)/tools/hosted.c -o $(BINDIR)/hosted-post.o
+ $(CC_amd64) $(SYSTEM_CFLAGS) -DV4_POST_AT_BOOT=1 -static $(BINDIR)/hosted-post.o $(BINDIR)/v4_image_64.c $(CAPSULE_DIR_C) $(ENGINE_SRCS) $(SYSTEM_SRCS) -o $@
+post: $(BINDIR)/starforth4-post
+ @$(BINDIR)/starforth4-post < /dev/null
+post79:
+ python3 $(HERE)/tools/mkpost.py
+
# `make hosted` builds the three. `make hosted-check` boots each with no
# input and requires that all three print the same lines, ending in
# PARITY:OK and the prompt: the same hashes on every ISA.
diff --git a/v4/README.md b/v4/README.md
index b2f6e6f6..35e615f5 100644
--- a/v4/README.md
+++ b/v4/README.md
@@ -55,21 +55,58 @@ and fails unless their output is identical and ends in `PARITY:OK`.
A capsule line the node does not answer ` ok` to ends the boot, naming the
capsule, block and line, with `PARITY:FAIL` and `POST: FAILED`.
-State, 2026-10-05: capsule loading works on all six builds. The three hosted
-binaries and the three bare-metal kernels (`clean qemu` with `STARFORTH_V4=1`)
-print the same four lines and reach `ok>`:
+State, 2026-10-05, after the POST work began: all six builds load
+`v4:forth79.4th` and reach `ok>` with the same lines:
```
-PARITY:V4_NUCLEUS words=292 image_hash=0x60b74e4f87adb0ac
-PARITY:V4_CAPSULE name=v4:forth79.4th capsule_id=0xa4b74bdc7deaf204 capsule_hash=0xa4b74bdc7deaf204 dict_hash=0x0baed67626b4fac4
+PARITY:V4_NUCLEUS words=295 image_hash=0x3ed5d5fc83f0b026
+PARITY:V4_CAPSULE name=v4:forth79.4th capsule_id=0xa4b74bdc7deaf204 capsule_hash=0xa4b74bdc7deaf204 dict_hash=0x118de9d37e682ea4
PARITY:OK
ok>
```
-Bare-metal logs: `logs/20261005-152955/amd64/`, `logs/20261005-154021/aarch64/`,
-`logs/20261005-154150/riscv64/`. Each run was ended once the prompt was in the
+Bare-metal logs: `logs/20261005-160144/amd64/`, `logs/20261005-160234/aarch64/`,
+`logs/20261005-160400/riscv64/`. Each run was ended once the prompt was in the
log; nothing was typed at a bare-metal prompt, so keyboard input there is not
yet verified. The capsules were unsigned (no signing key on this machine).
-`forth79.4th` holds no definitions yet: all 292 words are still in the
-nucleus. There is no POST yet.
+`forth79.4th` holds no definitions yet: every word is still in the nucleus.
+
+## POST
+
+`capsules/v4/post79.4th` is v3's POST cases for the FORTH-79 Required Word
+Set, written by `v4/tools/mkpost.py` (`make -C v4 post79`): 537 cases in
+blocks 7000–7112, covering 111 of the 130 required words. Each case carries
+what the hosted v3 binary did with the same line — error or not, the stack,
+the length and checksum of what was printed — and v4 must do the same.
+
+**POST does not pass yet, so it is not in the boot.** `make -C v4 post` builds
+the amd64 system with it (`-DV4_POST_AT_BOOT=1`) and boots it:
+
+```
+PARITY:V4_POST tests=537 pass=439 fail=98
+PARITY:FAIL
+POST: FAILED
+```
+
+The 98 are not yet sorted into v4 defects and differences that need a
+ruling. A first reading finds four kinds:
+
+| Kind | About | Examples |
+|---|---|---|
+| The case prints or leaves a memory address, which differs between the two machines | 40 | `HERE`, `PAD`, `1 BLOCK`, `BL WORD`, `CONTEXT @ .`, `FIND` |
+| v3 departs from FORTH-79 and v4 follows the standard | 35 | `PICK` and `ROLL` count from 1; `<# # #S #>` take a double number; `LEAVE` ends the loop at the next `LOOP`; `>R` `R>` only inside a definition |
+| The case assumes v3's byte address units, where a v4 address unit is a cell (D-1) | 8 | `42 , HERE 8 - @`, `PAD 42 OVER !` |
+| Not yet understood | 15 | vocabulary cases, `LIST`'s layout, `16 BASE ! 255 .`, `321 EMIT`, cases v3 ends in an error and v4 does not |
+
+Required words with no v3 case, and so no POST case: `U*` `U/MOD` `?`
+`EXECUTE` `KEY` `EXPECT` `QUERY` `U.` `CONVERT` `'` `."` `LITERAL` `STATE`
+`COMPILE` `[COMPILE]` `(` `QUIT` `BLK` `79-STANDARD`. `U*` and `U/MOD` are
+in neither v3 nor v4.
+
+Twelve v3 cases are left out: three read the keyboard, two forget a word of
+the system, two store to the search order, and five leave v3 unable to
+continue in one session (`mkpost.py` prints the list).
+
+The boot passes POST only on seeing the tally line with `fail=0`
+(`v4/system/boot.c`); that no line was refused is not enough.
diff --git a/v4/capsule/quit.v4 b/v4/capsule/quit.v4
index 44926d11..3b7d713c 100644
--- a/v4/capsule/quit.v4
+++ b/v4/capsule/quit.v4
@@ -68,6 +68,11 @@ macro R-CLEAR RSTACK-DEPTH b! a !b endmacro
\ FORTH-79: clear the return stack, set execution mode, return control to
\ the terminal; no message is given. The data stack is left as it is.
+\ NODE-ERROR, by name: how a definition written in FORTH raises an error.
+\ A store of a code that is not zero is the trap of D-18 -- the word goes no
+\ further, the message for the code is printed (-1: the word has printed
+\ its own) and the line ends with ERROR. The codes are listed in core.v4.
+header NODE-ERROR inline : NODE-ERROR' NODE-ERROR ;
header (CATCH) inline : (CATCH)' (CATCH) ;
header (EMIT-HOOK) inline : (EMIT-HOOK)' (EMIT-HOOK) ;
diff --git a/v4/include/v4/boot.h b/v4/include/v4/boot.h
index b925c5b0..80361ca0 100644
--- a/v4/include/v4/boot.h
+++ b/v4/include/v4/boot.h
@@ -6,8 +6,11 @@
* the text goes. So the two start the same way and print the same lines:
*
* PARITY:V4_NUCLEUS words=N image_hash=0x...
- * PARITY:V4_CAPSULE name=... capsule_id=0x... capsule_hash=0x... dict_hash=0x...
+ * PARITY:V4_CAPSULE name=v4:forth79.4th capsule_id=0x... capsule_hash=0x... dict_hash=0x...
+ * PARITY:V4_POST tests=N pass=N fail=N (printed by the POST capsule)
+ * PARITY:V4_CAPSULE name=v4:post79.4th capsule_id=0x... capsule_hash=0x... dict_hash=0x...
* PARITY:OK
+ * POST: PASSED
* ok>
*
* or, if anything is wrong, what was wrong and then
diff --git a/v4/system/boot.c b/v4/system/boot.c
index e3e0ddf1..840a9fff 100644
--- a/v4/system/boot.c
+++ b/v4/system/boot.c
@@ -11,7 +11,18 @@
#include "starkernel/capsule_blocks.h"
/* The capsules, in the order they are loaded. */
-static const char *const boot_capsules[] = { "v4:forth79.4th" };
+/* POST is not yet part of the boot: v4:post79.4th does not pass yet
+ * (v4/README.md). Build with -DV4_POST_AT_BOOT=1 to load it and to require
+ * its clean tally; `make -C v4 post` does. */
+#ifndef V4_POST_AT_BOOT
+#define V4_POST_AT_BOOT 0
+#endif
+static const char *const boot_capsules[] = {
+ "v4:forth79.4th",
+#if V4_POST_AT_BOOT
+ "v4:post79.4th",
+#endif
+};
#define LINE_MAX 80u /* QUERY takes 80 characters, the new-line among them */
#define STEP_LIMIT 4000000000ULL /* instruction words one line may take */
@@ -105,6 +116,37 @@ typedef struct {
unsigned len;
} tail;
+/* POST's verdict. The POST capsule ends by printing one line,
+ * PARITY:V4_POST tests=N pass=N fail=N
+ * and the boot passes only if it has seen that line with fail=0. That no
+ * line was refused is not enough: a POST that was broken half way would
+ * refuse nothing. */
+static char post_line[96];
+static unsigned post_len;
+static int post_seen, post_clean;
+
+static int text_at(const char *line, unsigned len, unsigned at, const char *want)
+{
+ unsigned i;
+ for (i = 0; want[i]; i++)
+ if (at + i >= len || line[at + i] != want[i]) return 0;
+ return 1;
+}
+
+static void post_watch(char c)
+{
+ static const char clean[] = " fail=0";
+ if (c != '\n') {
+ if (post_len < sizeof post_line) post_line[post_len++] = c;
+ return;
+ }
+ if (text_at(post_line, post_len, 0, "PARITY:V4_POST ")) {
+ post_seen = 1;
+ post_clean = post_len >= sizeof clean - 1 && text_at(post_line, post_len, post_len - (unsigned)(sizeof clean - 1), clean);
+ }
+ post_len = 0;
+}
+
static void tail_put(const v4_boot *b, tail *t, int show, char c)
{
unsigned i;
@@ -130,7 +172,10 @@ static int run_to_prompt(const v4_boot *b, int show)
for (;;) {
(void)v4_exec_step_word(n, b->es, b->h);
if (n->console_len) {
- for (i = 0; i < n->console_len; i++) tail_put(b, &t, show, (char)n->console[i]);
+ for (i = 0; i < n->console_len; i++) {
+ post_watch((char)n->console[i]);
+ tail_put(b, &t, show, (char)n->console[i]);
+ }
n->console_len = 0;
}
if (n->stopped) { say(b, "\nV4: the node stopped on a fault\n"); return 0; }
@@ -233,6 +278,7 @@ int v4_boot_run(const v4_boot *b, unsigned char *disk, unsigned blocks)
{
unsigned i;
+ post_len = 0; post_seen = 0; post_clean = 0;
if (!v4_image_boot(b->n, b->es, b->h, b->im, disk, blocks)) {
say(b, "V4: the nucleus image is not for this build of the engine\nPARITY:FAIL\nPOST: FAILED\n");
return 0;
@@ -247,7 +293,18 @@ int v4_boot_run(const v4_boot *b, unsigned char *disk, unsigned blocks)
for (i = 0; i < sizeof boot_capsules / sizeof boot_capsules[0]; i++)
if (!load_capsule(b, boot_capsules[i])) { say(b, "PARITY:FAIL\nPOST: FAILED\n"); return 0; }
+#if V4_POST_AT_BOOT
+ if (!post_seen || !post_clean) {
+ say(b, post_seen ? "V4: POST reported failures\n" : "V4: POST did not report\n");
+ say(b, "PARITY:FAIL\nPOST: FAILED\n");
+ return 0;
+ }
+#endif
+#if V4_POST_AT_BOOT
+ say(b, "PARITY:OK\nPOST: PASSED\nok> ");
+#else
say(b, "PARITY:OK\nok> ");
+#endif
return 1;
}
diff --git a/v4/tools/mkpost.py b/v4/tools/mkpost.py
new file mode 100755
index 00000000..578ede60
--- /dev/null
+++ b/v4/tools/mkpost.py
@@ -0,0 +1,455 @@
+#!/usr/bin/env python3
+"""mkpost.py -- write capsules/v4/post79.4th from v3's POST cases.
+
+ v4/tools/mkpost.py [--v3 PATH] [--report FILE]
+
+A development tool, run when the cases change; its output is committed and
+reviewed like any source. docs/v4.0.0/NUCLEUS.md section 6.
+
+What it does:
+
+ 1. Reads v3's case tables, v3/src/test_runner/modules/*.c, in the order
+ v3's own POST runs them. A case is a word, a name, a line of FORTH and
+ whether an error is expected.
+ 2. Keeps the cases for words of the FORTH-79 Required Word Set.
+ 3. Runs every kept case, in order, in one session of the hosted v3 binary,
+ and records what v3 did: an error or not, the data stack, and what was
+ printed. v3 is the reference.
+ 4. Writes the harness and one case after another as a .4th capsule:
+
+ T{ DUP.basic name the case, start clean
+ T| 5 DUP . . a line of the case, its output captured
+ -> 5 5 }T 0 0 T= v3's stack; v3's output: length, checksum
+
+ or, for a case v3 ended with an error, ->ERR in place of the last
+ line.
+
+A case is left out, and listed in the report, when: its word reads the
+keyboard; it forgets a word of the system or damages it on purpose; v3 could
+not finish it in one
+session; or one of its lines cannot be cut to fit a 64-character block
+line.
+"""
+import argparse
+import os
+import re
+import subprocess
+import sys
+
+ROOT = os.path.abspath(os.path.join(os.path.dirname(__file__), "..", ".."))
+MODULE_DIR = os.path.join(ROOT, "v3", "src", "test_runner", "modules")
+OUTPUT = os.path.join(ROOT, "capsules", "v4", "post79.4th")
+FIRST_BLOCK = 7000
+LINE_MAX = 64
+
+# v3's POST order (v3/src/test_runner/test_runner.c, test_modules[]), the
+# modules that test FORTH-79 words.
+MODULES = [
+ "stack_words_test.c", "return_stack_words_test.c", "memory_words_test.c",
+ "arithmetic_words_test.c", "logical_words_test.c",
+ "mixed_arithmetic_words_test.c", "double_words_test.c",
+ "format_words_test.c", "string_words_test.c", "io_words_test.c",
+ "block_words_test.c", "dictionary_words_test.c",
+ "dictionary_manipulation_words_test.c", "vocabulary_words_test.c",
+ "system_words_test.c", "defining_words_tests.c", "control_words_test.c",
+]
+
+# The FORTH-79 Standard's Required Word Set, by the standard's own groups.
+# Written from the standard's word list; check it against the document
+# before relying on it for a claim of compliance.
+REQUIRED = """
+DUP DROP SWAP OVER ROT PICK ROLL ?DUP DEPTH >R R> R@
+< = > 0< 0= 0> D< U< NOT
++ - * / MOD /MOD */ */MOD 1+ 1- 2+ 2- MAX MIN ABS NEGATE D+ DNEGATE
+U* U/MOD AND OR XOR
+@ ! C@ C! ? +! MOVE CMOVE FILL
+DO LOOP +LOOP I J LEAVE IF ELSE THEN BEGIN UNTIL WHILE REPEAT EXIT EXECUTE
+CR EMIT SPACE SPACES TYPE COUNT -TRAILING KEY EXPECT QUERY WORD
+BASE DECIMAL . U. CONVERT <# # #S HOLD SIGN #>
+LIST LOAD SCR BLOCK UPDATE BUFFER SAVE-BUFFERS EMPTY-BUFFERS
+: ; VARIABLE CONSTANT VOCABULARY CREATE DOES>
+CONTEXT CURRENT FORTH DEFINITIONS ' FIND FORGET
+, ALLOT ." IMMEDIATE LITERAL STATE [ ] COMPILE [COMPILE]
+( >IN ABORT QUIT HERE PAD BLK 79-STANDARD
+""".split()
+
+# Words whose cases wait for the keyboard, which a boot cannot type at.
+KEYBOARD = {"KEY", "EXPECT", "QUERY"}
+
+# ---- the harness: blocks FIRST_BLOCK up, FORTH-79 and the two nucleus hooks ----
+HARNESS = r"""
+( post79.4th -- POST for the FORTH-79 Required Word Set on v4. )
+( Generated by v4/tools/mkpost.py from v3's POST cases: do not )
+( edit. docs/v4.0.0/NUCLEUS.md section 6. )
+VARIABLE T# VARIABLE TPASS VARIABLE TFAIL VARIABLE TOPEN
+VARIABLE TBAD VARIABLE TWANT VARIABLE TLEN VARIABLE TSUM
+VARIABLE TDEP VARIABLE TBASE
+CREATE TBUF 64 ALLOT CREATE TSTK 16 ALLOT CREATE TNAME 8 ALLOT
+0 T# ! 0 TPASS ! 0 TFAIL ! 0 TOPEN ! 10 TBASE !
+: TB ( -- baddr ) TBUF 4 * ;
+: TN ( -- baddr ) TNAME 4 * ;
+( T-EMIT is given every character a case prints: the first 255 )
+( are kept, all are counted and summed. )
+: T-EMIT ( c -- )
+ DUP TSUM @ 31 * + 16777215 AND TSUM !
+ TLEN @ 255 < IF TB TLEN @ + C! ELSE DROP THEN 1 TLEN +! ;
+=====
+: T-CLEAR ( i*x -- ) BEGIN DEPTH WHILE DROP REPEAT ;
+: T. ( n -- ) 0 <# #S #> TYPE ;
+( what a failing case printed, and the stack it left )
+: T-SHOW ( -- )
+ ." out<" TB TLEN @ 255 MIN TYPE ." > stack<"
+ TDEP @ BEGIN DUP WHILE 1- DUP TSTK + @ . REPEAT DROP ." >" ;
+( the verdict on the case that is open, if one is )
+: T-CLOSE ( -- )
+ TOPEN @ IF
+ (CATCH) @ -1 = TWANT @ = 0= IF 1 TBAD ! THEN
+ TBAD @ IF 1 TFAIL +!
+ ." POST FAIL: " TN COUNT TYPE T-SHOW CR
+ ELSE 1 TPASS +! THEN
+ 0 TOPEN ! 0 (CATCH) ! TBASE @ BASE !
+ THEN ;
+=====
+( T{ name begin a case: clean stack, errors caught )
+: T{ ( i*x -- ) T-CLOSE T-CLEAR
+ BL WORD COUNT 31 MIN DUP TN C! TN 1+ SWAP CMOVE
+ 1 T# +! 1 TOPEN ! 0 TBAD ! 0 TWANT ! 0 TLEN ! 0 TSUM !
+ 0 TDEP ! 1 (CATCH) ! ;
+( T| ... a line of the case, what it prints captured )
+: T| ' T-EMIT (EMIT-HOOK) ! ; IMMEDIATE
+: T-END ( -- ) 0 (EMIT-HOOK) ! BASE @ TBASE ! DECIMAL ;
+( -> ... the case is over: set its stack aside, top first )
+: -> ( i*x -- ) T-END 0
+ BEGIN DEPTH 1 > WHILE
+ DUP 16 < IF SWAP OVER TSTK + ! ELSE SWAP DROP 1 TBAD ! THEN
+ 1+ REPEAT
+ 16 MIN TDEP ! ;
+( ->ERR the case is over, and must have ended in an error )
+: ->ERR ( i*x -- ) T-END -1 TWANT ! T-CLEAR ;
+=====
+( ... }T the stack the case must have left, in order )
+: }T ( i*x -- )
+ DEPTH TDEP @ = 0= IF 1 TBAD ! T-CLEAR EXIT THEN
+ 0 BEGIN DEPTH 1 > WHILE
+ SWAP OVER TSTK + @ = 0= IF 1 TBAD ! THEN 1+ REPEAT DROP ;
+( len sum T= what the case must have printed )
+: T= ( len sum -- ) TSUM @ = 0= IF 1 TBAD ! THEN
+ TLEN @ = 0= IF 1 TBAD ! THEN ;
+( the tally; a failure is an error, which ends the boot )
+: T-REPORT ( -- ) T-CLOSE 0 (CATCH) ! DECIMAL
+ ." PARITY:V4_POST tests=" T# @ T. ." pass=" TPASS @ T.
+ ." fail=" TFAIL @ T. CR
+ TFAIL @ IF -1 NODE-ERROR ! THEN ;
+"""
+
+
+# ---- reading v3's case tables ----------------------------------------------
+
+TOKEN = re.compile(r'''
+ \s+ | /\*.*?\*/ | //[^\n]* |
+ (?P"(?:\\.|[^"\\])*") |
+ (?P[{}(),;=\[\]&*]) |
+ (?P[A-Za-z0-9_.+\-]+)
+''', re.S | re.X)
+
+ESCAPES = {"n": "\n", "t": "\t", "\\": "\\", '"': '"', "r": "\r", "0": "\0"}
+
+
+def unescape(lit):
+ out, i, body = [], 0, lit[1:-1]
+ while i < len(body):
+ if body[i] == "\\" and i + 1 < len(body):
+ out.append(ESCAPES.get(body[i + 1], body[i + 1]))
+ i += 2
+ else:
+ out.append(body[i])
+ i += 1
+ return "".join(out)
+
+
+def tokens(text):
+ pos, out = 0, []
+ while pos < len(text):
+ m = TOKEN.match(text, pos)
+ if not m:
+ pos += 1
+ continue
+ pos = m.end()
+ if m.group("str"):
+ value = unescape(m.group("str"))
+ if out and out[-1][0] == "str": # adjacent literals join
+ out[-1] = ("str", out[-1][1] + value)
+ else:
+ out.append(("str", value))
+ elif m.group("punct"):
+ out.append(("punct", m.group("punct")))
+ elif m.group("word"):
+ out.append(("word", m.group("word")))
+ return out
+
+
+def parse_braces(toks, i):
+ """toks[i] is '{'; returns (nested list, index after the matching '}')."""
+ items = []
+ i += 1
+ while toks[i] != ("punct", "}"):
+ if toks[i] == ("punct", "{"):
+ sub, i = parse_braces(toks, i)
+ items.append(sub)
+ elif toks[i] == ("punct", ","):
+ i += 1
+ else:
+ items.append(toks[i][1] if toks[i][0] != "str" else ("s", toks[i][1]))
+ i += 1
+ return items, i + 1
+
+
+def read_module(path):
+ """Yields (word, case name, input, should_error) for every implemented case."""
+ toks = tokens(open(path, encoding="utf-8", errors="replace").read())
+ for i, t in enumerate(toks):
+ if t != ("word", "WordTestSuite"):
+ continue
+ j = i
+ while j < len(toks) and toks[j] != ("punct", "=") and toks[j] != ("punct", ";") and toks[j] != ("punct", "("):
+ j += 1
+ if j >= len(toks) or toks[j] != ("punct", "="):
+ continue
+ suites, _ = parse_braces(toks, j + 1)
+ for suite in suites:
+ if not isinstance(suite, list) or not suite or not isinstance(suite[0], tuple):
+ continue
+ word = suite[0][1]
+ for case in suite[1]:
+ if not isinstance(case, list) or len(case) < 6 or not isinstance(case[0], tuple):
+ continue
+ name, text = case[0][1], case[1][1]
+ should_error, implemented = case[4] != "0", case[5] != "0"
+ if implemented:
+ yield word, name, text, should_error
+
+
+# ---- cutting a case's line to block lines ------------------------------------
+
+STRING_OPENERS = {'."', 'S"', 'ABORT"', '.('}
+
+
+def atoms(text):
+ """The line as pieces that must each stay on one line: a word, or a word
+ that takes text together with its text. None if the line has a new-line
+ inside such a text."""
+ out, i, n = [], 0, len(text)
+ while i < n:
+ if text[i].isspace():
+ i += 1
+ continue
+ j = i
+ while j < n and not text[j].isspace():
+ j += 1
+ word = text[i:j]
+ upper = word.upper()
+ if upper in STRING_OPENERS or upper == "(":
+ close = ")" if upper in ("(", ".(") else '"'
+ k = text.find(close, j + 1 if j < n else j)
+ if k < 0:
+ k = n - 1
+ piece = text[i:k + 1]
+ if "\n" in piece:
+ return None
+ out.append(piece)
+ i = k + 1
+ elif word == "\\":
+ break # the rest of the line is a comment
+ else:
+ out.append(word)
+ i = j
+ return out
+
+
+def pack(prefix, pieces, width=LINE_MAX):
+ """Pieces into lines no longer than `width`, each begun with `prefix`
+ (which may be empty). None if a piece cannot fit on a line."""
+ head = [prefix] if prefix else []
+ lines, current = [], []
+ for piece in pieces:
+ if len(" ".join(head + [piece])) > width:
+ return None
+ if current and len(" ".join(head + current + [piece])) > width:
+ lines.append(current)
+ current = []
+ current.append(piece)
+ if current:
+ lines.append(current)
+ return [" ".join(head + line) for line in lines]
+
+
+# A store to the search order, which v3's C test runner survives and a
+# running FORTH system does not.
+DAMAGES = re.compile(r"\b(CONTEXT|CURRENT)\s+!")
+
+
+def forgets_system_word(text):
+ """True if the line FORGETs a word it did not itself define. In a plain
+ v3 session that takes the rest of the system with it, and v4 refuses."""
+ words = text.split()
+ for i, word in enumerate(words[:-1]):
+ if word.upper() == "FORGET":
+ target = words[i + 1]
+ made = any(words[k] == target and k > 0 and words[k - 1].upper() in
+ (":", "CREATE", "VARIABLE", "CONSTANT", "VOCABULARY") for k in range(i))
+ if not made:
+ return True
+ return False
+
+
+# ---- what v3 does --------------------------------------------------------------
+
+ANSI = re.compile(r"\x1b\[[0-9;]*m")
+
+
+def run_v3(v3, cases):
+ """Runs the cases in one session. Returns a list, one entry per case:
+ None if v3 did not get through it, else (error, stack, output)."""
+ script = [": T| ; IMMEDIATE", ": TCLR BEGIN DEPTH WHILE DROP REPEAT ;"]
+ for n, case in enumerate(cases):
+ script.append('TCLR ." [[B%d]]"' % n)
+ script.extend(case["lines"])
+ script.append('." [[E%d]]" BASE @ DECIMAL .S BASE ! ." [[S%d]]"' % (n, n))
+ script.append("BYE")
+ done = subprocess.run([v3, "--log-none"], input="\n".join(script) + "\n", capture_output=True,
+ text=True, errors="replace", timeout=600)
+ text = ANSI.sub("", done.stdout)
+ results = []
+ for n, case in enumerate(cases):
+ begin, mid, end = "[[B%d]] ok\nok> " % n, "ok> [[E%d]]" % n, "[[S%d]]" % n
+ b = text.find(begin)
+ e = text.find(mid, b) if b >= 0 else -1
+ s = text.find(end, e) if e >= 0 else -1
+ if b < 0 or e < 0 or s < 0:
+ results.append(None)
+ continue
+ body = text[b + len(begin):e]
+ # one "ok> " and one " ok" or " ERROR" for every line of the case
+ chunks = body.split("ok> ")
+ output, error, ok = "", False, True
+ for chunk in chunks:
+ if chunk.endswith(" ERROR\n"):
+ output += chunk[:-len(" ERROR\n")]
+ error = True
+ elif chunk.endswith(" ok\n"):
+ output += chunk[:-len(" ok\n")]
+ else:
+ ok = False
+ m = re.match(r"<(\d+)>((?: -?\d+)*) \n", text[e + len(mid):s])
+ if not ok or not m:
+ results.append(None)
+ continue
+ stack = [int(v) for v in m.group(2).split()]
+ results.append((error, stack[:-1], output)) # the last value is BASE
+ return results
+
+
+def checksum(output):
+ total = 0
+ for ch in output.encode("latin-1", errors="replace"):
+ total = (total * 31 + ch) & 0xFFFFFF
+ return total
+
+
+# ---- writing the capsule -------------------------------------------------------
+
+def main():
+ ap = argparse.ArgumentParser()
+ ap.add_argument("--v3", default=os.path.join(ROOT, "lfs", "amd64", "starforth"))
+ ap.add_argument("--report", default=None)
+ args = ap.parse_args()
+
+ required, left_out, cases, seen = set(REQUIRED), [], [], {}
+ for module in MODULES:
+ for word, name, text, should_error in read_module(os.path.join(MODULE_DIR, module)):
+ if word not in required:
+ continue
+ label = ("%s.%s" % (word, name))[:31]
+ seen[label] = seen.get(label, 0) + 1
+ if seen[label] > 1:
+ label = (label[:28] + "~%d" % seen[label])[:31]
+ if word in KEYBOARD:
+ left_out.append((label, "reads the keyboard"))
+ continue
+ if forgets_system_word(text):
+ left_out.append((label, "forgets a word of the system"))
+ continue
+ if DAMAGES.search(text.upper()):
+ left_out.append((label, "damages the system on purpose"))
+ continue
+ pieces = atoms(text)
+ lines = pack("T|", pieces) if pieces is not None else None
+ if not lines:
+ left_out.append((label, "a line cannot be cut to fit a block line"))
+ continue
+ cases.append({"label": label, "word": word, "text": text, "lines": lines, "should_error": should_error})
+
+ # v3 is run until every case left is one it gets through
+ while True:
+ results = run_v3(args.v3, cases)
+ bad = [i for i, r in enumerate(results) if r is None]
+ if not bad:
+ break
+ first = bad[0]
+ left_out.append((cases[first]["label"], "v3 did not get through it in one session"))
+ del cases[first]
+
+ blocks, current = [], []
+
+ def flush():
+ if current:
+ blocks.append(list(current))
+ del current[:]
+
+ for part in HARNESS.strip("\n").split("=====\n"):
+ current.extend(part.strip("\n").split("\n"))
+ flush()
+
+ disagreements = []
+ for case, (error, stack, output) in zip(cases, results):
+ if error != case["should_error"]:
+ disagreements.append((case["label"], "v3's table says %s, v3 %s"
+ % ("error" if case["should_error"] else "no error",
+ "raised one" if error else "raised none")))
+ lines = ["T{ " + case["label"]] + case["lines"]
+ if error:
+ lines.append("->ERR")
+ else:
+ tail = ["->"] + [str(v) for v in stack] + ["}T", str(len(output)), str(checksum(output)), "T="]
+ lines.extend(pack("", tail))
+ if len(current) + len(lines) > 16:
+ flush()
+ current.extend(lines)
+ flush()
+ blocks.append(["T-REPORT", "FORGET T# DECIMAL"])
+
+ with open(OUTPUT, "w", encoding="ascii") as out:
+ for k, block in enumerate(blocks):
+ assert len(block) <= 16, block
+ out.write("Block %d\n" % (FIRST_BLOCK + k))
+ for line in block:
+ assert len(line) <= LINE_MAX, line
+ out.write(line + "\n")
+
+ tested = sorted({c["word"] for c in cases})
+ untested = [w for w in REQUIRED if w not in set(tested)]
+ report = ["POST cases: %d, in %d blocks (%d to %d)" % (len(cases), len(blocks), FIRST_BLOCK, FIRST_BLOCK + len(blocks) - 1),
+ "Required words with at least one case: %d of %d" % (len(tested), len(REQUIRED)),
+ "Required words with no case: " + " ".join(untested), "",
+ "Left out (%d):" % len(left_out)]
+ report += [" %-32s %s" % item for item in left_out]
+ report += ["", "v3 did not do what its own table expects (%d):" % len(disagreements)]
+ report += [" %-32s %s" % item for item in disagreements]
+ text = "\n".join(report) + "\n"
+ if args.report:
+ open(args.report, "w").write(text)
+ sys.stdout.write(text)
+
+
+if __name__ == "__main__":
+ main()