diff --git a/capsules/BLOCK_MAP.md b/capsules/BLOCK_MAP.md index 530c8dd7..19344248 100644 --- a/capsules/BLOCK_MAP.md +++ b/capsules/BLOCK_MAP.md @@ -1,5 +1,5 @@ # Capsule Block Manifest — Auto-generated - + @@ -29,8 +29,8 @@ | `sdk.4th` | 5109, 5110, 5111, 5112, 5113, 5114, 5115 | `0x008fdbbb62c94a3a` | n/a | | `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 | +| `v4:forth79.4th` | 6000, 6001, 6002 | `0x4055641ee17d176b` | 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 | `0xb987dbb4388990bd` | 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,71 +368,73 @@ | 5113 | `sdk.4th` | `0x008fdbbb62c94a3a` | ok | | 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 | +| 6000 | `v4:forth79.4th` | `0x4055641ee17d176b` | ok | +| 6001 | `v4:forth79.4th` | `0x4055641ee17d176b` | ok | +| 6002 | `v4:forth79.4th` | `0x4055641ee17d176b` | ok | +| 7000 | `v4:post79.4th` | `0xb987dbb4388990bd` | ok | +| 7001 | `v4:post79.4th` | `0xb987dbb4388990bd` | ok | +| 7002 | `v4:post79.4th` | `0xb987dbb4388990bd` | ok | +| 7003 | `v4:post79.4th` | `0xb987dbb4388990bd` | ok | +| 7004 | `v4:post79.4th` | `0xb987dbb4388990bd` | ok | +| 7005 | `v4:post79.4th` | `0xb987dbb4388990bd` | ok | +| 7006 | `v4:post79.4th` | `0xb987dbb4388990bd` | ok | +| 7007 | `v4:post79.4th` | `0xb987dbb4388990bd` | ok | +| 7008 | `v4:post79.4th` | `0xb987dbb4388990bd` | ok | +| 7009 | `v4:post79.4th` | `0xb987dbb4388990bd` | ok | +| 7010 | `v4:post79.4th` | `0xb987dbb4388990bd` | ok | +| 7011 | `v4:post79.4th` | `0xb987dbb4388990bd` | ok | +| 7012 | `v4:post79.4th` | `0xb987dbb4388990bd` | ok | +| 7013 | `v4:post79.4th` | `0xb987dbb4388990bd` | ok | +| 7014 | `v4:post79.4th` | `0xb987dbb4388990bd` | ok | +| 7015 | `v4:post79.4th` | `0xb987dbb4388990bd` | ok | +| 7016 | `v4:post79.4th` | `0xb987dbb4388990bd` | ok | +| 7017 | `v4:post79.4th` | `0xb987dbb4388990bd` | ok | +| 7018 | `v4:post79.4th` | `0xb987dbb4388990bd` | ok | +| 7019 | `v4:post79.4th` | `0xb987dbb4388990bd` | ok | +| 7020 | `v4:post79.4th` | `0xb987dbb4388990bd` | ok | +| 7021 | `v4:post79.4th` | `0xb987dbb4388990bd` | ok | +| 7022 | `v4:post79.4th` | `0xb987dbb4388990bd` | ok | +| 7023 | `v4:post79.4th` | `0xb987dbb4388990bd` | ok | +| 7024 | `v4:post79.4th` | `0xb987dbb4388990bd` | ok | +| 7025 | `v4:post79.4th` | `0xb987dbb4388990bd` | ok | +| 7026 | `v4:post79.4th` | `0xb987dbb4388990bd` | ok | +| 7027 | `v4:post79.4th` | `0xb987dbb4388990bd` | ok | +| 7028 | `v4:post79.4th` | `0xb987dbb4388990bd` | ok | +| 7029 | `v4:post79.4th` | `0xb987dbb4388990bd` | ok | +| 7030 | `v4:post79.4th` | `0xb987dbb4388990bd` | ok | +| 7031 | `v4:post79.4th` | `0xb987dbb4388990bd` | ok | +| 7032 | `v4:post79.4th` | `0xb987dbb4388990bd` | ok | +| 7033 | `v4:post79.4th` | `0xb987dbb4388990bd` | ok | +| 7034 | `v4:post79.4th` | `0xb987dbb4388990bd` | ok | +| 7035 | `v4:post79.4th` | `0xb987dbb4388990bd` | ok | +| 7036 | `v4:post79.4th` | `0xb987dbb4388990bd` | ok | +| 7037 | `v4:post79.4th` | `0xb987dbb4388990bd` | ok | +| 7038 | `v4:post79.4th` | `0xb987dbb4388990bd` | ok | +| 7039 | `v4:post79.4th` | `0xb987dbb4388990bd` | ok | +| 7040 | `v4:post79.4th` | `0xb987dbb4388990bd` | ok | +| 7041 | `v4:post79.4th` | `0xb987dbb4388990bd` | ok | +| 7042 | `v4:post79.4th` | `0xb987dbb4388990bd` | ok | +| 7043 | `v4:post79.4th` | `0xb987dbb4388990bd` | ok | +| 7044 | `v4:post79.4th` | `0xb987dbb4388990bd` | ok | +| 7045 | `v4:post79.4th` | `0xb987dbb4388990bd` | ok | +| 7046 | `v4:post79.4th` | `0xb987dbb4388990bd` | ok | +| 7047 | `v4:post79.4th` | `0xb987dbb4388990bd` | ok | +| 7048 | `v4:post79.4th` | `0xb987dbb4388990bd` | ok | +| 7049 | `v4:post79.4th` | `0xb987dbb4388990bd` | ok | +| 7050 | `v4:post79.4th` | `0xb987dbb4388990bd` | ok | +| 7051 | `v4:post79.4th` | `0xb987dbb4388990bd` | ok | +| 7052 | `v4:post79.4th` | `0xb987dbb4388990bd` | ok | +| 7053 | `v4:post79.4th` | `0xb987dbb4388990bd` | ok | +| 7054 | `v4:post79.4th` | `0xb987dbb4388990bd` | ok | +| 7055 | `v4:post79.4th` | `0xb987dbb4388990bd` | ok | +| 7056 | `v4:post79.4th` | `0xb987dbb4388990bd` | ok | +| 7057 | `v4:post79.4th` | `0xb987dbb4388990bd` | ok | +| 7058 | `v4:post79.4th` | `0xb987dbb4388990bd` | ok | +| 7059 | `v4:post79.4th` | `0xb987dbb4388990bd` | ok | +| 7060 | `v4:post79.4th` | `0xb987dbb4388990bd` | ok | +| 7061 | `v4:post79.4th` | `0xb987dbb4388990bd` | ok | +| 7062 | `v4:post79.4th` | `0xb987dbb4388990bd` | ok | +| 7063 | `v4:post79.4th` | `0xb987dbb4388990bd` | ok | ## Conflicts diff --git a/capsules/v4/forth79.4th b/capsules/v4/forth79.4th index 47be6dff..105d58c9 100644 --- a/capsules/v4/forth79.4th +++ b/capsules/v4/forth79.4th @@ -3,4 +3,26 @@ Block 6000 ( as colon definitions, loaded when the system boots. ) ( docs/v4.0.0/NUCLEUS.md. Blocks 6000 up. ) ( A word moves here from the assembled nucleus, v4/capsule, ) -( once its colon definition passes POST. None has moved yet. ) +( once its colon definition passes POST. ) +Block 6001 +( U* U/MOD -- FORTH-79 unsigned multiply and divide. ) +( Neither v3 nor the v4 nucleus had them. ) +( The first two words count the bits in a cell. ) +: (BITS) ( -- n ) + 0 1 BEGIN DUP WHILE 2* SWAP 1+ SWAP REPEAT DROP ; +(BITS) CONSTANT (NB) +VARIABLE (UD) +( u1 u2 -- ud the unsigned double product ) +: U* UM* ; +Block 6002 +( ud u1 -- u2 u3 unsigned: u2 the remainder, u3 the quotient ) +( One bit a step: shift ud left, and take u1 from its high ) +( cell whenever it goes, counting that in the low cell. ) +( A zero divisor is error 11, Division by zero. ) +: U/MOD + DUP 0= IF DROP DROP DROP 11 NODE-ERROR ! THEN (UD) ! + (NB) 0 DO + DUP 0< >R 2* OVER 0< IF 1+ THEN SWAP 2* SWAP + R> IF (UD) @ - SWAP 1+ SWAP + ELSE DUP (UD) @ U< 0= IF (UD) @ - SWAP 1+ SWAP THEN THEN + LOOP SWAP ; diff --git a/capsules/v4/post79.4th b/capsules/v4/post79.4th index d8d01355..e9deb33c 100644 --- a/capsules/v4/post79.4th +++ b/capsules/v4/post79.4th @@ -4,15 +4,15 @@ Block 7000 ( 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 +VARIABLE TDEP CREATE TBUF 64 ALLOT CREATE TSTK 16 ALLOT CREATE TNAME 8 ALLOT -0 T# ! 0 TPASS ! 0 TFAIL ! 0 TOPEN ! 10 TBASE ! +0 T# ! 0 TPASS ! 0 TFAIL ! 0 TOPEN ! : 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 ! + 255 AND 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 ; @@ -28,40 +28,44 @@ Block 7001 TBAD @ IF 1 TFAIL +! ." POST FAIL: " TN COUNT TYPE T-SHOW CR ELSE 1 TPASS +! THEN - 0 TOPEN ! 0 (CATCH) ! TBASE @ BASE ! + 0 TOPEN ! 0 (CATCH) ! THEN ; Block 7002 -( T{ name begin a case: clean stack, errors caught ) +( T{ name begin a case: clean stack, decimal, FORTH ) : T{ ( i*x -- ) T-CLOSE T-CLEAR + DECIMAL [COMPILE] FORTH DEFINITIONS 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 ; +: T-END ( -- ) 0 (EMIT-HOOK) ! 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 ! ; +Block 7003 ( ->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 ; +( n }TD only how many values the case must have left ) +: }TD ( n -- ) TDEP @ = 0= IF 1 TBAD ! THEN ; ( len sum T= what the case must have printed ) : T= ( len sum -- ) TSUM @ = 0= IF 1 TBAD ! THEN TLEN @ = 0= IF 1 TBAD ! THEN ; +Block 7004 ( 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 +Block 7005 T{ DUP.basic T| 5 DUP . . CR -> }T 5 16397428 T= @@ -77,7 +81,7 @@ T| 2147483647 DUP . . CR T{ DUP.min_int T| -2147483648 DUP . . CR -> }T 25 386046 T= -Block 7005 +Block 7006 T{ DUP.empty_stack T| DUP ->ERR @@ -93,7 +97,7 @@ T| 10 -5 DROP . CR T{ DROP.double_drop T| 1 2 3 DROP DROP . CR -> }T 3 48091 T= -Block 7006 +Block 7007 T{ DROP.triple_drop T| 1 2 3 4 DROP DROP DROP . CR -> }T 3 48091 T= @@ -109,7 +113,7 @@ T| DEPTH 1 2 DROP DEPTH SWAP - . CR T{ DROP.preserve_depth T| DEPTH 5 6 DROP DROP DEPTH = . CR -> }T 3 47130 T= -Block 7007 +Block 7008 T{ DROP.max_int T| 2147483647 DROP DEPTH . CR -> }T 3 47130 T= @@ -125,7 +129,7 @@ T| 1 2 SWAP DROP . CR T{ DROP.complex T| 1 2 3 ROT DROP SWAP DROP . CR -> }T 3 50013 T= -Block 7008 +Block 7009 T{ DROP.empty_stack T| DROP ->ERR @@ -141,7 +145,7 @@ T| 0 99 SWAP . . CR T{ SWAP.negative T| -5 10 SWAP . . CR -> }T 7 12792257 T= -Block 7009 +Block 7010 T{ SWAP.one_item T| 42 SWAP ->ERR @@ -157,7 +161,7 @@ T| 0 0 OVER . . . CR T{ OVER.mixed T| -1 42 OVER . . . CR -> }T 10 1455732 T= -Block 7010 +Block 7011 T{ OVER.one_item T| 42 OVER ->ERR @@ -173,7 +177,7 @@ T| 0 0 0 ROT . . . CR T{ ROT.mixed T| -1 0 1 ROT . . . CR -> }T 8 201263 T= -Block 7011 +Block 7012 T{ ROT.two_items T| 1 2 ROT ->ERR @@ -189,23 +193,23 @@ T| DEPTH . CR T{ DEPTH.one_item T| 42 DEPTH . CR -> 42 }T 3 48091 T= -Block 7012 +Block 7013 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= +->ERR T{ PICK.pick_1 T| 1 2 3 1 PICK . CR --> 1 2 3 }T 3 49052 T= +-> 1 2 3 }T 3 50013 T= T{ PICK.pick_2 T| 1 2 3 2 PICK . CR --> 1 2 3 }T 3 48091 T= +-> 1 2 3 }T 3 49052 T= T{ ROLL.roll_1 T| 1 2 3 1 ROLL . . . CR --> }T 7 9069952 T= -Block 7013 +-> }T 7 4767936 T= +Block 7014 T{ ROLL.roll_2 T| 1 2 3 2 ROLL . . . CR -> }T 7 7380224 T= @@ -221,39 +225,39 @@ T| 0 ?DUP DEPTH . CR T{ ?DUP.empty_stack T| ?DUP ->ERR -Block 7014 +Block 7015 T{ >R.basic -T| 42 >R R@ . R> . CR +T| : RS1 42 >R R@ . R> . CR ; RS1 -> }T 7 15838026 T= T{ >R.zero -T| 0 >R R@ . R> . CR +T| : RS2 0 >R R@ . R> . CR ; RS2 -> }T 5 11775018 T= T{ >R.negative -T| -123 >R R@ . R> . CR +T| : RS3 -123 >R R@ . R> . CR ; RS3 -> }T 11 14101290 T= T{ >R.multiple -T| 1 2 >R >R R@ . R> . R@ . R> . CR +T| : RS4 1 2 >R >R R@ . R> . R@ . R> . CR ; RS4 -> }T 9 12265744 T= T{ >R.empty_stack T| >R ->ERR -Block 7015 +Block 7016 T{ R>.basic -T| 42 >R R> . CR +T| : RS5 42 >R R> . CR ; RS5 -> }T 4 1598184 T= T{ R>.lifo_order -T| 1 2 >R >R R> . R> . CR +T| : RS6 1 2 >R >R R> . R> . CR ; RS6 -> }T 5 12700461 T= T{ R>.empty_rstack T| R> ->ERR T{ R@.basic -T| 42 >R R@ . R> DROP CR +T| : RS7 42 >R R@ . R> DROP CR ; RS7 -> }T 4 1598184 T= T{ R@.non_destructive -T| 99 >R R@ R@ = . R> DROP CR +T| : RS8 99 >R R@ R@ = . R> DROP CR ; RS8 -> }T 4 1388686 T= -Block 7016 +Block 7017 T{ R@.empty_rstack T| R@ ->ERR @@ -269,7 +273,7 @@ T| -999 HERE ! HERE @ . CR T{ !.overwrite T| 111 HERE ! 222 HERE ! HERE @ . CR -> }T 5 14160220 T= -Block 7017 +Block 7018 T{ !.max_int T| 2147483647 HERE ! HERE @ . CR -> }T 12 4848918 T= @@ -285,7 +289,7 @@ T| 42 ! T{ @.after_store T| 123 HERE ! HERE @ . CR -> }T 5 13237660 T= -Block 7018 +Block 7019 T{ @.multiple_reads T| 456 HERE ! HERE @ HERE @ = . CR -> }T 4 1388686 T= @@ -301,7 +305,7 @@ T| 0 HERE C! HERE C@ . CR T{ C!.high_byte T| 255 HERE C! HERE C@ . CR -> }T 5 14252476 T= -Block 7019 +Block 7020 T{ C!.truncation T| 256 HERE C! HERE C@ . CR -> }T 3 47130 T= @@ -312,12 +316,12 @@ T{ C@.zero_byte T| 0 HERE C! HERE C@ . CR -> }T 3 47130 T= T{ ,.basic -T| 42 , HERE 8 - @ . CR +T| 42 , HERE 1 - @ . CR -> }T 4 1598184 T= T{ ,.negative -T| -999 , HERE 8 - @ . CR +T| -999 , HERE 1 - @ . CR -> }T 6 529078 T= -Block 7020 +Block 7021 T{ HERE.basic T| HERE HERE = . CR -> }T 4 1388686 T= @@ -333,7 +337,7 @@ T| HERE 0 ALLOT HERE SWAP - . CR T{ ALLOT.negative T| HERE -4 ALLOT HERE SWAP - . CR -> }T 4 1391569 T= -Block 7021 +Block 7022 T{ PAD.basic T| PAD PAD = . CR -> }T 4 1388686 T= @@ -342,17 +346,17 @@ T| PAD HERE = . CR -> }T 3 47130 T= T{ +!.basic T| 10 HERE ! 5 HERE +! HERE @ . CR -->ERR +-> }T 4 1511694 T= T{ +!.by_zero T| 42 HERE ! 0 HERE +! HERE @ . CR -->ERR +-> }T 4 1598184 T= T{ +!.negative T| 10 HERE ! -3 HERE +! HERE @ . CR -->ERR -Block 7022 +-> }T 3 53857 T= +Block 7023 T{ +!.accumulate T| 0 HERE ! 1 HERE +! 2 HERE +! 3 HERE +! HERE @ . CR -->ERR +-> }T 3 52896 T= T{ +!.empty_stack T| +! ->ERR @@ -365,14 +369,14 @@ T| HERE 0 88 FILL T{ FILL.zero_byte T| HERE 4 0 FILL HERE C@ . CR -> }T 3 47130 T= -Block 7023 +Block 7024 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| 65 HERE ! 66 HERE 1+ ! HERE HERE 16 + 2 MOVE HERE 16 + @ . +T| HERE 17 + @ . CR +-> }T 7 14525291 T= T{ MOVE.zero_n T| HERE HERE 8 + 0 MOVE -> }T 0 0 T= @@ -382,7 +386,7 @@ T| MOVE T{ +.basic T| 5 7 + . CR -> }T 4 1508811 T= -Block 7024 +Block 7025 T{ +.zero_add T| 42 0 + . CR -> }T 4 1598184 T= @@ -398,7 +402,7 @@ T| 2147483647 1 + . CR T{ +.underflow T| -2147483648 -1 + . CR -> }T 13 5384517 T= -Block 7025 +Block 7026 T{ +.empty_stack T| + ->ERR @@ -414,7 +418,7 @@ T| 42 0 - . CR T{ -.from_zero T| 0 5 - . CR -> }T 4 1392530 T= -Block 7026 +Block 7027 T{ -.negative T| 5 -3 - . CR -> }T 3 54818 T= @@ -430,7 +434,7 @@ T| 2147483647 -1 - . CR T{ -.empty_stack T| - ->ERR -Block 7027 +Block 7028 T{ -.one_item T| 42 - ->ERR @@ -446,7 +450,7 @@ T| 42 1 * . CR T{ *.by_negative T| 6 -7 * . CR -> }T 5 9602197 T= -Block 7028 +Block 7029 T{ *.negative_negative T| -6 -7 * . CR -> }T 4 1598184 T= @@ -462,7 +466,7 @@ T| * T{ *.one_item T| 42 * ->ERR -Block 7029 +Block 7030 T{ /.basic T| 15 3 / . CR -> }T 3 51935 T= @@ -478,7 +482,7 @@ T| 15 -3 / . CR T{ /.both_negative T| -15 -3 / . CR -> }T 3 51935 T= -Block 7030 +Block 7031 T{ /.truncation T| 7 3 / . CR -> }T 3 49052 T= @@ -494,7 +498,7 @@ T| 42 / T{ MOD.basic T| 17 5 MOD . CR -> }T 3 49052 T= -Block 7031 +Block 7032 T{ MOD.exact_division T| 15 3 MOD . CR -> }T 3 47130 T= @@ -510,7 +514,7 @@ T| 17 -5 MOD . CR T{ MOD.small_by_large T| 3 7 MOD . CR -> }T 3 50013 T= -Block 7032 +Block 7033 T{ MOD.by_zero T| 42 0 MOD ->ERR @@ -526,7 +530,7 @@ T| 17 5 /MOD . . CR T{ /MOD.exact T| 15 3 /MOD . . CR -> }T 5 16392623 T= -Block 7033 +Block 7034 T{ /MOD.negative T| -17 5 /MOD . . CR -> }T 7 5748361 T= @@ -542,7 +546,7 @@ T| 42 /MOD T{ ABS.positive T| 42 ABS . CR -> }T 4 1598184 T= -Block 7034 +Block 7035 T{ ABS.negative T| -42 ABS . CR -> }T 4 1598184 T= @@ -558,7 +562,7 @@ T| ABS T{ NEGATE.positive T| 42 NEGATE . CR -> }T 5 9602197 T= -Block 7035 +Block 7036 T{ NEGATE.negative T| -42 NEGATE . CR -> }T 4 1598184 T= @@ -574,7 +578,7 @@ T| NEGATE T{ MIN.basic T| 5 3 MIN . CR -> }T 3 50013 T= -Block 7036 +Block 7037 T{ MIN.equal T| 42 42 MIN . CR -> }T 4 1598184 T= @@ -590,7 +594,7 @@ T| 42 MIN T{ MIN.empty_stack T| MIN ->ERR -Block 7037 +Block 7038 T{ MAX.basic T| 5 3 MAX . CR -> }T 3 51935 T= @@ -606,7 +610,7 @@ T| -1 1 MAX . CR T{ MAX.one_item T| 42 MAX ->ERR -Block 7038 +Block 7039 T{ MAX.empty_stack T| MAX ->ERR @@ -622,7 +626,7 @@ T| -1 1+ . CR T{ 1+.chain T| 3 1+ 1+ 1+ . CR -> }T 3 52896 T= -Block 7039 +Block 7040 T{ 1+.overflow T| 2147483647 1+ . CR -> }T 12 4849879 T= @@ -638,7 +642,7 @@ T| 1 1- . CR T{ 1-.to_negative T| 0 1- . CR -> }T 4 1388686 T= -Block 7040 +Block 7041 T{ 1-.chain T| 6 1- 1- 1- . CR -> }T 3 50013 T= @@ -654,7 +658,7 @@ T| 5 2+ . CR T{ 2+.zero T| 0 2+ . CR -> }T 3 49052 T= -Block 7041 +Block 7042 T{ 2+.negative T| -3 2+ . CR -> }T 4 1388686 T= @@ -670,7 +674,7 @@ T| 2 2- . CR T{ 2-.negative T| 0 2- . CR -> }T 4 1389647 T= -Block 7042 +Block 7043 T{ 2-.empty_stack T| 2- ->ERR @@ -686,7 +690,7 @@ T| -1 0 AND . CR T{ AND.both_false T| 0 0 AND . CR -> }T 3 47130 T= -Block 7043 +Block 7044 T{ AND.bitwise T| 85 51 AND . CR -> }T 4 1513616 T= @@ -702,7 +706,7 @@ T| -1 -1 OR . CR T{ OR.first_false T| 0 -1 OR . CR -> }T 4 1388686 T= -Block 7044 +Block 7045 T{ OR.second_false T| -1 0 OR . CR -> }T 4 1388686 T= @@ -718,7 +722,7 @@ T| OR T{ OR.one_item T| 42 OR ->ERR -Block 7045 +Block 7046 T{ XOR.both_true T| -1 -1 XOR . CR -> }T 3 47130 T= @@ -734,7 +738,7 @@ T| 0 0 XOR . CR T{ XOR.bitwise T| 85 51 XOR . CR -> }T 5 13177117 T= -Block 7046 +Block 7047 T{ XOR.empty_stack T| XOR ->ERR @@ -750,7 +754,7 @@ T| 0 NOT . CR T{ NOT.positive T| 42 NOT . CR -> }T 3 47130 T= -Block 7047 +Block 7048 T{ NOT.negative T| -42 NOT . CR -> }T 3 47130 T= @@ -766,7 +770,7 @@ T| 42 43 = . CR T{ =.zero_equal T| 0 0 = . CR -> }T 4 1388686 T= -Block 7048 +Block 7049 T{ =.negative_equal T| -42 -42 = . CR -> }T 4 1388686 T= @@ -782,7 +786,7 @@ T| 42 = T{ <.less_than T| 5 7 < . CR -> }T 4 1388686 T= -Block 7049 +Block 7050 T{ <.greater_than T| 7 5 < . CR -> }T 3 47130 T= @@ -798,7 +802,7 @@ T| -7 -5 < . CR T{ <.empty_stack T| < ->ERR -Block 7050 +Block 7051 T{ <.one_item T| 42 < ->ERR @@ -814,7 +818,7 @@ T| 5 5 > . CR T{ >.positive_negative T| 5 -5 > . CR -> }T 4 1388686 T= -Block 7051 +Block 7052 T{ >.negative_negative T| -5 -7 > . CR -> }T 4 1388686 T= @@ -830,7 +834,7 @@ T| 0 0= . CR T{ 0=.positive T| 42 0= . CR -> }T 3 47130 T= -Block 7052 +Block 7053 T{ 0=.negative T| -42 0= . CR -> }T 3 47130 T= @@ -846,7 +850,7 @@ T| 0 0< . CR T{ 0<.positive T| 42 0< . CR -> }T 3 47130 T= -Block 7053 +Block 7054 T{ 0<.empty_stack T| 0< ->ERR @@ -862,7 +866,7 @@ T| -42 0> . CR T{ 0>.empty_stack T| 0> ->ERR -Block 7054 +Block 7055 T{ U<.less T| 3 5 U< . CR -> }T 4 1388686 T= @@ -878,7 +882,7 @@ T| 0 1 U< . CR T{ U<.empty_stack T| U< ->ERR -Block 7055 +Block 7056 T{ */.basic T| 6 7 4 */ . CR -> }T 4 1506889 T= @@ -894,7 +898,7 @@ T| 42 5 1 */ . CR T{ */.truncation T| 7 3 2 */ . CR -> }T 4 1506889 T= -Block 7056 +Block 7057 T{ */.negative_multiply T| -6 7 4 */ . CR -> }T 5 9510902 T= @@ -910,7 +914,7 @@ T| */ T{ */.two_items T| 1 2 */ ->ERR -Block 7057 +Block 7058 T{ */MOD.basic T| 17 3 5 */MOD . . CR -> }T 6 5318234 T= @@ -926,7 +930,7 @@ T| 42 5 1 */MOD . . CR T{ */MOD.remainder T| 7 8 5 */MOD . . CR -> }T 6 6241755 T= -Block 7058 +Block 7059 T{ */MOD.negative T| -7 3 4 */MOD . . CR -> }T 7 12674054 T= @@ -942,7 +946,7 @@ T| 100 200 300 400 D+ . . CR T{ D+.zero_add T| 42 99 0 0 D+ . . CR -> }T 7 6471656 T= -Block 7059 +Block 7060 T{ D+.negative T| -100 -200 50 75 D+ . . CR -> }T 10 13971193 T= @@ -958,7 +962,7 @@ T| 1 2 3 D+ T{ D+.empty_stack T| D+ ->ERR -Block 7060 +Block 7061 T{ DNEGATE.positive T| 100 200 DNEGATE . . CR -> }T 11 13922440 T= @@ -974,7 +978,7 @@ T| 2147483647 0 DNEGATE . . CR T{ DNEGATE.one_item T| 42 DNEGATE ->ERR -Block 7061 +Block 7062 T{ DNEGATE.empty_stack T| DNEGATE ->ERR @@ -990,7 +994,7 @@ T| 100 200 100 200 D< . CR T{ D<.negative_positive T| -100 -1 100 0 D< . CR -> }T 4 1388686 T= -Block 7062 +Block 7063 T{ D<.negative_negative T| -300 -1 -100 -1 D< . CR -> }T 4 1388686 T= @@ -1006,7 +1010,7 @@ T| D< T{ BASE.decimal T| DECIMAL 42 . CR -> }T 4 1598184 T= -Block 7063 +Block 7064 T{ BASE.hex T| HEX FF . CR -> }T 4 2153642 T= @@ -1015,14 +1019,14 @@ T| OCTAL 52 . CR -> }T 4 1627975 T= T{ BASE.base_store T| 16 BASE ! 255 . CR --> }T 5 16131231 T= +-> }T 5 14252476 T= T{ BASE.base_fetch T| BASE @ . CR --> }T 4 1510733 T= +-> }T 4 1506889 T= T{ DECIMAL.from_hex T| HEX FF DECIMAL . CR -> }T 5 14252476 T= -Block 7064 +Block 7065 T{ DECIMAL.from_octal T| OCTAL 52 DECIMAL . CR -> }T 4 1598184 T= @@ -1031,68 +1035,68 @@ 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{ <#.empty +T| 0 0 <# #> TYPE CR +-> }T 1 10 T= +T{ <#.negative +T| -42 DUP ABS 0 <# #S ROT SIGN #> TYPE CR +-> }T 4 1392127 T= +Block 7066 T{ #.single_digit -T| 15 <# # #> TYPE CR +T| 15 0 <# # #> TYPE CR -> }T 2 1653 T= T{ #.multiple -T| 15 <# # # #> TYPE CR +T| 15 0 <# # # #> TYPE CR -> }T 3 48742 T= T{ #.zero_pad -T| 5 <# # 0 # #> TYPE CR --> 0 }T 3 47781 T= +T| 5 0 <# # # #> TYPE CR +-> }T 3 47781 T= T{ #S.basic -T| 42 <# #S #> TYPE CR +T| 42 0 <# #S #> TYPE CR -> }T 3 51532 T= T{ #S.zero -T| 0 <# #S #> TYPE CR +T| 0 0 <# #S #> TYPE CR -> }T 2 1498 T= -Block 7066 +Block 7067 T{ #S.large -T| 1234567890 <# #S #> TYPE CR +T| 1234567890 0 <# #S #> TYPE CR -> }T 11 7265487 T= T{ SIGN.negative -T| -42 ABS <# #S SIGN #> TYPE CR --> 0 }T 3 51532 T= +T| -42 DUP ABS 0 <# #S ROT SIGN #> TYPE CR +-> }T 4 1392127 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| 42 DUP ABS 0 <# #S ROT SIGN #> TYPE CR -> }T 3 51532 T= -Block 7067 +T{ SIGN.zero +T| 0 DUP ABS 0 <# #S ROT SIGN #> TYPE CR +-> }T 2 1498 T= +T{ #>.normal +T| 42 0 <# #S #> TYPE CR +-> }T 3 51532 T= +Block 7068 T{ #>.empty -T| 0 <# #> TYPE CR --> 0 }T 1 10 T= +T| 0 0 <# #> TYPE CR +-> }T 1 10 T= T{ #>.stack_effect -T| 42 <# #S #> SWAP . . CR --> }T 6 4087998 T= +T| 42 0 <# #S #> SWAP DROP . CR +-> }T 3 49052 T= T{ HOLD.basic -T| 42 <# 46 HOLD #S #> TYPE CR +T| 42 0 <# 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| 4 PAD C! PAD COUNT . PAD - . CR +-> }T 5 15470063 T= +Block 7069 T{ COUNT.empty -T| HERE 0 OVER C! COUNT . . CR --> }T 7 11241141 T= +T| 0 PAD C! PAD COUNT . PAD - . CR +-> }T 5 11775979 T= T{ COUNT.max_length -T| HERE 255 OVER C! COUNT . . CR --> }T 9 2533207 T= +T| 255 PAD C! PAD COUNT . PAD - . CR +-> }T 7 6459661 T= T{ COUNT.string_bounds T| HERE COUNT SWAP 1- = . CR -> }T 3 47130 T= @@ -1101,43 +1105,41 @@ T| COUNT ->ERR T{ -TRAILING.basic T| HERE S" Test " -TRAILING TYPE CR --> 307 }T 6 6975864 T= -Block 7069 +-> 1 }TD 6 6975864 T= +Block 7070 T{ -TRAILING.all_spaces T| HERE S" " -TRAILING TYPE CR --> 315 }T 1 10 T= +-> 1 }TD 1 10 T= T{ -TRAILING.no_spaces T| HERE S" Test" -TRAILING TYPE CR --> 320 }T 5 13589912 T= +-> 1 }TD 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| 65 PAD C! 66 PAD 1+ C! PAD PAD 10 + 2 CMOVE PAD 10 + C@ . PAD +T| 11 + C@ . CR +-> }T 7 14525291 T= T{ CMOVE.empty T| HERE HERE 10 + 0 CMOVE -> }T 0 0 T= -Block 7070 +Block 7071 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 3 55779 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= +Block 7072 T{ ..zero T| 0 . CR -> }T 3 47130 T= @@ -1150,10 +1152,10 @@ T| -2147483648 . CR T{ ..multiple T| 1 2 3 . . . CR -> }T 7 4767936 T= -Block 7072 T{ ..empty_stack T| . ->ERR +Block 7073 T{ CR.basic T| 42 . CR 43 . CR -> }T 8 16061841 T= @@ -1166,10 +1168,10 @@ T| DEPTH CR DEPTH = . CR 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= +Block 7074 T{ SPACE.multiple T| SPACE SPACE SPACE -> }T 3 31776 T= @@ -1182,10 +1184,10 @@ T| 65 EMIT SPACE 66 EMIT CR T{ SPACES.zero T| 0 SPACES -> }T 0 0 T= -Block 7074 T{ SPACES.one T| 1 SPACES -> }T 1 32 T= +Block 7075 T{ SPACES.multiple T| 5 SPACES -> }T 5 13760544 T= @@ -1198,10 +1200,10 @@ T| -5 SPACES T{ SPACES.with_output T| 42 . 3 SPACES 43 . CR -> }T 10 11278119 T= -Block 7075 T{ SPACES.empty_stack T| SPACES ->ERR +Block 7076 T{ EMIT.letter_A T| 65 EMIT CR -> }T 2 2025 T= @@ -1214,10 +1216,10 @@ T| 48 EMIT CR T{ EMIT.space_char T| 32 EMIT CR -> }T 2 1002 T= -Block 7076 T{ EMIT.newline T| 10 EMIT -> }T 1 10 T= +Block 7077 T{ EMIT.high_ascii T| 127 EMIT CR -> }T 2 3947 T= @@ -1226,17 +1228,17 @@ T| 321 EMIT CR -> }T 2 2025 T= T{ EMIT.negative T| -1 EMIT CR --> }T 2 1963 T= +-> }T 2 7915 T= T{ EMIT.sequence T| 72 EMIT 73 EMIT 10 EMIT -> }T 3 71465 T= -Block 7077 T{ EMIT.empty_stack T| EMIT ->ERR +Block 7078 T{ TYPE.basic_string -T| HERE S" Hello" DUP >R HERE SWAP CMOVE HERE R> TYPE CR --> 400 }T 6 10415512 T= +T| 72 PAD C! 105 PAD 1+ C! PAD 2 TYPE CR +-> }T 3 72457 T= T{ TYPE.empty_string T| HERE 0 TYPE CR -> }T 1 10 T= @@ -1244,12 +1246,12 @@ 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| 49 PAD C! 50 PAD 1+ C! PAD 2 TYPE CR +-> }T 3 48649 T= T{ TYPE.zero_length T| PAD 0 TYPE -> }T 0 0 T= +Block 7079 T{ TYPE.one_item T| PAD TYPE ->ERR @@ -1257,76 +1259,34 @@ 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| 4 PAD C! PAD COUNT . PAD - . CR +-> }T 5 15470063 T= T{ COUNT.empty~2 -T| HERE 0 OVER C! COUNT . . CR --> }T 7 12194453 T= -Block 7079 +T| 0 PAD C! PAD COUNT . PAD - . CR +-> }T 5 11775979 T= T{ COUNT.max_length~2 -T| HERE 255 OVER C! COUNT . . CR --> }T 9 3486519 T= +T| 255 PAD C! PAD COUNT . PAD - . CR +-> }T 7 6459661 T= +Block 7080 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= +-> 1 }TD T{ BLOCK.zero_block T| 0 BLOCK ->ERR +Block 7081 T{ BLOCK.large_block T| 65536 BLOCK ->ERR -Block 7083 T{ BLOCK.negative T| -1 BLOCK ->ERR @@ -1335,33 +1295,33 @@ T| BLOCK ->ERR T{ BUFFER.basic T| 1 BUFFER DUP . CR --> 5238784 }T 9 11810843 T= +-> 1 }TD T{ BUFFER.zero_block T| 0 BUFFER ->ERR +Block 7082 T{ BUFFER.flush_dirty T| 2 BLOCK 1+ 2 BUFFER --> 5239809 5239808 }T 0 0 T= -Block 7084 +-> 2 }TD 0 0 T= T{ BUFFER.empty_stack T| BUFFER ->ERR T{ UPDATE.basic T| 1 BLOCK UPDATE --> 5238784 }T 0 0 T= +-> 1 }TD 0 0 T= T{ UPDATE.multiple T| 1 BLOCK UPDATE UPDATE --> 5238784 }T 0 0 T= +-> 1 }TD 0 0 T= T{ UPDATE.no_block T| 0 SCR ! UPDATE -->ERR +-> }T 0 0 T= +Block 7083 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= +-> 1 }TD 0 0 T= T{ SAVE-BUFFERS.no_dirty T| SAVE-BUFFERS -> }T 0 0 T= @@ -1370,11 +1330,11 @@ T| EMPTY-BUFFERS -> }T 0 0 T= T{ EMPTY-BUFFERS.after_use T| 1 BLOCK EMPTY-BUFFERS --> 5238784 }T 0 0 T= +-> 1 }TD 0 0 T= +Block 7084 T{ EMPTY-BUFFERS.dirty_blocks T| 1 BLOCK UPDATE EMPTY-BUFFERS --> 5238784 }T 0 0 T= -Block 7086 +-> 1 }TD 0 0 T= T{ LOAD.basic T| 1 LOAD -> }T 0 0 T= @@ -1387,10 +1347,10 @@ T| 9999 LOAD T{ LOAD.empty_stack T| LOAD ->ERR +Block 7085 T{ LIST.basic T| 1 LIST --> }T 1114 997788 T= -Block 7087 +-> 0 }TD T{ LIST.zero_block T| 0 LIST ->ERR @@ -1403,29 +1363,29 @@ T| LIST T{ SCR.basic T| SCR @ . CR -> }T 3 48091 T= +Block 7086 T{ SCR.after_list T| 1 LIST SCR @ . CR --> }T 1117 12700863 T= -Block 7088 +-> 0 }TD T{ SCR.after_load T| 1 LOAD SCR @ . CR --> }T 0 0 T= +-> }T 3 48091 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 +-> 0 }T 0 0 T= T{ HERE.after_c_comma T| HERE 65 C, HERE SWAP - . CR -> }T 3 48091 T= +Block 7087 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= +-> 1 }TD 4 1388686 T= T{ ALLOT.basic~2 T| HERE 10 ALLOT HERE SWAP - . CR -> }T 4 1506889 T= @@ -1435,10 +1395,10 @@ T| HERE 0 ALLOT HERE SWAP - . CR T{ ALLOT.negative~2 T| HERE -4 ALLOT HERE SWAP - . CR -> }T 4 1391569 T= +Block 7088 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= @@ -1451,10 +1411,10 @@ T| 42 , HERE 1 CELLS - @ . CR T{ ,.negative~2 T| -999 , HERE 1 CELLS - @ . CR -> }T 6 529078 T= +Block 7089 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= @@ -1467,26 +1427,23 @@ T| 10 , 20 , HERE 1 CELLS - @ . HERE 1 CELLS - @ . CR T{ ,.empty_stack T| , ->ERR +Block 7090 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= +-> 1 }TD 4 1388686 T= T{ CREATE.basic T| CREATE test1 42 , test1 @ . CR -> }T 4 1598184 T= T{ CREATE.empty_name T| CREATE ->ERR -Block 7093 +Block 7091 T{ CREATE.redefine_shadows T| CREATE T 1 , CREATE T 2 , T @ . CR -> }T 3 49052 T= @@ -1502,23 +1459,23 @@ T| CREATE temp1 FORGET temp1 T{ IMMEDIATE.basic T| : test3 42 ; IMMEDIATE test3 . CR -> }T 4 1598184 T= -Block 7094 +Block 7092 T{ IMMEDIATE.already_immediate T| : test4 43 ; IMMEDIATE IMMEDIATE -> }T 0 0 T= T{ FIND.existing T| FIND DUP . CR --> }T 11 15395591 T= +-> 0 }TD T{ FIND.user_word T| : test5 44 ; FIND test5 . CR --> }T 11 8385165 T= +-> 0 }TD T{ FIND.nonexistent T| FIND nonexistent . CR -> }T 3 47130 T= T{ FIND.empty T| FIND -->ERR -Block 7095 +-> 0 }T 0 0 T= +Block 7093 T{ DEFINITIONS.basic T| FORTH DEFINITIONS -> }T 0 0 T= @@ -1530,28 +1487,28 @@ 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= +-> 0 }TD T{ VOCABULARY.word_isolation T| VOCABULARY ISOLATED ISOLATED DEFINITIONS : ISOWORD 99 ; FORTH T| DEFINITIONS -> }T 0 0 T= -Block 7096 +Block 7094 T{ VOCABULARY.cross_vocab_access T| VOCABULARY V1 V1 DEFINITIONS : V1WORD 11 ; FORTH V1WORD . CR --> }T 4 1507850 T= +->ERR 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 0 0 T= T{ VOCABULARY.empty_name T| VOCABULARY ->ERR T{ FORTH.basic T| FORTH DEFINITIONS -> }T 0 0 T= -Block 7097 +Block 7095 T{ FORTH.persistence T| FORTH : TEST1 42 ; TEST1 . CR -> }T 4 1598184 T= @@ -1567,23 +1524,23 @@ T| VOCABULARY TEST-VOC6 TEST-VOC6 DEFINITIONS T{ DEFINITIONS.word_creation T| VOCABULARY TEST-VOC7 TEST-VOC7 DEFINITIONS : TEST2 43 ; -> }T 0 0 T= -Block 7098 +Block 7096 T{ CONTEXT.basic T| CONTEXT @ . CR --> }T 11 8729384 T= +-> 0 }TD T{ CONTEXT.initial T| FORTH CONTEXT @ . CR --> }T 11 2699444 T= +-> 0 }TD T{ CURRENT.basic T| CURRENT @ . CR --> }T 11 8729384 T= +-> 0 }TD T{ CURRENT.after_def T| VOCABULARY TEST-VOC8 TEST-VOC8 DEFINITIONS CURRENT @ . CR --> }T 11 14389674 T= +-> 0 }TD T{ ABORT.basic T| ABORT -> }T 0 0 T= -Block 7099 +Block 7097 T{ ABORT.with_data T| 1 2 3 ABORT DEPTH . CR -> }T 0 0 T= @@ -1599,7 +1556,7 @@ T| : T{ ;.alone T| ; ->ERR -Block 7100 +Block 7098 T{ ;.immediate T| : TEST4 42 ; IMMEDIATE TEST4 . CR -> }T 4 1598184 T= @@ -1615,7 +1572,7 @@ T| -1 CONSTANT MINUS MINUS . CR T{ CONSTANT.empty_stack T| CONSTANT ->ERR -Block 7101 +Block 7099 T{ VARIABLE.basic T| VARIABLE VAR1 42 VAR1 ! VAR1 @ . CR -> }T 4 1598184 T= @@ -1631,7 +1588,7 @@ T| CREATE OBJ1 T{ CREATE.with_data T| CREATE OBJ2 42 , OBJ2 @ . CR -> }T 4 1598184 T= -Block 7102 +Block 7100 T{ CREATE.empty_name~2 T| CREATE ->ERR @@ -1647,7 +1604,7 @@ T| DOES> T{ [.basic T| : TEST5 [ 42 ] LITERAL ; TEST5 . CR -> }T 4 1598184 T= -Block 7103 +Block 7101 T{ [.outside T| [ -> }T 0 0 T= @@ -1656,14 +1613,14 @@ 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 4 1598184 T= T{ IF.false T| : TEST2 IF 42 ELSE 24 THEN ; 0 TEST2 . CR --> 0 }T 4 1599145 T= +-> }T 4 1540524 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 +Block 7102 T{ IF.no_else T| : TEST4 IF 42 THEN ; -1 TEST4 . CR -> }T 4 1598184 T= @@ -1679,7 +1636,7 @@ T| THEN T{ BEGIN.until T| : TEST5 0 BEGIN 1+ DUP 5 = UNTIL ; TEST5 . CR -> }T 3 51935 T= -Block 7105 +Block 7103 T{ BEGIN.while T| : TEST6 0 BEGIN DUP 5 < WHILE 1+ REPEAT ; TEST6 . CR -> }T 3 51935 T= @@ -1695,7 +1652,7 @@ T| : TEST9 BEGIN 1 UNTIL ; IMMEDIATE T{ UNTIL.no_begin T| UNTIL ->ERR -Block 7106 +Block 7104 T{ WHILE.basic T| : TEST10 BEGIN DUP 5 < WHILE 1+ REPEAT ; 0 TEST10 . CR -> }T 3 51935 T= @@ -1711,7 +1668,7 @@ T| : TEST12 BEGIN DUP 5 < WHILE 1+ REPEAT ; 0 TEST12 . CR T{ REPEAT.no_while T| REPEAT ->ERR -Block 7107 +Block 7105 T{ DO.basic T| : TEST13 5 0 DO I . LOOP ; TEST13 CR -> }T 11 12528484 T= @@ -1727,7 +1684,7 @@ T| : TEST16 3 0 DO 3 0 DO J I + . LOOP LOOP ; TEST16 CR T{ LOOP.basic T| : TEST20 5 0 DO I . LOOP ; TEST20 CR -> }T 11 12528484 T= -Block 7108 +Block 7106 T{ LOOP.no_do T| LOOP ->ERR @@ -1743,7 +1700,7 @@ T| : TEST23 10 0 DO I . DUP +LOOP ; 3 TEST23 CR T{ I.basic T| : TI 4 0 DO I . LOOP CR ; TI -> }T 9 7781840 T= -Block 7109 +Block 7107 T{ I.single T| : TI1 1 0 DO I . LOOP CR ; TI1 -> }T 3 47130 T= @@ -1759,7 +1716,7 @@ T| : TJ 2 0 DO 3 0 DO J . LOOP LOOP CR ; TJ T{ J.paired T| : TJ2 2 0 DO 2 0 DO J I + . LOOP LOOP CR ; TJ2 -> }T 9 6857358 T= -Block 7110 +Block 7108 T{ EXIT.early_return T| : TEX 5 EXIT 99 ; TEX . CR -> }T 3 51935 T= @@ -1774,14 +1731,104 @@ 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 3 50974 T= +Block 7109 T{ LEAVE.at_start T| : TLV2 0 5 0 DO LEAVE 1+ LOOP ; TLV2 . CR --> }T 3 47130 T= +-> }T 3 48091 T= T{ LEAVE.qdloop T| : TLV3 0 5 0 ?DO I 2 = IF LEAVE THEN 1+ LOOP ; TLV3 . CR --> }T 3 49052 T= +-> }T 3 50013 T= +T{ U*.small +T| 3 4 U* . . CR +-> }T 6 12751803 T= +T{ U*.zero +T| 0 5 U* . . CR +-> }T 5 11775018 T= +T{ U*.full +T| -1 -1 U* 2+ . 1 = . CR +-> }T 6 12631678 T= +Block 7110 +T{ U/MOD.small +T| 7 0 2 U/MOD . . CR +-> }T 5 14546542 T= +T{ U/MOD.exact +T| 12 0 4 U/MOD . . CR +-> }T 5 14545581 T= +T{ U/MOD.double +T| 0 1 2 U/MOD 2* . . CR +-> }T 5 11775018 T= +T{ U/MOD.inverse +T| -1 -1 U* -1 U/MOD 1+ . . CR +-> }T 5 11775018 T= +T{ U/MOD.carry +T| -1 -2 -1 U/MOD 1+ . 2+ . CR +-> }T 5 11775018 T= +Block 7111 +T{ U/MOD.by_zero +T| 1 0 0 U/MOD +->ERR +T{ ?.basic +T| VARIABLE Q1 42 Q1 ! Q1 ? CR +-> }T 4 1598184 T= +T{ EXECUTE.found +T| : E1 7 ; FIND E1 EXECUTE . CR +-> }T 3 53857 T= +T{ U..small +T| 42 U. CR +-> }T 4 1598184 T= +T{ U..unsigned +T| -1 U. CR +-> }T 22 3892143 T= Block 7112 +T{ CONVERT.digits +T| : C1 0 0 BL WORD CONVERT DROP ; C1 123 . . CR +-> }T 7 9448876 T= +T{ '.found +T| ' DUP 0= . CR +-> }T 3 47130 T= +T{ .".in_definition +T| : Q3 ." hi there" ; Q3 CR +-> }T 9 13319717 T= +T{ LITERAL.basic +T| : Q4 [ 5 ] LITERAL ; Q4 . CR +-> }T 3 51935 T= +T{ STATE.interpreting +T| STATE @ . CR +-> }T 3 47130 T= +Block 7113 +T{ STATE.compiling +T| : Q5 STATE @ 0= . ; IMMEDIATE : Q6 Q5 ; CR +-> }T 3 47130 T= +T{ COMPILE.basic +T| : Q7 COMPILE DUP ; IMMEDIATE : Q8 Q7 ; 3 Q8 . . CR +-> }T 5 14548464 T= +T{ [COMPILE].basic +T| : Q9 [COMPILE] IF ; IMMEDIATE : Q10 Q9 1 ELSE 2 THEN ; 0 Q10 +T| . -1 Q10 . CR +-> }T 5 13623021 T= +T{ (.comment +T| 1 ( 2 ) 3 . . CR +-> }T 5 14546542 T= +T{ BLK.terminal +T| BLK @ . CR +-> }T 3 47130 T= +Block 7114 +T{ 79-STANDARD.present +T| 79-STANDARD +-> }T 0 0 T= +T{ WORD.next_word +T| : W1 BL WORD COUNT TYPE ; W1 HELLO +-> }T 5 1515698 T= +T{ WORD.delimiter +T| : W2 44 WORD COUNT TYPE ; W2 A B, +-> }T 3 63523 T= +T{ WORD.count +T| : W3 BL WORD C@ . ; W3 ABC +-> }T 2 1613 T= +T{ WORD.skips_leading +T| : W4 BL WORD COUNT TYPE ; W4 X +-> }T 1 88 T= +Block 7115 T-REPORT FORGET T# DECIMAL diff --git a/docs/v4.0.0/NUCLEUS.md b/docs/v4.0.0/NUCLEUS.md index 81f99846..848901b4 100644 --- a/docs/v4.0.0/NUCLEUS.md +++ b/docs/v4.0.0/NUCLEUS.md @@ -178,10 +178,32 @@ and names each failing case. ### 6.4 Generating the expected values -A script reads the v3 test modules, keeps the cases for Required Word Set -words, pipes each line through the hosted v3 binary, and writes the -`T{ ... }T` lines. It is a development tool, run when the cases change; its -output, `post79.4th`, is committed and reviewed like any source. +`v4/tools/mkpost.py` reads the v3 test modules, keeps the cases for +Required Word Set words, runs them in one session of the hosted v3 binary, +and writes `capsules/v4/post79.4th`. It is a development tool +(`make -C v4 post79`), run when the cases or the rules change; its output +is committed and reviewed like any source. Every case starts from the same +state on both machines: empty stack, `DECIMAL`, `FORTH DEFINITIONS`. + +### 6.5 Where POST does not take v3's word (ruled 2026-10-05) + +`v4/tools/post79_rules.py` holds the exceptions, each with its reason, and +`mkpost.py` writes them out as `POST79.md`, which lists every one. + +1. **Address-dependent cases.** A case that leaves or prints a memory + address is checked for the number of values it leaves, and for what it + prints unless an address is printed. The values are not compared. +2. **Where v3 departs from FORTH-79.** The expected result is the + standard's. Where v3's line is not valid FORTH-79 (`>R` at the prompt, a + single number given to `<#`), the line is rewritten so that it is. +3. **Cases written for v3's machine.** A v4 address unit is a cell (D-1); + cases that assume v3's byte addresses are rewritten in v4's terms. +4. **Words v3 has no case for** get cases written by hand, with the + standard's results. `U*` and `U/MOD`, which neither v3 nor the v4 + nucleus had, are colon definitions in `forth79.4th`. + +Not tested: `KEY`, `EXPECT` and `QUERY`, which wait for the keyboard, and +`QUIT`, which returns to the terminal without ` ok`. ## 7. Hashing, signing and parity diff --git a/docs/v4.0.0/POST79.md b/docs/v4.0.0/POST79.md new file mode 100644 index 00000000..e8bce0f4 --- /dev/null +++ b/docs/v4.0.0/POST79.md @@ -0,0 +1,193 @@ +# POST for the FORTH-79 Required Word Set: where it departs from v3 + +Written by `v4/tools/mkpost.py` from `v4/tools/post79_rules.py`; do not edit. +Design: `NUCLEUS.md` section 6. The capsule is `capsules/v4/post79.4th`. + +POST runs 550 cases. 443 are v3's, with what the hosted v3 binary did as the +expected result. This file lists every other case, and why. + +## 1. Rewritten for FORTH-79 (59) + +v3 departs from the standard, or the case is written for v3's machine. v4 +follows the standard (standing ruling), so the expected result is the +standard's and not v3's. + +| Case | v3's line | What v3 did | As POST runs it | Must do | Why | +|---|---|---|---|---|---| +| `PICK.pick_0` | `1 2 3 0 PICK . CR` | stack `1 2 3`, printed `3 \n` | unchanged | an error | FORTH-79: PICK and ROLL count from 1; v3 counts from 0; 0 PICK is an error | +| `PICK.pick_1` | `1 2 3 1 PICK . CR` | stack `1 2 3`, printed `2 \n` | unchanged | stack `1 2 3`, prints `3 \n` | FORTH-79: PICK and ROLL count from 1; v3 counts from 0 | +| `PICK.pick_2` | `1 2 3 2 PICK . CR` | stack `1 2 3`, printed `1 \n` | unchanged | stack `1 2 3`, prints `2 \n` | FORTH-79: PICK and ROLL count from 1; v3 counts from 0 | +| `ROLL.roll_1` | `1 2 3 1 ROLL . . . CR` | stack `empty`, printed `1 3 2 \n` | unchanged | stack `empty`, prints `3 2 1 \n` | FORTH-79: PICK and ROLL count from 1; v3 counts from 0 | +| `>R.basic` | `42 >R R@ . R> . CR` | stack `empty`, printed `42 42 \n` | `: RS1 42 >R R@ . R> . CR ; RS1` | stack `empty`, prints `42 42 \n` | FORTH-79: >R R> R@ are for use inside a definition; v4 refuses them at the prompt | +| `>R.zero` | `0 >R R@ . R> . CR` | stack `empty`, printed `0 0 \n` | `: RS2 0 >R R@ . R> . CR ; RS2` | stack `empty`, prints `0 0 \n` | FORTH-79: >R R> R@ are for use inside a definition; v4 refuses them at the prompt | +| `>R.negative` | `-123 >R R@ . R> . CR` | stack `empty`, printed `-123 -123 \n` | `: RS3 -123 >R R@ . R> . CR ; RS3` | stack `empty`, prints `-123 -123 \n` | FORTH-79: >R R> R@ are for use inside a definition; v4 refuses them at the prompt | +| `>R.multiple` | `1 2 >R >R R@ . R> . R@ . R> . CR` | stack `empty`, printed `1 1 2 2 \n` | `: RS4 1 2 >R >R R@ . R> . R@ . R> . CR ; RS4` | stack `empty`, prints `1 1 2 2 \n` | FORTH-79: >R R> R@ are for use inside a definition; v4 refuses them at the prompt | +| `R>.basic` | `42 >R R> . CR` | stack `empty`, printed `42 \n` | `: RS5 42 >R R> . CR ; RS5` | stack `empty`, prints `42 \n` | FORTH-79: >R R> R@ are for use inside a definition; v4 refuses them at the prompt | +| `R>.lifo_order` | `1 2 >R >R R> . R> . CR` | stack `empty`, printed `1 2 \n` | `: RS6 1 2 >R >R R> . R> . CR ; RS6` | stack `empty`, prints `1 2 \n` | FORTH-79: >R R> R@ are for use inside a definition; v4 refuses them at the prompt | +| `R@.basic` | `42 >R R@ . R> DROP CR` | stack `empty`, printed `42 \n` | `: RS7 42 >R R@ . R> DROP CR ; RS7` | stack `empty`, prints `42 \n` | FORTH-79: >R R> R@ are for use inside a definition; v4 refuses them at the prompt | +| `R@.non_destructive` | `99 >R R@ R@ = . R> DROP CR` | stack `empty`, printed `-1 \n` | `: RS8 99 >R R@ R@ = . R> DROP CR ; RS8` | stack `empty`, prints `-1 \n` | FORTH-79: >R R> R@ are for use inside a definition; v4 refuses them at the prompt | +| `,.basic` | `42 , HERE 8 - @ . CR` | stack `empty`, printed `42 \n` | `42 , HERE 1 - @ . CR` | stack `empty`, prints `42 \n` | v3's address unit is a byte; a v4 address unit is a cell (D-1) | +| `,.negative` | `-999 , HERE 8 - @ . CR` | stack `empty`, printed `-999 \n` | `-999 , HERE 1 - @ . CR` | stack `empty`, prints `-999 \n` | v3's address unit is a byte; a v4 address unit is a cell (D-1) | +| `+!.basic` | `10 HERE ! 5 HERE +! HERE @ . CR` | error | unchanged | stack `empty`, prints `15 \n` | v3 raises an error FORTH-79 does not ask for: a store to HERE | +| `+!.by_zero` | `42 HERE ! 0 HERE +! HERE @ . CR` | error | unchanged | stack `empty`, prints `42 \n` | v3 raises an error FORTH-79 does not ask for: a store to HERE | +| `+!.negative` | `10 HERE ! -3 HERE +! HERE @ . CR` | error | unchanged | stack `empty`, prints `7 \n` | v3 raises an error FORTH-79 does not ask for: a store to HERE | +| `+!.accumulate` | `0 HERE ! 1 HERE +! 2 HERE +! 3 HERE +! HERE @ . CR` | error | unchanged | stack `empty`, prints `6 \n` | v3 raises an error FORTH-79 does not ask for: a store to HERE | +| `HERE.after_comma~2` | `HERE 42 , HERE SWAP - 1 CELLS = 0 SWAP /` | error | unchanged | stack `0`, prints nothing | the case divides by zero unless HERE moved by one cell; on v3 it had moved by 8 | +| `MOVE.basic` | `HERE 65 OVER C! HERE 1+ 66 OVER C! HERE HERE 16 + 2 MOVE HERE 16 + C@ . HERE 17 + C@ . CR` | stack `302 303`, printed `65 66 \n` | `65 HERE ! 66 HERE 1+ ! HERE HERE 16 + 2 MOVE HERE 16 + @ . HERE 17 + @ . CR` | stack `empty`, prints `65 66 \n` | FORTH-79: MOVE moves cells; and v3's address unit is a byte; a v4 address unit is a cell (D-1) | +| `BASE.base_store` | `16 BASE ! 255 . CR` | stack `empty`, printed `597 \n` | unchanged | stack `empty`, prints `255 \n` | 255 read in base 16 and printed in base 16 is 255; v3 printed 467 | +| `<#.basic` | `DECIMAL 42 S>D <# #S #> TYPE CR` | stack `empty`, printed `774763251095801167872\n` | unchanged | stack `empty`, prints `42\n` | v3 prints 774763251095801167872 for 42 S>D <# #S #> | +| `<#.empty` | `0 <# #> TYPE CR` | stack `0`, printed `\n` | `0 0 <# #> TYPE CR` | stack `empty`, prints `\n` | FORTH-79: <# # #S #> work on a double number; v3 takes a single | +| `<#.negative` | `-42 <# #S #> TYPE CR` | stack `empty`, printed `42\n` | `-42 DUP ABS 0 <# #S ROT SIGN #> TYPE CR` | stack `empty`, prints `-42\n` | FORTH-79: <# # #S #> work on a double number; v3 takes a single | +| `#.single_digit` | `15 <# # #> TYPE CR` | stack `empty`, printed `5\n` | `15 0 <# # #> TYPE CR` | stack `empty`, prints `5\n` | FORTH-79: <# # #S #> work on a double number; v3 takes a single | +| `#.multiple` | `15 <# # # #> TYPE CR` | stack `empty`, printed `15\n` | `15 0 <# # # #> TYPE CR` | stack `empty`, prints `15\n` | FORTH-79: <# # #S #> work on a double number; v3 takes a single | +| `#.zero_pad` | `5 <# # 0 # #> TYPE CR` | stack `0`, printed `05\n` | `5 0 <# # # #> TYPE CR` | stack `empty`, prints `05\n` | FORTH-79: <# # #S #> work on a double number; v3 takes a single | +| `#S.basic` | `42 <# #S #> TYPE CR` | stack `empty`, printed `42\n` | `42 0 <# #S #> TYPE CR` | stack `empty`, prints `42\n` | FORTH-79: <# # #S #> work on a double number; v3 takes a single | +| `#S.zero` | `0 <# #S #> TYPE CR` | stack `empty`, printed `0\n` | `0 0 <# #S #> TYPE CR` | stack `empty`, prints `0\n` | FORTH-79: <# # #S #> work on a double number; v3 takes a single | +| `#S.large` | `1234567890 <# #S #> TYPE CR` | stack `empty`, printed `1234567890\n` | `1234567890 0 <# #S #> TYPE CR` | stack `empty`, prints `1234567890\n` | FORTH-79: <# # #S #> work on a double number; v3 takes a single | +| `SIGN.negative` | `-42 ABS <# #S SIGN #> TYPE CR` | stack `0`, printed `42\n` | `-42 DUP ABS 0 <# #S ROT SIGN #> TYPE CR` | stack `empty`, prints `-42\n` | FORTH-79: <# # #S #> work on a double number; v3 takes a single | +| `SIGN.positive` | `42 <# #S SIGN #> TYPE CR` | stack `0`, printed `42\n` | `42 DUP ABS 0 <# #S ROT SIGN #> TYPE CR` | stack `empty`, prints `42\n` | FORTH-79: <# # #S #> work on a double number; v3 takes a single | +| `SIGN.zero` | `0 <# #S SIGN #> TYPE CR` | stack `0`, printed `0\n` | `0 DUP ABS 0 <# #S ROT SIGN #> TYPE CR` | stack `empty`, prints `0\n` | FORTH-79: <# # #S #> work on a double number; v3 takes a single | +| `#>.normal` | `42 <# #S #> TYPE CR` | stack `empty`, printed `42\n` | `42 0 <# #S #> TYPE CR` | stack `empty`, prints `42\n` | FORTH-79: <# # #S #> work on a double number; v3 takes a single | +| `#>.empty` | `0 <# #> TYPE CR` | stack `0`, printed `\n` | `0 0 <# #> TYPE CR` | stack `empty`, prints `\n` | FORTH-79: <# # #S #> work on a double number; v3 takes a single | +| `#>.stack_effect` | `42 <# #S #> SWAP . . CR` | stack `empty`, printed `24 2 \n` | `42 0 <# #S #> SWAP DROP . CR` | stack `empty`, prints `2 \n` | FORTH-79: <# # #S #> work on a double number; v3 takes a single | +| `HOLD.basic` | `42 <# 46 HOLD #S #> TYPE CR` | stack `empty`, printed `42.\n` | `42 0 <# 46 HOLD #S #> TYPE CR` | stack `empty`, prints `42.\n` | FORTH-79: <# # #S #> work on a double number; v3 takes a single | +| `COUNT.basic` | `HERE S" Test" DROP COUNT . . CR` | stack `302`, printed `84 303 \n` | `4 PAD C! PAD COUNT . PAD - . CR` | stack `empty`, prints `4 1 \n` | v3's address unit is a byte; a v4 address unit is a cell (D-1); and S" is not FORTH-79 | +| `COUNT.empty` | `HERE 0 OVER C! COUNT . . CR` | stack `empty`, printed `0 308 \n` | `0 PAD C! PAD COUNT . PAD - . CR` | stack `empty`, prints `0 1 \n` | v3's address unit is a byte; a v4 address unit is a cell (D-1) | +| `COUNT.max_length` | `HERE 255 OVER C! COUNT . . CR` | stack `empty`, printed `255 308 \n` | `255 PAD C! PAD COUNT . PAD - . CR` | stack `empty`, prints `255 1 \n` | v3's address unit is a byte; a v4 address unit is a cell (D-1) | +| `COUNT.basic~2` | `HERE S" Test" DROP C@ HERE 1+ SWAP COUNT . . CR` | stack `412 418`, printed `0 85 \n` | `4 PAD C! PAD COUNT . PAD - . CR` | stack `empty`, prints `4 1 \n` | v3's address unit is a byte; a v4 address unit is a cell (D-1) | +| `COUNT.empty~2` | `HERE 0 OVER C! COUNT . . CR` | stack `empty`, printed `0 418 \n` | `0 PAD C! PAD COUNT . PAD - . CR` | stack `empty`, prints `0 1 \n` | v3's address unit is a byte; a v4 address unit is a cell (D-1) | +| `COUNT.max_length~2` | `HERE 255 OVER C! COUNT . . CR` | stack `empty`, printed `255 418 \n` | `255 PAD C! PAD COUNT . PAD - . CR` | stack `empty`, prints `255 1 \n` | v3's address unit is a byte; a v4 address unit is a cell (D-1) | +| `CMOVE.basic` | `HERE S" Test" DUP >R HERE 10 + SWAP CMOVE CR` | stack `325`, printed `\n` | `65 PAD C! 66 PAD 1+ C! PAD PAD 10 + 2 CMOVE PAD 10 + C@ . PAD 11 + C@ . CR` | stack `empty`, prints `65 66 \n` | v3's address unit is a byte; a v4 address unit is a cell (D-1); and the v3 case leaves a value on the return stack | +| `TYPE.basic_string` | `HERE S" Hello" DUP >R HERE SWAP CMOVE HERE R> TYPE CR` | stack `400`, printed `Hello\n` | `72 PAD C! 105 PAD 1+ C! PAD 2 TYPE CR` | stack `empty`, prints `Hi\n` | v3's address unit is a byte; a v4 address unit is a cell (D-1); and FORTH-79: >R R> R@ are for use inside a definition; v4 refuses them at the prompt | +| `TYPE.numbers` | `HERE S" 12345" DUP >R HERE SWAP CMOVE HERE R> TYPE CR` | stack `406`, printed `12345\n` | `49 PAD C! 50 PAD 1+ C! PAD 2 TYPE CR` | stack `empty`, prints `12\n` | v3's address unit is a byte; a v4 address unit is a cell (D-1); and FORTH-79: >R R> R@ are for use inside a definition; v4 refuses them at the prompt | +| `>IN.initial` | `>IN @ . CR` | stack `empty`, printed `852597488 \n` | unchanged | stack `empty`, prints `9 \n` | FORTH-79: >IN is the offset into the input, 9 here; v3 prints an address | +| `UPDATE.no_block` | `0 SCR ! UPDATE` | error | unchanged | stack `empty`, prints nothing | v3 raises an error FORTH-79 does not ask for | +| `SCR.after_load` | `1 LOAD SCR @ . CR` | stack `empty`, printed `` | unchanged | stack `empty`, prints `1 \n` | v3 prints nothing after 1 LOAD; SCR is still 1 from the LIST before | +| `FIND.existing` | `FIND DUP . CR` | stack `empty`, printed `852596848 \n` | unchanged | 0 value(s) left; output not compared | FORTH-79: FIND takes the next word, DUP here, and leaves its address, which is printed | +| `FIND.user_word` | `: test5 44 ; FIND test5 . CR` | stack `empty`, printed `852923888 \n` | unchanged | 0 value(s) left; output not compared | the address FIND leaves is printed | +| `FIND.empty` | `FIND` | error | unchanged | stack `0`, prints nothing | FORTH-79: FIND leaves 0 when there is no word; v3 raises an error | +| `VOCABULARY.cross_vocab_access` | `VOCABULARY V1 V1 DEFINITIONS : V1WORD 11 ; FORTH V1WORD . CR` | stack `empty`, printed `11 \n` | unchanged | an error | FORTH-79: a word defined in another vocabulary is not found from FORTH; v3 finds it | +| `VOCABULARY.duplicate` | `VOCABULARY TESTVOC VOCABULARY TESTVOC` | error | unchanged | stack `empty`, prints nothing | v3 raises an error FORTH-79 does not ask for: defining a name again | +| `IF.true` | `: TEST1 IF 42 ELSE 24 THEN ; -1 TEST1 . CR` | stack `empty`, printed `42 \n` | unchanged | stack `empty`, prints `42 \n` | v3 runs an older TEST1 from another vocabulary and leaves the flag | +| `IF.false` | `: TEST2 IF 42 ELSE 24 THEN ; 0 TEST2 . CR` | stack `empty`, printed `24 \n` | unchanged | stack `empty`, prints `24 \n` | v3 runs an older TEST2 from another vocabulary and leaves the flag | +| `LEAVE.basic` | `: TLV 0 5 0 DO I 3 = IF LEAVE THEN 1+ LOOP ; TLV . CR` | stack `empty`, printed `3 \n` | unchanged | stack `empty`, prints `4 \n` | FORTH-79: LEAVE ends the loop at the next LOOP; v3 jumps out at once | +| `LEAVE.at_start` | `: TLV2 0 5 0 DO LEAVE 1+ LOOP ; TLV2 . CR` | stack `empty`, printed `0 \n` | unchanged | stack `empty`, prints `1 \n` | FORTH-79: LEAVE ends the loop at the next LOOP; v3 jumps out at once | +| `LEAVE.qdloop` | `: TLV3 0 5 0 ?DO I 2 = IF LEAVE THEN 1+ LOOP ; TLV3 . CR` | stack `empty`, printed `2 \n` | unchanged | stack `empty`, prints `3 \n` | FORTH-79: LEAVE ends the loop at the next LOOP; v3 jumps out at once | + +## 2. Address-dependent (20) + +The case leaves or prints a memory address, which is a different number on +the two machines. The number of values left is checked, and what is +printed unless an address is printed; the values are not. + +| Case | Line | Checked | +|---|---|---| +| `-TRAILING.basic` | `HERE S" Test " -TRAILING TYPE CR` | values left, and output | +| `-TRAILING.all_spaces` | `HERE S" " -TRAILING TYPE CR` | values left, and output | +| `-TRAILING.no_spaces` | `HERE S" Test" -TRAILING TYPE CR` | values left, and output | +| `HERE.stability` | `HERE DUP HERE = . CR` | values left, and output | +| `PAD.stability` | `PAD DUP PAD = . CR` | values left, and output | +| `UPDATE.basic` | `1 BLOCK UPDATE` | values left, and output | +| `UPDATE.multiple` | `1 BLOCK UPDATE UPDATE` | values left, and output | +| `SAVE-BUFFERS.dirty_blocks` | `1 BLOCK UPDATE SAVE-BUFFERS` | values left, and output | +| `EMPTY-BUFFERS.after_use` | `1 BLOCK EMPTY-BUFFERS` | values left, and output | +| `EMPTY-BUFFERS.dirty_blocks` | `1 BLOCK UPDATE EMPTY-BUFFERS` | values left, and output | +| `BUFFER.flush_dirty` | `2 BLOCK 1+ 2 BUFFER` | values left, and output | +| `BLOCK.basic` | `1 BLOCK DUP . CR` | values left only | +| `BUFFER.basic` | `1 BUFFER DUP . CR` | values left only | +| `VOCABULARY.create_and_switch` | `VOCABULARY MYVOC MYVOC DEFINITIONS CONTEXT @ . CR` | values left only | +| `CONTEXT.basic` | `CONTEXT @ . CR` | values left only | +| `CONTEXT.initial` | `FORTH CONTEXT @ . CR` | values left only | +| `CURRENT.basic` | `CURRENT @ . CR` | values left only | +| `CURRENT.after_def` | `VOCABULARY TEST-VOC8 TEST-VOC8 DEFINITIONS CURRENT @ . CR` | values left only | +| `LIST.basic` | `1 LIST` | values left only | +| `SCR.after_list` | `1 LIST SCR @ . CR` | values left only | + +## 3. Written by hand (28) + +For required words v3 has no case for. The expected results are the +standard's; no v3 run stands behind them. + +| Case | Line | Must do | +|---|---|---| +| `U*.small` | `3 4 U* . . CR` | stack `empty`, prints `0 12 \n` | +| `U*.zero` | `0 5 U* . . CR` | stack `empty`, prints `0 0 \n` | +| `U*.full` | `-1 -1 U* 2+ . 1 = . CR` | stack `empty`, prints `0 -1 \n` | +| `U/MOD.small` | `7 0 2 U/MOD . . CR` | stack `empty`, prints `3 1 \n` | +| `U/MOD.exact` | `12 0 4 U/MOD . . CR` | stack `empty`, prints `3 0 \n` | +| `U/MOD.double` | `0 1 2 U/MOD 2* . . CR` | stack `empty`, prints `0 0 \n` | +| `U/MOD.inverse` | `-1 -1 U* -1 U/MOD 1+ . . CR` | stack `empty`, prints `0 0 \n` | +| `U/MOD.carry` | `-1 -2 -1 U/MOD 1+ . 2+ . CR` | stack `empty`, prints `0 0 \n` | +| `U/MOD.by_zero` | `1 0 0 U/MOD` | an error | +| `?.basic` | `VARIABLE Q1 42 Q1 ! Q1 ? CR` | stack `empty`, prints `42 \n` | +| `EXECUTE.found` | `: E1 7 ; FIND E1 EXECUTE . CR` | stack `empty`, prints `7 \n` | +| `U..small` | `42 U. CR` | stack `empty`, prints `42 \n` | +| `U..unsigned` | `-1 U. CR` | stack `empty`, prints `18446744073709551615 \n` | +| `CONVERT.digits` | `: C1 0 0 BL WORD CONVERT DROP ; C1 123 . . CR` | stack `empty`, prints `0 123 \n` | +| `'.found` | `' DUP 0= . CR` | stack `empty`, prints `0 \n` | +| `.".in_definition` | `: Q3 ." hi there" ; Q3 CR` | stack `empty`, prints `hi there\n` | +| `LITERAL.basic` | `: Q4 [ 5 ] LITERAL ; Q4 . CR` | stack `empty`, prints `5 \n` | +| `STATE.interpreting` | `STATE @ . CR` | stack `empty`, prints `0 \n` | +| `STATE.compiling` | `: Q5 STATE @ 0= . ; IMMEDIATE : Q6 Q5 ; CR` | stack `empty`, prints `0 \n` | +| `COMPILE.basic` | `: Q7 COMPILE DUP ; IMMEDIATE : Q8 Q7 ; 3 Q8 . . CR` | stack `empty`, prints `3 3 \n` | +| `[COMPILE].basic` | `: Q9 [COMPILE] IF ; IMMEDIATE : Q10 Q9 1 ELSE 2 THEN ; 0 Q10 . -1 Q10 . CR` | stack `empty`, prints `2 1 \n` | +| `(.comment` | `1 ( 2 ) 3 . . CR` | stack `empty`, prints `3 1 \n` | +| `BLK.terminal` | `BLK @ . CR` | stack `empty`, prints `0 \n` | +| `79-STANDARD.present` | `79-STANDARD` | stack `empty`, prints nothing | +| `WORD.next_word` | `: W1 BL WORD COUNT TYPE ; W1 HELLO` | stack `empty`, prints `HELLO` | +| `WORD.delimiter` | `: W2 44 WORD COUNT TYPE ; W2 A B,` | stack `empty`, prints `A B` | +| `WORD.count` | `: W3 BL WORD C@ . ; W3 ABC` | stack `empty`, prints `3 ` | +| `WORD.skips_leading` | `: W4 BL WORD COUNT TYPE ; W4 X` | stack `empty`, prints `X` | + +## 4. v3 cases left out (27) + +| Case | Why | +|---|---| +| `EXPECT.zero_length` | reads the keyboard | +| `EXPECT.one_item` | reads the keyboard | +| `EXPECT.empty_stack` | reads the keyboard | +| `FORGET.nonexistent` | forgets a word of the system | +| `FORGET.protected` | forgets a word of the system | +| `CONTEXT.modify` | damages the system on purpose | +| `CURRENT.protect` | damages the system on purpose | +| `QUIT.in_definition` | v3 did not get through it in one session | +| `:.nested` | v3 did not get through it in one session | +| `].basic` | v3 did not get through it in one session | +| `ELSE.double` | v3 did not get through it in one session | +| `THEN.extra` | v3 did not get through it in one session | +| `CMOVE.bounds` | moves 1000 bytes over the system; v3 refuses by a bounds rule FORTH-79 has not got | +| `WORD.empty_input` | v3's WORD does not take the next word from the input, as FORTH-79's does; see the WORD cases written by hand | +| `WORD.space_delim` | v3's WORD does not take the next word from the input, as FORTH-79's does; see the WORD cases written by hand | +| `WORD.newline_delim` | v3's WORD does not take the next word from the input, as FORTH-79's does; see the WORD cases written by hand | +| `WORD.tab_delim` | v3's WORD does not take the next word from the input, as FORTH-79's does; see the WORD cases written by hand | +| `WORD.comma_delim` | v3's WORD does not take the next word from the input, as FORTH-79's does; see the WORD cases written by hand | +| `WORD.skip_leading` | v3's WORD does not take the next word from the input, as FORTH-79's does; see the WORD cases written by hand | +| `WORD.single_char` | v3's WORD does not take the next word from the input, as FORTH-79's does; see the WORD cases written by hand | +| `WORD.long_word` | v3's WORD does not take the next word from the input, as FORTH-79's does; see the WORD cases written by hand | +| `WORD.zero_delim` | v3's WORD does not take the next word from the input, as FORTH-79's does; see the WORD cases written by hand | +| `WORD.high_ascii` | v3's WORD does not take the next word from the input, as FORTH-79's does; see the WORD cases written by hand | +| `WORD.count_format` | v3's WORD does not take the next word from the input, as FORTH-79's does; see the WORD cases written by hand | +| `WORD.count_value` | v3's WORD does not take the next word from the input, as FORTH-79's does; see the WORD cases written by hand | +| `WORD.multi_delim` | v3's WORD does not take the next word from the input, as FORTH-79's does; see the WORD cases written by hand | +| `PAD.usable` | OPEN: PAD 42 OVER ! faults on v4 -- PAD is a byte address and ! takes a cell address (D-1) | + +## 5. Required words POST does not test + +`KEY` `EXPECT` `QUERY` `QUIT`. + +`KEY`, `EXPECT` and `QUERY` wait for the keyboard, which a boot cannot type +at. `QUIT` returns to the terminal without `ok`, which the capsule loader +takes for a refused line. + +## 6. Where v3 did not do what its own table expects (6) + +POST expects what v3 did, unless section 1 says otherwise. + +| Case | | +|---|---| +| `+!.basic` | v3's table says no error, v3 raised one | +| `+!.by_zero` | v3's table says no error, v3 raised one | +| `+!.negative` | v3's table says no error, v3 raised one | +| `+!.accumulate` | v3's table says no error, v3 raised one | +| `HERE.after_comma~2` | v3's table says no error, v3 raised one | +| `CREATE.long_name` | v3's table says error, v3 raised none | diff --git a/logs/20261005-161924/amd64/qemu-amd64-20261005-161924.log b/logs/20261005-161924/amd64/qemu-amd64-20261005-161924.log new file mode 100644 index 00000000..b63d4334 --- /dev/null +++ b/logs/20261005-161924/amd64/qemu-amd64-20261005-161924.log @@ -0,0 +1,112 @@ +[=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:18:59 + +UEFI BootServices: EXITED + +=== StarKernel Boot Information === +Memory map entries: 135 +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=2100864460 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=1006177928, tick_hz=100, initial_count=10061779 +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=0x4055641ee17d176b capsule_hash=0x4055641ee17d176b dict_hash=0x1ec33b48cc76a0b5 +V4: capsule v4:post79.4th signature: missing (unsigned) +PARITY:V4_POST tests=550 pass=550 fail=0 +PARITY:V4_CAPSULE name=v4:post79.4th capsule_id=0xb987dbb4388990bd capsule_hash=0xb987dbb4388990bd dict_hash=0x671fdd7aebf0f8d8 +PARITY:OK +POST: PASSED +ok> \ No newline at end of file diff --git a/logs/20261005-162142/aarch64/qemu-aarch64-20261005-162142.log b/logs/20261005-162142/aarch64/qemu-aarch64-20261005-162142.log new file mode 100644 index 00000000..0d5abc5b --- /dev/null +++ b/logs/20261005-162142/aarch64/qemu-aarch64-20261005-162142.log @@ -0,0 +1,86 @@ +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:21:17 + +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=0x4055641ee17d176b capsule_hash=0x4055641ee17d176b dict_hash=0x1ec33b48cc76a0b5 +V4: capsule v4:post79.4th signature: missing (unsigned) +PARITY:V4_POST tests=550 pass=550 fail=0 +PARITY:V4_CAPSULE name=v4:post79.4th capsule_id=0xb987dbb4388990bd capsule_hash=0xb987dbb4388990bd dict_hash=0x671fdd7aebf0f8d8 +PARITY:OK +POST: PASSED +ok> \ No newline at end of file diff --git a/logs/20261005-162524/riscv64/qemu-riscv64-20261005-162524.log b/logs/20261005-162524/riscv64/qemu-riscv64-20261005-162524.log new file mode 100644 index 00000000..d6abc1be --- /dev/null +++ b/logs/20261005-162524/riscv64/qemu-riscv64-20261005-162524.log @@ -0,0 +1,156 @@ + +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 = 0x00000000bde97936 +riscv64: satp cleared -- Bare mode, explicit (item 4.3.5a) + + + _____ _ _ __ _ + / ____| | | |/ / | | + | (___ | |_ __ _ _ __| ' / ___ _ __ _ __ ___| | + \___ \| __/ _` | '__| < / _ \ '__| '_ \ / _ \ | + ____) | || (_| | | | . \ __/ | | | | | __/ | + |_____/ \__\__,_|_| |_|\_\___|_| |_| |_|\___|_| + +LithosAnanke v2.1.0 +Architecture: riscv64 +Build: Oct 5 2026 16:24:48 + +UEFI BootServices: EXITED + +=== StarKernel Boot Information === +Memory map entries: 100 +Total memory: 1020 MB +Usable memory: 977 MB +=================================== + +PMM initialized. +PMM statistics: + Total pages: 250774 + Free pages : 250122 + 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=0x4055641ee17d176b capsule_hash=0x4055641ee17d176b dict_hash=0x1ec33b48cc76a0b5 +V4: capsule v4:post79.4th signature: missing (unsigned) +PARITY:V4_POST tests=550 pass=550 fail=0 +PARITY:V4_CAPSULE name=v4:post79.4th capsule_id=0xb987dbb4388990bd capsule_hash=0xb987dbb4388990bd dict_hash=0x671fdd7aebf0f8d8 +PARITY:OK +POST: PASSED +ok> \ No newline at end of file diff --git a/v4/Makefile b/v4/Makefile index 52e571aa..51c26060 100644 --- a/v4/Makefile +++ b/v4/Makefile @@ -129,27 +129,24 @@ $(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. +# `make post` boots the amd64 system alone, which is the quick check after a +# change to the vocabulary: nucleus, forth79.4th, POST, prompt. `make +# post79` writes the POST capsule, ../capsules/v4/post79.4th, again from +# v3's cases and tools/post79_rules.py (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 +post: $(BINDIR)/starforth4-amd64 + @$(BINDIR)/starforth4-amd64 < /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. +# PARITY:OK, POST: PASSED and the prompt: the same hashes on every ISA. .PHONY: hosted hosted-check hosted: $(foreach i,$(HOSTED_ISAS),$(BINDIR)/starforth4-$(i)) hosted-check: $(foreach i,$(HOSTED_ISAS),$(BINDIR)/boot-$(i).txt) - @grep -q '^PARITY:OK$$' $(BINDIR)/boot-amd64.txt || { echo "hosted-check: no PARITY:OK"; exit 1; } + @grep -q '^POST: PASSED$$' $(BINDIR)/boot-amd64.txt || { echo "hosted-check: no POST: PASSED"; exit 1; } @cmp $(BINDIR)/boot-amd64.txt $(BINDIR)/boot-aarch64.txt @cmp $(BINDIR)/boot-amd64.txt $(BINDIR)/boot-riscv64.txt @echo "hosted-check: amd64, aarch64 and riscv64 boot identically" diff --git a/v4/README.md b/v4/README.md index 35e615f5..7da483ae 100644 --- a/v4/README.md +++ b/v4/README.md @@ -55,58 +55,53 @@ 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, after the POST work began: all six builds load -`v4:forth79.4th` and reach `ok>` with the same lines: +State, 2026-10-05: all six builds start the nucleus, load `v4:forth79.4th`, +pass POST and reach `ok>`, with the same lines: ``` 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:V4_CAPSULE name=v4:forth79.4th capsule_id=0x4055641ee17d176b capsule_hash=0x4055641ee17d176b dict_hash=0x1ec33b48cc76a0b5 +PARITY:V4_POST tests=550 pass=550 fail=0 +PARITY:V4_CAPSULE name=v4:post79.4th capsule_id=0xb987dbb4388990bd capsule_hash=0xb987dbb4388990bd dict_hash=0x671fdd7aebf0f8d8 PARITY:OK +POST: PASSED ok> ``` -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 +Bare-metal logs: `logs/20261005-161924/amd64/`, `logs/20261005-162142/aarch64/`, +`logs/20261005-162524/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: every word is still in the nucleus. +**What this does not yet show.** `forth79.4th` holds two definitions, `U*` +and `U/MOD`. Every other word is still in the assembled nucleus, so POST is +so far a test of the assembled words. Moving them to the capsule, a group at +a time with POST after each, is the next step (`NUCLEUS.md` section 8). ## 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. +`capsules/v4/post79.4th`: 550 cases in blocks 7000 up, covering 126 of the +130 words of the FORTH-79 Required Word Set. 443 are v3's cases with what +the hosted v3 binary did as the expected result. The other 107, and the 27 +v3 cases left out, are listed with reasons in `docs/v4.0.0/POST79.md`. -**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: +- `make -C v4 post` boots the amd64 system: the quick check after a change. +- `make -C v4 hosted-check` boots all three hosted ISAs and compares them. +- `make -C v4 post79` writes the capsule again (`tools/mkpost.py`, + `tools/post79_rules.py`); it needs the hosted v3 binary. -``` -PARITY:V4_POST tests=537 pass=439 fail=98 -PARITY:FAIL -POST: FAILED -``` +POST is FORTH: a harness of FORTH-79 words and two nucleus hooks, `(CATCH)` +and `(EMIT-HOOK)`. It forgets itself when it has finished. The boot passes +only on seeing POST's tally line with `fail=0` (`v4/system/boot.c`). A colon +definition broken on purpose (`U/MOD` without its last `SWAP`) fails five +cases and the boot stops with `POST: FAILED`. -The 98 are not yet sorted into v4 defects and differences that need a -ruling. A first reading finds four kinds: +Not tested: `KEY`, `EXPECT`, `QUERY` (the keyboard) and `QUIT` (it returns +without ` ok`). -| 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 | +Open: `PAD 42 OVER !` faults on v4, because `PAD` is a byte address and `!` +takes a cell address (D-1). FORTH-79 expects it to work. The v3 case for it +is left out until that is ruled. -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. +The Required Word Set list in `tools/mkpost.py` was written from memory of +the standard and has not been checked against the document. diff --git a/v4/system/boot.c b/v4/system/boot.c index 840a9fff..bbde2c6e 100644 --- a/v4/system/boot.c +++ b/v4/system/boot.c @@ -11,11 +11,11 @@ #include "starkernel/capsule_blocks.h" /* The capsules, in the order they are loaded. */ -/* 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. */ +/* POST is part of the boot: v4:post79.4th is loaded after the vocabulary it + * tests and must end with a clean tally. -DV4_POST_AT_BOOT=0 leaves it + * out, for work on a vocabulary that does not pass yet. */ #ifndef V4_POST_AT_BOOT -#define V4_POST_AT_BOOT 0 +#define V4_POST_AT_BOOT 1 #endif static const char *const boot_capsules[] = { "v4:forth79.4th", @@ -136,14 +136,18 @@ static int text_at(const char *line, unsigned len, unsigned at, const char *want static void post_watch(char c) { static const char clean[] = " fail=0"; + unsigned i; 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); - } + /* the node's prompt comes before it on the line, so look along the line */ + for (i = 0; i < post_len; i++) + if (text_at(post_line, post_len, i, "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); + break; + } post_len = 0; } diff --git a/v4/tools/mkpost.py b/v4/tools/mkpost.py index 578ede60..cf077ec8 100755 --- a/v4/tools/mkpost.py +++ b/v4/tools/mkpost.py @@ -36,6 +36,9 @@ import re import subprocess import sys +sys.path.insert(0, os.path.dirname(os.path.abspath(__file__))) +import post79_rules as rules # noqa: E402 + 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") @@ -83,15 +86,15 @@ HARNESS = r""" ( 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 +VARIABLE TDEP CREATE TBUF 64 ALLOT CREATE TSTK 16 ALLOT CREATE TNAME 8 ALLOT -0 T# ! 0 TPASS ! 0 TFAIL ! 0 TOPEN ! 10 TBASE ! +0 T# ! 0 TPASS ! 0 TFAIL ! 0 TOPEN ! : 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 ! + 255 AND 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 ; @@ -107,34 +110,38 @@ CREATE TBUF 64 ALLOT CREATE TSTK 16 ALLOT CREATE TNAME 8 ALLOT TBAD @ IF 1 TFAIL +! ." POST FAIL: " TN COUNT TYPE T-SHOW CR ELSE 1 TPASS +! THEN - 0 TOPEN ! 0 (CATCH) ! TBASE @ BASE ! + 0 TOPEN ! 0 (CATCH) ! THEN ; ===== -( T{ name begin a case: clean stack, errors caught ) +( T{ name begin a case: clean stack, decimal, FORTH ) : T{ ( i*x -- ) T-CLOSE T-CLEAR + DECIMAL [COMPILE] FORTH DEFINITIONS 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 ; +: T-END ( -- ) 0 (EMIT-HOOK) ! 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 ; +( n }TD only how many values the case must have left ) +: }TD ( n -- ) TDEP @ = 0= IF 1 TBAD ! THEN ; ( 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. @@ -312,13 +319,13 @@ def run_v3(v3, cases): 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.append('TCLR DECIMAL FORTH DEFINITIONS ." [[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) + done = subprocess.run([v3, "--log-none"], input=("\n".join(script) + "\n").encode("latin-1"), + capture_output=True, timeout=600) + text = ANSI.sub("", done.stdout.decode("latin-1")) # a byte is a character results = [] for n, case in enumerate(cases): begin, mid, end = "[[B%d]] ok\nok> " % n, "ok> [[E%d]]" % n, "[[S%d]]" % n @@ -362,6 +369,7 @@ def main(): ap = argparse.ArgumentParser() ap.add_argument("--v3", default=os.path.join(ROOT, "lfs", "amd64", "starforth")) ap.add_argument("--report", default=None) + ap.add_argument("--dump", default=None, help="write what v3 did with every case") args = ap.parse_args() required, left_out, cases, seen = set(REQUIRED), [], [], {} @@ -410,21 +418,60 @@ def main(): current.extend(part.strip("\n").split("\n")) flush() - disagreements = [] + disagreements, applied = [], {"address": 0, "standard": 0, "extra": 0} + + def expectation(error, stack, output, mode="full"): + """The lines that end a case.""" + if error: + return ["->ERR"] + if mode == "depth": + return ["-> %d }TD" % len(stack)] + if mode == "depth+output": + return pack("", ["->", str(len(stack)), "}TD", str(len(output)), str(checksum(output)), "T="]) + return pack("", ["->"] + [str(v) for v in stack] + ["}T", str(len(output)), str(checksum(output)), "T="]) + + def emit(label, lines, ending): + block = ["T{ " + label] + lines + ending + if len(current) + len(block) > 16: + flush() + current.extend(block) + + dump = [] for case, (error, stack, output) in zip(cases, results): + label = case["label"] + dump.append("%s\n input: %s\n v3: %s stack=%s out=%r\n" + % (label, " ".join(case["text"].split()), "ERROR" if error else "ok", stack, output)) if error != case["should_error"]: - disagreements.append((case["label"], "v3's table says %s, v3 %s" + disagreements.append((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") + if label in rules.STANDARD: + rule = rules.STANDARD[label] + if rule is None: # the case is dropped + applied["standard"] += 1 + left_out.append((label, rules.DROPPED[label])) + continue + lines = pack("T|", atoms(rule.get("text", case["text"]))) + assert lines, label + if "depth" in rule: + emit(label, lines, ["-> %d }TD" % rule["depth"]]) + else: + emit(label, lines, expectation(rule.get("error", False), rule.get("stack", []), rule.get("out", ""))) + applied["standard"] += 1 + elif label in rules.ADDRESS: + emit(label, case["lines"], expectation(error, stack, output, rules.ADDRESS[label])) + applied["address"] += 1 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) + emit(label, case["lines"], expectation(error, stack, output)) + for rule in rules.EXTRA: + lines = pack("T|", atoms(rule["text"])) + assert lines, rule + emit(rule["label"], lines, expectation(rule.get("error", False), rule.get("stack", []), rule.get("out", ""))) + applied["extra"] += 1 + unknown = [k for k in list(rules.STANDARD) + list(rules.ADDRESS) if k not in {c["label"] for c in cases}] + assert not unknown, "rules for cases that do not exist: %s" % unknown + if args.dump: + open(args.dump, "w").write("\n".join(dump)) flush() blocks.append(["T-REPORT", "FORGET T# DECIMAL"]) @@ -436,9 +483,15 @@ def main(): assert len(line) <= LINE_MAX, line out.write(line + "\n") - tested = sorted({c["word"] for c in cases}) + tested = sorted({c["word"] for c in cases} | {r["label"].rsplit(".", 1)[0] for r in rules.EXTRA}) 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), + dropped = sum(1 for v in rules.STANDARD.values() if v is None) + total = len(cases) - dropped + len(rules.EXTRA) + report = ["POST cases: %d, in %d blocks (%d to %d)" % (total, len(blocks), FIRST_BLOCK, FIRST_BLOCK + len(blocks) - 1), + " from v3 unchanged: %d" % (len(cases) - applied["address"] - applied["standard"]), + " from v3, address-dependent (post79_rules.ADDRESS): %d" % applied["address"], + " rewritten or dropped for FORTH-79 (post79_rules.STANDARD): %d, of which dropped %d" % (applied["standard"], dropped), + " written by hand (post79_rules.EXTRA): %d" % applied["extra"], "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)] @@ -446,10 +499,73 @@ def main(): 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" + write_doc(cases, results, left_out, disagreements, untested, total, applied, dropped) if args.report: open(args.report, "w").write(text) sys.stdout.write(text) +DOC = os.path.join(ROOT, "docs", "v4.0.0", "POST79.md") + + +def code(text): + return "`" + " ".join(text.split()).replace("|", "\\|") + "`" + + +def expects(rule): + if rule.get("error"): + return "an error" + if "depth" in rule: + return "%d value(s) left; output not compared" % rule["depth"] + return "stack `%s`, prints %s" % (" ".join(str(v) for v in rule.get("stack", [])) or "empty", + "`%s`" % rule["out"].replace("\n", "\\n") if rule.get("out") else "nothing") + + +def write_doc(cases, results, left_out, disagreements, untested, total, applied, dropped): + by_label = {c["label"]: (c, r) for c, r in zip(cases, results)} + out = ["# POST for the FORTH-79 Required Word Set: where it departs from v3", "", + "Written by `v4/tools/mkpost.py` from `v4/tools/post79_rules.py`; do not edit.", + "Design: `NUCLEUS.md` section 6. The capsule is `capsules/v4/post79.4th`.", "", + "POST runs %d cases. %d are v3's, with what the hosted v3 binary did as the" % (total, len(cases) - applied["address"] - applied["standard"]), + "expected result. This file lists every other case, and why.", "", + "## 1. Rewritten for FORTH-79 (%d)" % (applied["standard"] - dropped), "", + "v3 departs from the standard, or the case is written for v3's machine. v4", + "follows the standard (standing ruling), so the expected result is the", + "standard's and not v3's.", "", + "| Case | v3's line | What v3 did | As POST runs it | Must do | Why |", "|---|---|---|---|---|---|"] + for label, rule in rules.STANDARD.items(): + if rule is None: + continue + case, (error, stack, output) = by_label[label] + did = "error" if error else "stack `%s`, printed `%s`" % (" ".join(map(str, stack)) or "empty", output.replace("\n", "\\n")[:40]) + ran = code(rule["text"]) if "text" in rule else "unchanged" + out.append("| `%s` | %s | %s | %s | %s | %s |" % (label, code(case["text"]), did, ran, expects(rule), rule["why"])) + out += ["", "## 2. Address-dependent (%d)" % applied["address"], "", + "The case leaves or prints a memory address, which is a different number on", + "the two machines. The number of values left is checked, and what is", + "printed unless an address is printed; the values are not.", "", + "| Case | Line | Checked |", "|---|---|---|"] + for label, mode in rules.ADDRESS.items(): + out.append("| `%s` | %s | %s |" % (label, code(by_label[label][0]["text"]), + "values left, and output" if mode == "depth+output" else "values left only")) + out += ["", "## 3. Written by hand (%d)" % len(rules.EXTRA), "", + "For required words v3 has no case for. The expected results are the", + "standard's; no v3 run stands behind them.", "", + "| Case | Line | Must do |", "|---|---|---|"] + for rule in rules.EXTRA: + out.append("| `%s` | %s | %s |" % (rule["label"], code(rule["text"]), expects(rule))) + out += ["", "## 4. v3 cases left out (%d)" % len(left_out), "", "| Case | Why |", "|---|---|"] + out += ["| `%s` | %s |" % item for item in left_out] + out += ["", "## 5. Required words POST does not test", "", + " ".join("`%s`" % w for w in untested) + ".", "", + "`KEY`, `EXPECT` and `QUERY` wait for the keyboard, which a boot cannot type", + "at. `QUIT` returns to the terminal without `ok`, which the capsule loader", + "takes for a refused line.", "", + "## 6. Where v3 did not do what its own table expects (%d)" % len(disagreements), "", + "POST expects what v3 did, unless section 1 says otherwise.", "", "| Case | |", "|---|---|"] + out += ["| `%s` | %s |" % item for item in disagreements] + open(DOC, "w").write("\n".join(out) + "\n") + + if __name__ == "__main__": main() diff --git a/v4/tools/post79_rules.py b/v4/tools/post79_rules.py new file mode 100644 index 00000000..300bc9c4 --- /dev/null +++ b/v4/tools/post79_rules.py @@ -0,0 +1,163 @@ +"""post79_rules.py -- where POST does not take v3's word for it. + +mkpost.py takes every case from v3 and, by default, what v3 did with it. +This file holds the exceptions, each with its reason. Ruled by Captain Bob, +2026-10-05 (docs/v4.0.0/NUCLEUS.md 6.5): + + ADDRESS the case leaves or prints a memory address, which is not the + same number on the two machines. "depth+output": the number of + values left and what was printed are checked, the values are + not. "depth": only the number of values, because an address is + printed. + + STANDARD v3 departs from FORTH-79, or the case is written for v3's + machine; v4 follows the standard. The entry gives the case as + POST runs it: `text` if the line had to change, then what it + must do -- `error`, or `stack` and `out`, or `depth` alone where + an address is printed. None drops the case. `why` is the + reason, and is what docs/v4.0.0/POST79.md lists. + + EXTRA cases written by hand, for required words v3 has no case for. +""" + +D1 = "v3's address unit is a byte; a v4 address unit is a cell (D-1)" +PIC = "FORTH-79: <# # #S #> work on a double number; v3 takes a single" +RS = "FORTH-79: >R R> R@ are for use inside a definition; v4 refuses them at the prompt" +PICK = "FORTH-79: PICK and ROLL count from 1; v3 counts from 0" +LEAVE = "FORTH-79: LEAVE ends the loop at the next LOOP; v3 jumps out at once" +V3WORD = "v3's WORD does not take the next word from the input, as FORTH-79's does; see the WORD cases written by hand" +V3ERR = "v3 raises an error FORTH-79 does not ask for" +VOC = "FORTH-79: a word defined in another vocabulary is not found from FORTH; v3 finds it" + +ADDRESS = { + "-TRAILING.basic": "depth+output", "-TRAILING.all_spaces": "depth+output", "-TRAILING.no_spaces": "depth+output", + "HERE.stability": "depth+output", "PAD.stability": "depth+output", + "UPDATE.basic": "depth+output", "UPDATE.multiple": "depth+output", "SAVE-BUFFERS.dirty_blocks": "depth+output", + "EMPTY-BUFFERS.after_use": "depth+output", "EMPTY-BUFFERS.dirty_blocks": "depth+output", + "BUFFER.flush_dirty": "depth+output", + "BLOCK.basic": "depth", "BUFFER.basic": "depth", + "VOCABULARY.create_and_switch": "depth", "CONTEXT.basic": "depth", "CONTEXT.initial": "depth", + "CURRENT.basic": "depth", "CURRENT.after_def": "depth", + # the standard leaves the layout of a listing to the system + "LIST.basic": "depth", "SCR.after_list": "depth", +} + +STANDARD = { + "PICK.pick_0": dict(error=True, why=PICK + "; 0 PICK is an error"), + "PICK.pick_1": dict(stack=[1, 2, 3], out="3 \n", why=PICK), + "PICK.pick_2": dict(stack=[1, 2, 3], out="2 \n", why=PICK), + "ROLL.roll_1": dict(out="3 2 1 \n", why=PICK), + + ">R.basic": dict(text=": RS1 42 >R R@ . R> . CR ; RS1", out="42 42 \n", why=RS), + ">R.zero": dict(text=": RS2 0 >R R@ . R> . CR ; RS2", out="0 0 \n", why=RS), + ">R.negative": dict(text=": RS3 -123 >R R@ . R> . CR ; RS3", out="-123 -123 \n", why=RS), + ">R.multiple": dict(text=": RS4 1 2 >R >R R@ . R> . R@ . R> . CR ; RS4", out="1 1 2 2 \n", why=RS), + "R>.basic": dict(text=": RS5 42 >R R> . CR ; RS5", out="42 \n", why=RS), + "R>.lifo_order": dict(text=": RS6 1 2 >R >R R> . R> . CR ; RS6", out="1 2 \n", why=RS), + "R@.basic": dict(text=": RS7 42 >R R@ . R> DROP CR ; RS7", out="42 \n", why=RS), + "R@.non_destructive": dict(text=": RS8 99 >R R@ R@ = . R> DROP CR ; RS8", out="-1 \n", why=RS), + + ",.basic": dict(text="42 , HERE 1 - @ . CR", out="42 \n", why=D1), + ",.negative": dict(text="-999 , HERE 1 - @ . CR", out="-999 \n", why=D1), + "+!.basic": dict(out="15 \n", why=V3ERR + ": a store to HERE"), + "+!.by_zero": dict(out="42 \n", why=V3ERR + ": a store to HERE"), + "+!.negative": dict(out="7 \n", why=V3ERR + ": a store to HERE"), + "+!.accumulate": dict(out="6 \n", why=V3ERR + ": a store to HERE"), + "HERE.after_comma~2": dict(stack=[0], why="the case divides by zero unless HERE moved by one cell; on v3 it had moved by 8"), + "MOVE.basic": dict(text="65 HERE ! 66 HERE 1+ ! HERE HERE 16 + 2 MOVE HERE 16 + @ . HERE 17 + @ . CR", + out="65 66 \n", why="FORTH-79: MOVE moves cells; and " + D1), + "PAD.usable": None, # see OPEN below + + "BASE.base_store": dict(out="255 \n", why="255 read in base 16 and printed in base 16 is 255; v3 printed 467"), + + "<#.basic": dict(out="42\n", why="v3 prints 774763251095801167872 for 42 S>D <# #S #>"), + "<#.empty": dict(text="0 0 <# #> TYPE CR", out="\n", why=PIC), + "<#.negative": dict(text="-42 DUP ABS 0 <# #S ROT SIGN #> TYPE CR", out="-42\n", why=PIC), + "#.single_digit": dict(text="15 0 <# # #> TYPE CR", out="5\n", why=PIC), + "#.multiple": dict(text="15 0 <# # # #> TYPE CR", out="15\n", why=PIC), + "#.zero_pad": dict(text="5 0 <# # # #> TYPE CR", out="05\n", why=PIC), + "#S.basic": dict(text="42 0 <# #S #> TYPE CR", out="42\n", why=PIC), + "#S.zero": dict(text="0 0 <# #S #> TYPE CR", out="0\n", why=PIC), + "#S.large": dict(text="1234567890 0 <# #S #> TYPE CR", out="1234567890\n", why=PIC), + "SIGN.negative": dict(text="-42 DUP ABS 0 <# #S ROT SIGN #> TYPE CR", out="-42\n", why=PIC), + "SIGN.positive": dict(text="42 DUP ABS 0 <# #S ROT SIGN #> TYPE CR", out="42\n", why=PIC), + "SIGN.zero": dict(text="0 DUP ABS 0 <# #S ROT SIGN #> TYPE CR", out="0\n", why=PIC), + "#>.normal": dict(text="42 0 <# #S #> TYPE CR", out="42\n", why=PIC), + "#>.empty": dict(text="0 0 <# #> TYPE CR", out="\n", why=PIC), + "#>.stack_effect": dict(text="42 0 <# #S #> SWAP DROP . CR", out="2 \n", why=PIC), + "HOLD.basic": dict(text="42 0 <# 46 HOLD #S #> TYPE CR", out="42.\n", why=PIC), + + "COUNT.basic": dict(text="4 PAD C! PAD COUNT . PAD - . CR", out="4 1 \n", why=D1 + "; and S\" is not FORTH-79"), + "COUNT.empty": dict(text="0 PAD C! PAD COUNT . PAD - . CR", out="0 1 \n", why=D1), + "COUNT.max_length": dict(text="255 PAD C! PAD COUNT . PAD - . CR", out="255 1 \n", why=D1), + "COUNT.basic~2": dict(text="4 PAD C! PAD COUNT . PAD - . CR", out="4 1 \n", why=D1), + "COUNT.empty~2": dict(text="0 PAD C! PAD COUNT . PAD - . CR", out="0 1 \n", why=D1), + "COUNT.max_length~2": dict(text="255 PAD C! PAD COUNT . PAD - . CR", out="255 1 \n", why=D1), + "CMOVE.basic": dict(text="65 PAD C! 66 PAD 1+ C! PAD PAD 10 + 2 CMOVE PAD 10 + C@ . PAD 11 + C@ . CR", + out="65 66 \n", why=D1 + "; and the v3 case leaves a value on the return stack"), + "CMOVE.bounds": None, # moves 1000 bytes over the system; v3 refuses by a bounds rule FORTH-79 has not got + "TYPE.basic_string": dict(text="72 PAD C! 105 PAD 1+ C! PAD 2 TYPE CR", out="Hi\n", why=D1 + "; and " + RS), + "TYPE.numbers": dict(text="49 PAD C! 50 PAD 1+ C! PAD 2 TYPE CR", out="12\n", why=D1 + "; and " + RS), + + ">IN.initial": dict(out="9 \n", why="FORTH-79: >IN is the offset into the input, 9 here; v3 prints an address"), + + "WORD.empty_input": None, "WORD.space_delim": None, "WORD.newline_delim": None, "WORD.tab_delim": None, + "WORD.comma_delim": None, "WORD.skip_leading": None, "WORD.single_char": None, "WORD.long_word": None, + "WORD.zero_delim": None, "WORD.high_ascii": None, "WORD.count_format": None, "WORD.count_value": None, + "WORD.multi_delim": None, + + "UPDATE.no_block": dict(why=V3ERR), + "SCR.after_load": dict(out="1 \n", why="v3 prints nothing after 1 LOAD; SCR is still 1 from the LIST before"), + + "FIND.existing": dict(depth=0, why="FORTH-79: FIND takes the next word, DUP here, and leaves its address, which is printed"), + "FIND.user_word": dict(depth=0, why="the address FIND leaves is printed"), + "FIND.empty": dict(stack=[0], why="FORTH-79: FIND leaves 0 when there is no word; v3 raises an error"), + + "VOCABULARY.cross_vocab_access": dict(error=True, why=VOC), + "VOCABULARY.duplicate": dict(why=V3ERR + ": defining a name again"), + + "IF.true": dict(out="42 \n", why="v3 runs an older TEST1 from another vocabulary and leaves the flag"), + "IF.false": dict(out="24 \n", why="v3 runs an older TEST2 from another vocabulary and leaves the flag"), + "LEAVE.basic": dict(out="4 \n", why=LEAVE), + "LEAVE.at_start": dict(out="1 \n", why=LEAVE), + "LEAVE.qdloop": dict(out="3 \n", why=LEAVE), +} + +# Dropped, and why. mkpost.py prints these with the cases it leaves out. +DROPPED = { + "PAD.usable": "OPEN: PAD 42 OVER ! faults on v4 -- PAD is a byte address and ! takes a cell address (D-1)", + "CMOVE.bounds": "moves 1000 bytes over the system; v3 refuses by a bounds rule FORTH-79 has not got", +} +for _name in [k for k, v in STANDARD.items() if v is None and k.startswith("WORD.")]: + DROPPED[_name] = V3WORD + +EXTRA = [ + dict(label="U*.small", text="3 4 U* . . CR", out="0 12 \n"), + dict(label="U*.zero", text="0 5 U* . . CR", out="0 0 \n"), + dict(label="U*.full", text="-1 -1 U* 2+ . 1 = . CR", out="0 -1 \n"), # (2^N-1)^2: high cell 2^N-2, low cell 1 + dict(label="U/MOD.small", text="7 0 2 U/MOD . . CR", out="3 1 \n"), + dict(label="U/MOD.exact", text="12 0 4 U/MOD . . CR", out="3 0 \n"), + dict(label="U/MOD.double", text="0 1 2 U/MOD 2* . . CR", out="0 0 \n"), # 2^N / 2: quotient 2^(N-1), remainder 0 + dict(label="U/MOD.inverse", text="-1 -1 U* -1 U/MOD 1+ . . CR", out="0 0 \n"), + dict(label="U/MOD.carry", text="-1 -2 -1 U/MOD 1+ . 2+ . CR", out="0 0 \n"), + dict(label="U/MOD.by_zero", text="1 0 0 U/MOD", error=True), + dict(label="?.basic", text="VARIABLE Q1 42 Q1 ! Q1 ? CR", out="42 \n"), + dict(label="EXECUTE.found", text=": E1 7 ; FIND E1 EXECUTE . CR", out="7 \n"), + dict(label="U..small", text="42 U. CR", out="42 \n"), + dict(label="U..unsigned", text="-1 U. CR", out="18446744073709551615 \n"), + dict(label="CONVERT.digits", text=": C1 0 0 BL WORD CONVERT DROP ; C1 123 . . CR", out="0 123 \n"), + dict(label="'.found", text="' DUP 0= . CR", out="0 \n"), + dict(label='.".in_definition', text=': Q3 ." hi there" ; Q3 CR', out="hi there\n"), + dict(label="LITERAL.basic", text=": Q4 [ 5 ] LITERAL ; Q4 . CR", out="5 \n"), + dict(label="STATE.interpreting", text="STATE @ . CR", out="0 \n"), + dict(label="STATE.compiling", text=": Q5 STATE @ 0= . ; IMMEDIATE : Q6 Q5 ; CR", out="0 \n"), + dict(label="COMPILE.basic", text=": Q7 COMPILE DUP ; IMMEDIATE : Q8 Q7 ; 3 Q8 . . CR", out="3 3 \n"), + dict(label="[COMPILE].basic", text=": Q9 [COMPILE] IF ; IMMEDIATE : Q10 Q9 1 ELSE 2 THEN ; 0 Q10 . -1 Q10 . CR", out="2 1 \n"), + dict(label="(.comment", text="1 ( 2 ) 3 . . CR", out="3 1 \n"), + dict(label="BLK.terminal", text="BLK @ . CR", out="0 \n"), + dict(label="79-STANDARD.present", text="79-STANDARD"), + dict(label="WORD.next_word", text=": W1 BL WORD COUNT TYPE ; W1 HELLO", out="HELLO"), + dict(label="WORD.delimiter", text=": W2 44 WORD COUNT TYPE ; W2 A B,", out="A B"), + dict(label="WORD.count", text=": W3 BL WORD C@ . ; W3 ABC", out="3 "), + dict(label="WORD.skips_leading", text=": W4 BL WORD COUNT TYPE ; W4 X", out="X"), +]