From 5d6043e37e2fe35f4a77a8c3157f340540eee45d Mon Sep 17 00:00:00 2001 From: rajames Date: Mon, 5 Oct 2026 16:04:48 -0400 Subject: [PATCH] feat(v4.0.0): POST for FORTH-79, from v3's cases; not passing yet capsules/v4/post79.4th: 537 of v3's POST cases for the FORTH-79 Required Word Set, each carrying what the hosted v3 binary did with the same line (error or not, the stack, the length and checksum of what it printed). Written by v4/tools/mkpost.py. The harness is FORTH-79 plus the two nucleus hooks. docs/v4.0.0/NUCLEUS.md section 6. - NODE-ERROR has a FORTH name: how a definition in FORTH raises an error - the boot passes POST only on seeing its tally line with fail=0 - POST is not in the boot yet (V4_POST_AT_BOOT=0); make -C v4 post runs it Result: tests=537 pass=439 fail=98. The 98 are not yet sorted into v4 defects and differences needing a ruling; v4/README.md has a first reading. Verified: make -C v4 test passes; hosted-check passes on three ISAs; clean qemu with STARFORTH_V4=1 on amd64, aarch64 and riscv64 reaches ok> with the same hashes as hosted (logs/20261005-1601xx..1604xx). Nothing was typed at a bare-metal prompt. Co-Authored-By: Claude Opus 5.5 --- capsules/BLOCK_MAP.md | 69 +- capsules/v4/post79.4th | 1787 +++++++++++++++++ .../amd64/qemu-amd64-20261005-160144.log | 108 + .../aarch64/qemu-aarch64-20261005-160234.log | 82 + .../riscv64/qemu-riscv64-20261005-160400.log | 152 ++ v4/Makefile | 14 + v4/README.md | 55 +- v4/capsule/quit.v4 | 5 + v4/include/v4/boot.h | 5 +- v4/system/boot.c | 61 +- v4/tools/mkpost.py | 455 +++++ 11 files changed, 2779 insertions(+), 14 deletions(-) create mode 100644 capsules/v4/post79.4th create mode 100644 logs/20261005-160144/amd64/qemu-amd64-20261005-160144.log create mode 100644 logs/20261005-160234/aarch64/qemu-aarch64-20261005-160234.log create mode 100644 logs/20261005-160400/riscv64/qemu-riscv64-20261005-160400.log create mode 100755 v4/tools/mkpost.py 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 @@ +[=3hBdsDxe: 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) +[=3hStarKernel 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) +[=3hBdsDxe: 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) +[=3hStarKernel 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 +[=3hRISC-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 +[=3hStarKernel 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()