Page 16 of 25
Re: Fleet Forth design considerations
Posted: Tue May 10, 2022 3:43 am
by GARTHWILSON
I can't think of any situation where STATE would be something other than 0 or FFFF. I would think that if it were, it'd be because something corrupted it, meaning it would be invalid anyway. If that happened, you'd probably have additional problems to worry about.
Re: Fleet Forth design considerations
Posted: Tue May 10, 2022 5:19 am
by barrym95838
I'm pretty sure that I read of an example somewhere a few years back where an advanced user would decrement or increment STATE with [ and ] to allow some form of nested compilation, but I can't remember any other details.
Re: Fleet Forth design considerations
Posted: Tue May 10, 2022 5:26 am
by GARTHWILSON
I'm pretty sure that I read of an example somewhere a few years back where an advanced user would decrement or increment STATE with [ and ] to allow some form of nested compilation, but I can't remember any other details.
Might it have been for conditional compilation?
Re: Fleet Forth design considerations
Posted: Tue May 10, 2022 5:35 am
by barrym95838
Might it have been for conditional compilation?
Maybe. The concept flew over my head at the time, but I took a swipe at it and stuffed it into a dusty corner of my brain, hoping to return later and analyze it better. Later is still waiting, and that dusty corner is now covered by a pile of laundry ...
Re: Fleet Forth design considerations
Posted: Sat May 14, 2022 12:16 am
by JimBoyd
I can't think of any situation where STATE would be something other than 0 or FFFF. I would think that if it were, it'd be because something corrupted it, meaning it would be invalid anyway. If that happened, you'd probably have additional problems to worry about.
I was being excessively cautious, but I was thinking of something along the lines of building an execution table by doing this
instead of this
Code: Select all
CREATE TABLE1
' ROT , ' -ROT , ' SWAP ,
This could also work.
Code: Select all
CREATE TABLE1
STATE ON ROT -ROT SWAP [
In Fleet Forth, the following would not work.
Code: Select all
CREATE TABLE1
1 STATE ! ROT -ROT SWAP [
Since STATE is only supposed to be manipulated by [ and ] , manipulating STATE directly, as in the last two examples, should be avoided.
That being the case, I will leave (I/C) , the heart of Fleet Forth's interpreter, as is.
Re: Fleet Forth design considerations
Posted: Sat May 14, 2022 12:29 am
by JimBoyd
Might it have been for conditional compilation?
Maybe. The concept flew over my head at the time, but I took a swipe at it and stuffed it into a dusty corner of my brain, hoping to return later and analyze it better. Later is still waiting, and that dusty corner is now covered by a pile of laundry ...
I would think that in addition to conditional compiling, one would want conditional interpretation included since code words are assembled while interpreting.
Here is Fleet Forth's source for conditional compiling.
Code: Select all
:NONAME ( NL1 ADR -- NL2 )
( NL1 ADR -- )
DUP 5 " [IF]" TEXT= ABS UNDER+
DUP 7 " [THEN]" TEXT= UNDER+
7 " [ELSE]" TEXT= OVER 1 =
AND + ?DUP ?EXIT
['] (I/C) IS I/C ;
: [THEN] ; IMMEDIATE
: [ELSE] ( -- )
1 [ ROT ] LITERAL IS I/C ;
IMMEDIATE
: [IF] ( FLAG -- )
?EXIT
[COMPILE] [ELSE] ; IMMEDIATE
A system which increments and decrements STATE could do so for some other purpose, but I can't imagine what.
Re: Fleet Forth design considerations
Posted: Sun Jun 12, 2022 10:01 pm
by JimBoyd
(Whether rounded or truncated, the result is usually inexact anyway.)
The accuracy for small numbers can be improved. The word DSQRT takes a 64 bit number (a quadruple number or two doubles in Fleet Forth) and returns a double. The input could also be considered a mixed fraction consisting of two unsigned doubles where the top double is the integer part and the lower double is the fraction part. In this case the double number result from DSQRT would be a mixed fraction with the top cell the integer part and the lower cell the fraction part.
Here is a word to take a possible improper mixed fraction (the numerator might be larger than the denominator) and fix it.
Code: Select all
: MFIX ( UD1 U1 U2 -- UD2 U3 U2 )
>R 0 R@ UM/MOD 2SWAP 0 -ROT D+
ROT R> ;
And a word to convert that to a fixed point number consisting of a double fraction and a double integer.
Code: Select all
: FIXED ( UD1 U1 U2 -- UD2 UD3 )
DUP>R 0 -ROT UM/MOD SWAP
0 SWAP R> UM/MOD NIP
SWAP 2SWAP ;
When the parameter for DSQRT is a fixed point number (a mixed fraction with 32 bits for each part as I've described) , the result can be displayed with this word.
Code: Select all
: .RESULT ( UD -- )
1 U.R ." ."
3 0
DO
1000 UM* 0 <# # # # #> TYPE
LOOP
DROP ;
The high cell is displayed as is since it is the integer portion. The DO LOOP extracts and displays the fractional portion three decimal places at a time.
For this mixed fraction: 2. 0 1 (which can also be entered as 0. 2.), the following:
returns this result:
1.414199829
which should be within 0.001 percent of the correct answer.
Re: Fleet Forth design considerations
Posted: Thu Jun 16, 2022 2:31 am
by JimBoyd
For greater precision when the integer portion of the parameter for DSQRT is no bigger than an unsigned single (0-65535), the following word can be used to take an integer with a fraction and convert it to a 64 bit fixed point number, consisting of two Forth double numbers, where the integer portion is only 16 bits.
Code: Select all
: FIXED ( U NUM DEN -- UT U )
DUP>R 0 -ROT UM/MOD SWAP
0 SWAP R@ UM/MOD SWAP
0 SWAP R> UM/MOD NIP
SWAP 2SWAP SWAP ;
In the stack comments, UT means unsigned triple.
Here is a word to 'clean up' sloppy fractions.
Code: Select all
: MFIX ( U U2 U3 -- U4 U5 U3 )
>R 0 R@ UM/MOD UNDER+ R> ;
And an appropriate version of .RESULT
Code: Select all
: .RESULT ( UD -- )
256. UMD* 1 D.R ." ."
3 0
DO
1000. UMD* <# # # # #> TYPE
LOOP
2DROP ;
UMD* multiplies two double numbers and produces a quadruple number.
.RESULT first multiplies the double number result by the double number 256. to produce a quadruple number result. The top double number is the integer portion of the result.
As with the other version of .RESULT , the DO LOOP extracts and displays the fractional portion three decimal places at a time.
Here is the source for UMD* used in this version of .RESULT
Code: Select all
: UMD* ( UD1 UD2 -- UQ )
// UD1 - B A UD2 - D C
ROT 2DUP UM* // B D C A AC
>R >R 2OVER // B D C A B D
ROT UM* >R >R // B D C B
UM* >R >R UM* // BD
0 R> R> R> // BDL BDH. L H L
SWAP >R 0 TUCK // BDL BDH. L. L.
D+ D+ 0 // BDL BDH+ CY.
R> R> 0 TUCK // BDL BDH+ CY. H. H.
D+ D+ // BDL BDH+ CY+ CY2
R> R> D+ ;
Here is the source for DSQRT . It does not round.
Code: Select all
CODE DSQRT ( UQ -- UD )
TYA $FF ,X STA 8 # LDY
BEGIN
N 1- ,Y STA DEY
0< UNTIL
$20 # LDY
BEGIN
1 ,X LDA
0= WHILE
0 ,X LDA 1 ,X STA
3 ,X LDA 0 ,X STA
2 ,X LDA 3 ,X STA
5 ,X LDA 2 ,X STA
4 ,X LDA 5 ,X STA
7 ,X LDA 4 ,X STA
6 ,X LDA 7 ,X STA
DEY DEY DEY DEY
0= UNTIL
POPTWO JMP
THEN
BEGIN
6 ,X ASL 7 ,X ROL
4 ,X ROL 5 ,X ROL
2 ,X ROL 3 ,X ROL
0 ,X ROL 1 ,X ROL
N ROL N 1+ ROL
N 2+ ROL N 3 + ROL
$FF ,X ROL
6 ,X ASL 7 ,X ROL
4 ,X ROL 5 ,X ROL
2 ,X ROL 3 ,X ROL
0 ,X ROL 1 ,X ROL
N ROL N 1+ ROL
N 2+ ROL N 3 + ROL
$FF ,X ROL
N 4 + ASL N 5 + ROL
N 6 + ROL N 7 + ROL
N 1- ROL SEC
N 4 + ROL N 5 + ROL
N 6 + ROL N 7 + ROL
N 1- ROL SEC
N LDA N 4 + SBC
N 1+ LDA N 5 + SBC
N 2+ LDA N 6 + SBC
N 3 + LDA N 7 + SBC
$FF ,X LDA N 1- SBC
CS IF
N LDA N 4 + SBC N STA
N 1+ LDA N 5 + SBC N 1+ STA
N 2+ LDA N 6 + SBC N 2+ STA
N 3 + LDA N 7 + SBC N 3 + STA
$FF ,X LDA N 1- SBC $FF ,X STA
N 4 + LDA 2 # ORA N 4 + STA
THEN
N 1- LSR
N 7 + ROR N 6 + ROR
N 5 + ROR N 4 + ROR DEY
0= NOT WHILE // TOO FAR TO
REPEAT // BRANCH BACK
N 4 + LDA 6 ,X STA
N 5 + LDA 7 ,X STA
N 6 + LDA 4 ,X STA
N 7 + LDA 5 ,X STA
POPTWO JMP
END-CODE
Re: Fleet Forth design considerations
Posted: Mon Jun 20, 2022 1:45 am
by BruceRMcF
I can't think of any situation where STATE would be something other than 0 or FFFF. I would think that if it were, it'd be because something corrupted it, meaning it would be invalid anyway. If that happened, you'd probably have additional problems to worry about.
I can easily imagine a situation where STATE is not used by the outer interpreter, but is simply offered as a convenience for portable code, where STATE is always 0 or TRUE, but setting STATE doesn't actually DO anything ... when you CALL STATE, it infers the state, and puts the 0 or TRUE in the location that it returns.
Also in a context of support for porting standard code to a system, I can also imagine a situation where there are three states ... regular interpretation, regular compilation, and some special compilation state, where STATE for the special compilation state is 1 rather than TRUE.
Re: Fleet Forth design considerations
Posted: Sat Jun 25, 2022 2:34 am
by JimBoyd
I've changed the way WORD is defined in Fleet Forth.
Both versions use 'STREAM to obtain the address of the current position in the text stream and the remaining length. Here is the latest definition of 'STREAM .
Code: Select all
: 'STREAM ( -- ADR N )
BLK @ ?DUP
IF
BLOCK B/BUF
ELSE
TIB #TIB @
THEN
>IN @
OVER UMIN /STRING ;
Both use SKIP to skip leading occurrences of the delimiter and SCAN to scan for the delimiter at the end of the parsed text.
The new version of Fleet Forth's WORD is different in how it adjusts >IN . The old WORD saved the length returned by 'STREAM , the address returned by SKIP , and the address and length returned by SCAN . They were passed to the headerless word ADJUST in this order: address returned by SKIP , length returned by 'STREAM , address returned by SCAN , and length returned by SCAN . ADJUST calculated how far to move >IN without making it point further than one byte past the text stream. Even though ADJUST was headerless, it did have a name in the source used by the metacompiler.
For the old and new versions of WORD , as well as CHAR , when the source is a block, WORD will never leave >IN with a value larger than B/BUF ( 1024), otherwise >IN will never be left with a value larger than that in #TIB . Although >IN can be manually set to a larger value, doing so causes 'STREAM to return a size of zero for the remaining length of the text stream.
The new version of Fleet Forth's WORD does away with the headerless word ADJUST . The length returned by 'STREAM is added to >IN , pushing it just past the text stream. The length remaining returned by SCAN is decremented and the maximum of it and zero is subtracted from >IN .
The change to CHAR also did away with the need for ADJUST . CHAR takes a delimiter and returns an address and length for the parsed text. CHAR does not skip leading delimiters and the text stream can not be exhausted without an error condition since the delimiter must be found. The only place CHAR alters >IN is where the returned length plus one is added to >IN .
Here are the old versions of WORD and CHAR .
Code: Select all
NH
2VARIABLE HISTORY
NH
: ADJUST ( A1 L1 A2 L2 -- A1 CNT )
DUP 0<> + NEGATE ROT + \ adr1 adr2 len3
>IN +! \ adr1 adr2
OVER - ; \ adr1 cnt
: WORD ( C -- ADR )
>R 'STREAM \ adr1 len1
BLK 2@ HISTORY 2! \ save BLK and >IN
TUCK R@ SKIP \ len1 adr2 len2
>R TUCK R> R> SCAN \ adr2 len1 adr3 len3
ADJUST >HERE ; \ adr2 cnt
: CHAR ( C -- ADR CNT )
DUP>R LIT [ HERE >A 0 , ] C!
'STREAM 2DUP R> \ adr1 len1 adr1 len1 c
SCAN DUP 0= \ adr1 len1 adr2 len2 flag
[ HERE 3 + A> ! ]
ABORT" MISSING"
ADJUST ; \ adr1 cnt
Here are the new versions.
Code: Select all
NH
2VARIABLE HISTORY
: WORD ( C -- HERE )
'STREAM \ c adr1 len1
BLK 2@ HISTORY 2! \ save BLK and >IN
DUP >IN +!
2PICK SKIP \ c adr2 len2
ROT 2PICK -ROT SCAN \ adr2 adr3 len3
1- 0 MAX NEGATE >IN +! \ adr2 adr3
OVER - >HERE ; \ here
: CHAR ( C -- ADR CNT )
DUP>R LIT [ HERE >A 0 , ] C!
'STREAM 2DUP R> \ adr1 len1 adr1 len1 c
SCAN 0= \ adr1 len1 adr2 flag
[ HERE 3 + A> ! ]
ABORT" MISSING"
NIP OVER - \ adr2 cnt
DUP 1+ >IN +! ; \ adr2 cnt
The line:
Code: Select all
BLK 2@ HISTORY 2! \ save BLK and >IN
saves the values of BLK and >IN in a headerless double variable HISTORY for use by WHERE , the word which displays where an error occurred.
The extra size of WORD and CHAR exactly offset the memory saved by removing the headerless word ADJUST ; however, there are fewer trips through NEXT with WORD and CHAR so they will be slightly faster.
Re: Fleet Forth design considerations
Posted: Wed Jul 13, 2022 11:47 pm
by JimBoyd
I've changed the definition for Fleet Forth's LOAD . Here is the old definition:
And the new:
Code: Select all
: LOAD ( U -- )
0 SWAP BRANCH
[ ' LINELOAD >BODY , ] ; -2 ALLOT
This does not change the size of LOAD , nor will it make a noticeable speed improvement. It does save a cell on the return stack for each nesting of nested LOADs .
I've also changed the source for Fleet Forth's warm start routine from this:
Code: Select all
HSUBR WARM
$FF # LDX TXS
(WARM) JSR
>FORTH
FORTH DEFINITIONS
." {REV}WARM START"
ABORT ; -2 ALLOT
To this:
Code: Select all
HSUBR WARM
$FF # LDX TXS
(WARM) JSR
>FORTH
FORTH DEFINITIONS
." {REV}WARM START"
QUIT ; -2 ALLOT
Note: {REV} is the reverse print character in the C64 PETSCII. A carriage return clears the reverse print mode.
Here is the definition for Fleet Forth's ABORT
Code: Select all
: ABORT ( -- )
SINGLE ERR SP! AP!
QUIT ; -2 ALLOT
Since the stacks are cleared and multitasking is disabled in the subroutine called by the warm start and cold start routines, there is no need to go to ABORT rather than QUIT in the warm start routine. This also avoids executing the deferred word ERR during a warm start which could have been initiated because ERR was set to a bad vector.
Re: Fleet Forth design considerations
Posted: Tue Jul 19, 2022 12:40 am
by JimBoyd
Back near the end of 2020 I presented the source code for Fleet Forth's new (ABORT") , which is so much faster than the old version when there is no error.
Code: Select all
CODE (ABORT") ( F -- )
0 ,X LDA, 1 ,X ORA,
0= IF,
IP )Y LDA, SEC,
IP ADC, IP STA,
CS IF, IP 1+ INC, THEN,
POP JMP,
THEN,
>FORTH
WHERE CR R@ S?
ABORT ;
-2 ALLOT
The following snippet of code skips Fleet Forth's instruction pointer, IP , over an inline counted string.
Code: Select all
IP )Y LDA, SEC,
IP ADC, IP STA,
CS IF, IP 1+ INC, THEN,
There are two other words in Fleet Forth which skip over an inline string. They are (.") and (") .
Code: Select all
: (.") ( -- )
R> COUNT 2DUP + >R TYPE ;
: (") ( -- ADR )
R> DUP COUNT + >R ;
Fleet Forth's kernel can be made smaller by taking the string skipping code out of (ABORT") and placing it in (") .
Code: Select all
: (") ( -- ADR )
R@
>ASSEM
IP )Y LDA SEC
IP ADC IP STA
CS IF IP 1+ INC THEN
NEXT JMP END-CODE
: (.") ( -- )
R@ COUNT TYPE
BRANCH
[ ' (") >BODY 2+ , ] ; -2 ALLOT
The new (") is six bytes bigger and the new (.") is four bytes smaller.
The newest (ABORT") is twelve bytes smaller for a net savings of ten bytes.
Code: Select all
CODE (ABORT") ( F -- )
INX INX
$FE ,X LDA $FF ,X ORA
' (") >BODY 4 + 0= BRAN
>FORTH
WHERE CR R> S?
ABORT ; -2 ALLOT
(ABORT") is still fast. When there is no error, this version of (ABORT") should be two cycles faster. The branch does not cross a page boundary, my metacompiler reports page boundary crossings. I get a print file of the metacompiler messages by typing LOGGER before loading the kernel source.
There is also this code in ?BRANCH
Code: Select all
LABEL 2.IP.+!
CLC
IP LDA 2 # ADC IP STA
NEXT CS NOT BRAN
IP 1+ INC
NEXT 0= NOT BRAN // ALWAYS
which skips IP over a cell.
Note: LABEL creates a label in the metacompiler's host vocabulary with the present value of THERE , the target's HERE , as its value. It does not increase the size of the target in any way.
This code fragment, 2.IP.+! can also be used by (IS) , the word compiled by IS , and COMPILE .
The original source.
Code: Select all
: (IS)
R> DUP 2+ >R @ >BODY ! ;
: COMPILE
?COMP R> DUP 2+ >R @ , ;
And the new.
Code: Select all
: (IS) ( -- )
R@ @ >BODY !
LABEL SKIP.CELL
>ASSEM
2.IP.+! JMP END-CODE
: COMPILE
?COMP R@ @ , BRANCH
[ SKIP.CELL , ] ; -2 ALLOT
The new (IS) is three bytes smaller and the new COMPILE is four bytes smaller.
Re: Fleet Forth design considerations
Posted: Tue Aug 16, 2022 2:35 am
by JimBoyd
I mentioned in this post that I was going to write an experimental kernel. I've written the experimental kernel and I like it. Here is the source for the following words:
?EXIT 0EXIT ?LEAVE (LOOP) ?BRANCH
Code: Select all
CODE ?EXIT ( F -- )
INX INX
$FE ,X LDA $FF ,X ORA
0= IF CS>A
0= NOT IF CS>A END-CODE
CODE 0EXIT ( F -- )
INX INX
$FE ,X LDA $FF ,X ORA
0= NOT IF CS>A
0= IF CS>A END-CODE
CODE ?LEAVE ( F -- )
INX INX
$FE ,X LDA $FF ,X ORA
0= IF CS>A
0= NOT IF CS>A END-CODE
CODE (LOOP)
XSAVE STX TSX $101 ,X INC
0= IF // BRANCHING OUT OF WORD
SEC TYA
LABEL I.HI+A
$102 ,X ADC $102 ,X STA
VS IF // BRANCHING OUT OF WORD
XSAVE LDX
A>CS A>CS THEN
LABEL LEAVE.BODY
PLA PLA PLA PLA
A>CS A>CS THEN
A>CS A>CS THEN
LABEL EXIT.BODY
PLA IP STA PLA IP 1+ STA
THEN THEN THEN CS>A CS>A
LABEL NEXT
1 # LDY
IP )Y LDA W 1+ STA DEY
IP )Y LDA W STA CLC
IP LDA 2 # ADC IP STA
CS NOT IF
W 1- JMP
THEN
IP 1+ INC
W 1- JMP END-CODE
CODE ?BRANCH ( F -- )
INX INX
$FE ,X LDA $FF ,X ORA
0= NOT IF
LABEL 2.IP.+!
CLC
IP LDA 2 # ADC IP STA
NEXT CS NOT BRAN
IP 1+ INC
NEXT 0= NOT BRAN // ALWAYS
A>CS THEN A>CS THEN
LABEL XBRANCH
XSAVE LDX
THEN
IP )Y LDA PHA INY
IP )Y LDA IP 1+ STA
PLA IP STA
NEXT 2+ JMP END-CODE
The label XBRANCH is no longer needed since it is now only used in the phrase XBRANCH 2+ . I will remove it and add a label just under the line with XSAVE LDX . This new label will be BRANCH.BODY . Of course, I'll need to change the two occurrences of XBRANCH 2+ to BRANCH.BODY .
In Fleet Forth, an item of control flow data consists of an address and a security number. The words which supply the address and security number are
>MARK <MARK
the words which use the address and security number are
>RESOLVE <RESOLVE
The control flow security is to make sure that a >MARK is matched with a >RESOLVE and a <MARK is matched with a <RESOLVE . These two conditions are to make sure that branches are properly resolved, avoiding an upcoming system crash. As long as they are met, control flow words can be used in any way the programmer sees fit.
The word CS>A copies one item of control flow data to the auxiliary stack and the word A>CS copies one item of control flow data from the auxiliary stack.
Using the auxiliary stack to temporarily hold the control flow data makes it easier to write branches out of the words ?EXIT 0EXIT and ?LEAVE and into the body of (LOOP) . It also makes it easier to write two branches out of (LOOP) and into the body of ?BRANCH (really into the part that has the code for BRANCH ).
Here is the source for the words BRANCH LEAVE and EXIT , which have no bodies.
Code: Select all
CODE BRANCH ( -- )
-2 ALLOT XBRANCH 2+ ,
END-CODE
CODE LEAVE ( -- )
-2 ALLOT LEAVE.BODY ,
END-CODE
CODE EXIT ( -- )
-2 ALLOT EXIT.BODY ,
END-CODE
With the new kernel, EXIT and LEAVE fall through to NEXT because their code is in the body of (LOOP) .
(LOOP) falls through to NEXT when the DO LOOP terminates.
Here is the new source for LIT .
Code: Select all
CODE LIT ( -- W )
DEX DEX
IP )Y LDA 0 ,X STA INY
IP )Y LDA 1 ,X STA
2.IP.+! JMP END-CODE
2.IP.+! is a metacompiler label for the address in ?BRANCH which, as the label name implies, adds two to IP .
Here is the new source for CLIT .
Code: Select all
CODE CLIT ( -- B )
IP )Y LDA
IP INC
0= IF IP 1+ INC THEN
AYPUSH JMP
// SETUP SETS CARRY AS SIDE EFFECT
LABEL SETUP
.A ASL N 1- STA
BEGIN
0 ,X LDA N ,Y STA
INX INY N 1- CPY
0= UNTIL
0 # LDY
RTS END-CODE
Placing the code for SETUP right after CLIT was done as a convenience (or laziness on my part). I could just as well have placed END-CODE after the jump to AYPUSH with HSUBR SETUP (headerless subroutine) used rather than LABEL SETUP .
LIT and CLIT are used in LITERAL .
Code: Select all
: LITERAL ( N -- )
DUP SPLIT NIP
IF COMPILE LIT , EXIT THEN
COMPILE CLIT C, ; IMMEDIATE
I have removed the constants PUSH and PUT from Fleet Forth's assembler. Fleet Forth has AYPUSH to push a cell on the data stack with the low byte in the accumulator and high byte in the Y-register, and the word AYPUT to replace a cell on the data stack. If the high byte were in the accumulator, I would have named them YAPUSH and YAPUT to reflect the (low byte, high byte) order of the 16 bit cell.
It seemed awkward to me to have AYPUSH AYPUT as well as PUSH PUT in the assembler, almost like Fleet Forth's kernel was not a single unified design. With the new kernel, a jump to PUSH and PUT now cost three more clocks cycles, so I got rid of them.
If a code word needs them, the following code fragments can be defined.
Code: Select all
SUBR PUSH ( -- W )
TAY PLA
AYPUSH JMP
END-CODE
SUBR PUT ( -- W )
TAY PLA
AYPUT JMP
END-CODE
These are used just like the constants PUSH and PUT in the FIG Forth assembler.
I have a disk of Blazin' Forth utilities ported to Fleet Forth. When I modified the words using PUSH and PUT to use AYPUSH and AYPUT , they were smaller. These words were a more natural fit for AYPUSH and AYPUT than PUSH and PUT .
The experimental kernel was slightly smaller until I saw how I could squeeze a few more cycles out of the code portion of BLOCK and made a few other speed/size trade offs before rebuilding once again. The experimental kernel is now about three bytes bigger than the other one.
I'm going to run a few more tests, maybe look for potential optimizations. My metacompiler reports where a branch crosses a page boundary, I'd like to minimize the occurrence of those. They're not so bad when the branch is not part of a loop, but I really don't like the extra cycle in a loop. As I said, I like this experimental kernel. It is Fleet Forth's new kernel.
Re: Fleet Forth design considerations
Posted: Tue Aug 30, 2022 12:49 am
by JimBoyd
In this post I discussed Fleet Forth's WORD .
I think UMIN and 2PICK were the only non-standard words which I didn't define.
UMIN is the unsigned version of MIN .
Fleet Forth's 2PICK has the same stack effect as the phrase '2 PICK'.
Here is Fleet Forth's 2PICK
Code: Select all
CODE 2PICK ( N1 N2 N3 -- N1 N2 N3 N1 )
4 ,X LDA 5 ,X LDY
AYPUSH JMP END-CODE
Fleet Forth's double number version of PICK is DPICK
As with Mosaic Forth's DPICK , it is zero based and copies the double number whose high cell is the Nth item on the data stack, not counting N. This double number could also be thought of as a pair of single numbers.
Code: Select all
DPICK ( D WN-1 . . . W0 +N -- D WN-1 . . . W0 D )
Here is another way to look at it. Not counting N, PICK skips the top N numbers on the stack and copies the next one to push onto the stack.
2PICK skips the top number, the next to top number and copies the third number to push onto the stack.
DPICK also skips the top N numbers on the stack but it copies two cells ( a double or a pair of singles ) to push onto the stack.
Re: Fleet Forth design considerations
Posted: Sat Sep 03, 2022 3:07 pm
by BruceRMcF
In xForth I use THIRD for what you have called 2PICK. FOURTH is what would be 3PICK in that naming system, but I stop at THIRD, so the verbal confusion of FOURTH and FORTH is not an issue.