6502.org Forum  Projects  Code  Documents  Tools  Forum
It is currently Sat Nov 23, 2024 11:42 am

All times are UTC




Post new topic Reply to topic  [ 51 posts ]  Go to page 1, 2, 3, 4  Next
Author Message
PostPosted: Sun Jul 24, 2022 11:04 pm 
Offline

Joined: Fri May 05, 2017 9:27 pm
Posts: 895

When I wrote my metacompiler my main goal was to get my Forth kernel written and built. The metacompiler works and overall I am pleased with it; however, there is room for improvement. As the topic suggests, this thread is about the redesign of the Fleet Forth metacompiler.
The first goal, or milestone, with the new metacompiler will be to simply build a CODE word in virtual memory complete with a header and an alias in a target Forth vocabulary on the host (a handle to access the new word). Although the ability to build CODE words in virtual memory may seem more difficult because a target assembler is required, that part isn't that difficult. Supporting CREATE DOES> words in the target is, if not trickier, then definitely messier.
Fleet Forth's metacompiler needs access to virtual memory to build the new kernel. I discuss Fleet Forth's virtual memory words in this post. Fleet Forth's virtual memory uses Forth blocks with a high enough number that they are mapped to the Ram Expansion Unit, but could just as well be mapped to one of the disk drives. Virtual memory doesn't have to be set up this way. Since the kernel is less than ten kilobytes, an array could be created like this.
Code:
CREATE VIRTUAL  10240 ALLOT

In this case >VIRTUAL is just this.
Code:
: >VIRTUAL  ( ADR -- VADR )
   VIRTUAL + ;

Regardless of how virtual memory is implemented, the metacompiler needs the following virtual memory words, which are in Fleet Forth even without the metacompiler.
Code:
>VIRTUAL  ( adr -- vadr ) -- convert an address to the address in virtual memory buffer.
VC@  ( vadr -- b )        -- fetch a byte from virtual memory.
VC!  ( b vadr -- )        -- store a byte in virtual memory.
V@   ( vadr -- w )        -- fetch a cell from virtual memory.
V!   ( w vadr -- )        -- store a cell in virtual memory.
CMOVE>V  ( adr vadr u )   -- copy u bytes at adr to virtual memory.
VMSAVE  ( start.adr end.adr+1 name.adr cnt -- )
                          -- save virtual memory to disk.

The metacompiler will need to build a dictionary in the target.
Code:
VARIABLE TDP
VARIABLE (ORIGIN)  (ORIGIN) ON
: ORIGIN  ( ADR -- )
   DUP (ORIGIN) @ UMIN (ORIGIN) !
   TDP ! ;
: THERE  ( -- VADR )
   TDP @ ;
: VALLOT  ( N -- )
   TDP +! ;
: VC,  ( B -- )
   THERE 1 VALLOT VC! ;
: V,  ( W -- )
   THERE 2 VALLOT V! ;
: VADD  ( ADR -- )
   THERE OVER @ V,  SWAP ! ;

TDP is the target DP .
THERE is the target HERE .
VALLOT is virtual ALLOT .
VC, and V, are virtual C, and , respectively.
VADD is the virtual memory equivalent of Fleet Forth's ADD . it takes an address in real memory (such as a variable) which is used to hold a chain of addresses and adds THERE to it.
Here is an example of the use of ADD in Fleet Forth to add a VOCABULARY to VOC-LINK , the chain of all vocabularies used by FORGET to prune vocabularies.
Code:
: VOCABULARY  ( -- )
   VARIABLE  CURRENT @ ,
   VOC-LINK ADD          \ <- here
   DOES>
      CONTEXT ! ;

and a code snippet from Fleet Forth's CREATE to link the new word into the current vocabulary.
Code:
   CURRENT @ ADD

A few string manipulating words are also needed.
Code:
: >THERE  ( ADR CNT -- THERE )
   >HERE THERE TUCK OVER C@ 2+
   CMOVE>V ;
: VNAME  ( -- HERE )
   NAME DUP THERE OVER C@ 2+
   CMOVE>V ;
CODE V,"  ( -- )
   >FORTH
   ASCII " CHAR
   >THERE C@ 1+ VALLOT ;

>THERE takes an address of a string with a count and moves that string to HERE and THERE as a counted string with a trailing blank.
VNAME parses the text stream for a blank delimited name moves it to HERE and THERE as a counted string with a trailing blank.
V," is the metacompiler's version of ," . It parses the text stream for a " delimiter and copies that string to HERE and THERE as a counted string with a trailing blank.
A word to TOGGLE bits in an address is needed.
Code:
: VTOGGLE  ( VADR B -- )
   SWAP >VIRTUAL SWAP TOGGLE
   UPDATE ;

And now a few more vocabularies.
Code:
FORTH DEFINITIONS
: HOST  ( -- )
   FORTH DEFINITIONS ; IMMEDIATE
: [HOST]   FORTH ; IMMEDIATE
VOCABULARY META  META DEFINITIONS
VOCABULARY SHADOW  SHADOW DEFINITIONS
VOCABULARY FORTH  FORTH DEFINITIONS
HOST
: [META]   META ; IMMEDIATE
: [SHADOW]   [META] SHADOW ; IMMEDIATE
: [TARGET]   [SHADOW] FORTH ; IMMEDIATE
: TARGET   [TARGET] FORTH DEFINITIONS ; IMMEDIATE
HOST

Notice that there are two Forth vocabularies. This is not a problem. The only vocabulary in Fleet Forth without a parent vocabulary is the original Forth vocabulary. Every other vocabulary has a parent, the vocabulary in which it was created, as the word VOCS shows. This is a portion of a session log after the second ASSEMBLER vocabulary was added.
Code:
VOCS
FORTH
  META
    SHADOW
      FORTH
        ASSEMBLER
  EDITOR
  ASSEMBLER
 OK

The metacompiler will need to build a header in virtual memory as well as creating a word in the target Forth vocabulary for each word defined for the target. The word VHEADER creates a header in virtual memory. It does not add a code field. HEADER executes VHEADER and creates an alias in the target Forth vocabulary.
Here are some variables and helper words for VHEADER .
Code:
VARIABLE WLINK
VARIABLE HEAD
VARIABLE HEADS
VARIABLE HEADLESS
VARIABLE PNAMES
: NH  ( -- )
   ?EXEC  HEAD OFF ; IMMEDIATE
: PNAME  ( -- )
   1 VALLOT  1 PNAMES +!
   COLS ?CR ." PADDED: R"
   HERE S? CR ;

WLINK holds the start of the chain of link fields.
If either HEAD or HEADS are ON then the word being defined in virtual memory will have a header. HEAD is normally used to switch headers off for one word at a time. HEADS is normally zero to allow some headerless words and true to forbid headerless words.
NH is used just before a word is defined and is a shortcut for the phrase HEAD OFF .
PNAME compensates for the indirect jump bug by padding memory before the link field is created. It also keeps track of the number of padded headers and displays the name of each as it occurs.
Here are some words for target Forth vocabulary only searches and some words used for peace of mind. the peace of mind words show if compiling to the host took place.
Code:
// TARGET SEARCH & SANITY CHECK
: TFIND  ( AD -- AD 0/XT 1/XT -1 )
   [TARGET] ['] FORTH
   [HOST] >BODY VFIND ;
: ?TFIND  ( F -- )
   ABORT" NOT IN TARGET" ;
: T'   NAME TFIND 0= ?TFIND
   >BODY @ ;
VARIABLE CDP
: !CDP  ( -- )  HERE CDP ! ;
: ?CDP  ( -- )  HERE CDP @ <>
   ABORT" COMPILED TO HOST" ;

VFIND is a primitive like (FIND) , but it only searches one vocabulary. It does not search parent vocabularies. It is also a word defined in the Fleet Forth kernel without a body of its own. Its code field points one byte into the body of (FIND) .
The word to build headers in virtual memory, VHEADER .
Code:
: VHEADER  ( >IN@ -- >IN@ )
   VNAME TFIND NIP
   ABORT" REDEFINITION IN TARGET"
   HEAD @ HEADS @ OR
   IF
      DUP >IN !
      HERE C@ THERE + 4 +
      SPLIT DROP 0=
      IF  PNAME  THEN
      WLINK VADD
      VNAME C@  THERE $80 VTOGGLE
      VALLOT  THERE $80 VTOGGLE
      1 VALLOT
      EXIT
   THEN
   THERE 1+ SPLIT DROP 0=
   IF  PNAME  THEN
   1 HEADLESS +! ;

It takes the current value of >IN on the stack and returns the current value of >IN on the stack. HEADER leaves a copy on the stack anyway and there are two possible paths in VHEADER , one which parses a name to create a header and one which does not (but still pads memory if needed to avoid the code field straddling a page boundary).
The word to create the header in virtual memory via VHEADER and create an alias in the target Forth vocabulary.
Code:
: HEADER  ( -- )
   >IN @ VHEADER DUP >IN !
   NAME FIND 0<> AND  SWAP >IN !
   HEAD ON
   CREATE
      THERE ,  ,  0 ,
      [ HERE 2+ >A ]
   DOES>
      2+ @ DUP 0=
      ABORT" COUNTERPART NOT FOUND"
      EXECUTE ;
A> CONSTANT TARGET-WORD-CF

TARGET-WORD-CF is a constant which is used later.
The auxiliary stack words >A and A> can be replaced with the phrases 2 ! and 2 @ respectively.
An alias in the target Forth vocabulary is a CREATE DOES> word with three cells in its body.
The first cell is the code field address of its counterpart in virtual memory.
The second cell is the address of its counterpart in the host system. It could be defined in the original FORTH vocabulary or the META vocabulary or even the SHADOW vocabulary. If there is no counterpart found in the host system, a zero is stored in that cell.
The third cell is for statistical data, how many times this word is compiled into another.
A word to initialize those variables and one to show some stats.
Code:
: START  ( -- )
   WLINK OFF  (ORIGIN) ON
   HEAD ON  HEADS OFF
   HEADLESS OFF  PNAMES OFF
   [COMPILE] TARGET ; IMMEDIATE
: META-STATUS   SETWIDTH
   CR ."    STATE: " STATE @ U.
   CR ."    WLINK: " WLINK @ U.
   CR ."     HEAD: " HEAD @ U.
   CR ."    HEADS: " HEADS @ U.
   CR ." HEADLESS: " HEADLESS @ U.
   CR ."   ORIGIN: " (ORIGIN) @ U.
   CR ."    THERE: " TDP @ U.
   CR ."   PADDED: " PNAMES @ U.
   ORDER ;

The completed metacompiler with have a slightly more complex START and META-STATUS but not by much. These versions are adequate for now.
The last thing needed to be able to build CODE words in virtual memory is the target assembler.
Code:
// TIE IN WITH FLEET FORTH ASSEMBLER
TARGET VOCABULARY ASSEMBLER
HOST ASSEMBLER ' NOT >LINK
TARGET ' ASSEMBLER >BODY !
HOST
: [ASSEMBLER]   [TARGET] ASSEMBLER ;
   IMMEDIATE
TARGET ASSEMBLER DEFINITIONS

HEX
: CPU0   CREATE C, DOES>  C@ VC, ;
  0 CPU0 BRK    18 CPU0 CLC
0D8 CPU0 CLD    58 CPU0 CLI
0B8 CPU0 CLV   0CA CPU0 DEX
 88 CPU0 DEY   0E8 CPU0 INX
0C8 CPU0 INY   0EA CPU0 NOP
 48 CPU0 PHA     8 CPU0 PHP
 68 CPU0 PLA    28 CPU0 PLP
 40 CPU0 RTI    60 CPU0 RTS
 38 CPU0 SEC   0F8 CPU0 SED
 78 CPU0 SEI   0AA CPU0 TAX
0A8 CPU0 TAY   0BA CPU0 TSX
 8A CPU0 TXA    9A CPU0 TXS
 98 CPU0 TYA

HEX
: CPU1  ( BMAP BOP -- )
   [ FORTH ]
   CREATE C, , DOES>
   Z  DUP 1 MODE @ MEM DUP>R
   LSHIFT AND 0=
   ABORT" NON VALID ADDRESSING MODE"
   0< $B AND  R@ + TABLE + C@ + VC,
   R> ?DUP 0EXIT
   7 U<  IF  VC,  EXIT  THEN
   V, ;
ASSEMBLER

HEX
073E  61 CPU1 ADC
073E  21 CPU1 AND
073E 0C1 CPU1 CMP
073E  41 CPU1 EOR
073E 0A1 CPU1 LDA
073E  01 CPU1 ORA
073E 0E1 CPU1 SBC
0736  81 CPU1 STA
0331  02 CPU1 ASL
0331  42 CPU1 LSR
0331  22 CPU1 ROL
0331  62 CPU1 ROR
8558 0A2 CPU1 LDX
8338 0A0 CPU1 LDY

HEX
 0330  C2 CPU1 DEC
 0330  E2 CPU1 INC
 8118  E0 CPU1 CPX
 8118  C0 CPU1 CPY
 0150  82 CPU1 STX
 0130  80 CPU1 STY
 0110  20 CPU1 BIT
 0180  40 CPU1 JMP
 0100  14 CPU1 JSR

HEX
: >BRA  ( N1 N2 -- N3 )
   RB HEX
   OVER SPLIT NIP OVER 1+ SPLIT NIP <>
   IF
      COLS ?CR ." PAGE CROSSING "
      DUP ASCII V 2OVER 1+ U<
      IF
         [ ASCII ^ ASCII V - ] LITERAL
         +
      THEN
      DUP EMIT EMIT SPACE 1- U.
      ." : R" LATEST ID. CR
   THEN
   BO ;

HEX
: THEN  ( ADDR CS -- )
   ?EXEC  31 ?PAIRS
   THERE OVER VC@
   IF
      SWAP V!
   ELSE
      OVER >BRA SWAP VC!
   THEN
; IMMEDIATE

HEX
: IF  ( CC -- ADR CS )
   ?EXEC  VC,  THERE 0 VC, 31
; IMMEDIATE
: AHEAD  ( -- ADR CS )
   ?EXEC
   THERE 1+ 1 JMP 31 ; IMMEDIATE
: WHILE  ( A1 C1 -- A2 C2 A1 C1 )
   [COMPILE] IF 2SWAP ; IMMEDIATE
: ELIF  ( ADR1 CS -- ADR2 CS )
   [COMPILE] WHILE
   [COMPILE] THEN ; IMMEDIATE
: ELSE  ( ADR1 CS -- ADR2 CS )
   [COMPILE] AHEAD  2SWAP
   [COMPILE] THEN ; IMMEDIATE

HEX
: BEGIN  ( -- ADR CS )  ?EXEC
   THERE 32 ; IMMEDIATE
: AGAIN  ( ADR CS -- )  ?EXEC
   32 ?PAIRS JMP ; IMMEDIATE
: UNTIL  ( ADR CS CC -- )  ?EXEC
   VC, 32 ?PAIRS
   THERE >BRA VC,
; IMMEDIATE
: REPEAT  ( ADR1 CS1 ADR2 CS2 -- )
   [COMPILE] AGAIN
   [COMPILE] THEN ; IMMEDIATE
: BRAN  ( ADR CS -- )
   NOT 32 SWAP
   [COMPILE] UNTIL ; IMMEDIATE

HEX
META DEFINITIONS
: ASSEMBLE  ( -- ADR TRUE )
   LATEST TRUE OVER TSB
   [ASSEMBLER] ASSEMBLER MEM
   !CDP ;
HOST

META DEFINITIONS
: CODE  ( -- ADR TRUE )
   HEADER THERE 2+ V,
   ASSEMBLE ;
: END-CODE  ( ADR TRUE -- )
   ?CDP [COMPILE] END-CODE ;
   IMMEDIATE
HOST

Now to build some CODE words in virtual memory. Here is the session log.
Code:
 OK
VOCS
FORTH
  META
    SHADOW
      FORTH
        ASSEMBLER
  EDITOR
  ASSEMBLER
 OK
ORDER
CONTEXT: FORTH
         
CURRENT: FORTH
         
 OK
START  OK
1024 ORIGIN  OK
CODE TESTWORD  OK
   0 ,X LDA  1 ,X ORA  OK
   0= IF  DEY  THEN  OK
   RTS  OK
   END-CODE  OK
HOST  OK
TARGET  OK
TESTWORD
TESTWORD
^^^^^^^^
COUNTERPART NOT FOUND

Typing TESTWORD shows that a word called TESTWORD was not defined in the SHADOW , META , or host FORTH vocabularies.
Code:
HOST  OK
$FB CONSTANT IP  OK
$FE CONSTANT W  OK
TARGET  OK
CODE LIT  OK
   IP )Y LDA  PHA  IP INC  OK
   0= IF  IP 1+ INC  THEN  OK
   IP )Y LDA  IP INC  OK
   0= IF  IP 1+ INC  THEN  OK
   DEX  DEX  OK
   1 ,X STA  PLA  0 ,X STA  OK
   1 # LDY  OK
   IP )Y LDA  W 1+ STA  DEY  OK
   IP )Y LDA  W    STA  CLC  OK
   IP LDA  2 # ADC  IP STA  OK
   CS NOT IF  OK
      W 1- JMP  OK
   THEN  OK
   IP 1+ INC  OK
   W 1- JMP  END-CODE  OK
' TESTWORD >BODY 6 HEX DUMP
838A   B  4  0  0  0  0  0  0  E1 7E 82 49 D0 AE 24 FB   KD@@@@@@...I..$.
 OK
' LIT >BODY 6 DUMP
83AF  1B  4 42  A  0  0  4 44  55 4D 50 20 20 52 44 20   [DBJ@@DDUMP  RD
 OK

As can be seen in the hex dump for TESTWORD , its second cell holds a zero. The second cell for the target word LIT holds the address of the original LIT (a word compiled by LITERAL) in the host system.
Code:
HOST ' LIT U. A42  OK
41B >VIRTUAL DIS
 CC1B B104 ,X ORA
 CC1E FUTURE EXPANSION
3
 OK
41B V@ U. 41D  OK
41D >VIRTUAL DIS
 CC1D   FB )Y LDA IP
 CC1F         PHA
 CC20   FB    INC IP
 CC22 CC26    BNE
 CC24   FC    INC IP 1+
 CC26   FB )Y LDA IP
 CC28   FB    INC IP
 CC2A CC2E    BNE
 CC2C   FC    INC IP 1+
 CC2E         DEX
 CC2F         DEX
 CC30    1 ,X STA
 CC32         PLA
 CC33    0 ,X STA
 CC35    1  # LDY
 CC37   FB )Y LDA IP
 CC39   FF    STA  W 1+
 CC3B         DEY
 CC3C   FB )Y LDA IP
 CC3E   FE    STA  W
 CC40         CLC
 CC41   FB    LDA IP
 CC43    2  # ADC
 CC45   FB    STA IP
 CC47 CC4C    BCS
 CC49   FD    JMP  W 1-
 CC4C   FC    INC IP 1+
 CC4E   FD    JMP  W 1-
34
 OK
#1024 THERE OVER -  OK
.S  400   51  OK
. 51  OK
>VIRTUAL 51  OK
.S CC00   51  OK
DUMP
CC00   0  0 88 54 45 53 54 57  4F 52 C4  D  4 B5  0 15   @@.TESTWOR.MD.@U
CC10   1 D0  1 88 60  0  4 83  4C 49 D4 1D  4 B1 FB 48   A.A..@D.LI.]D..H
CC20  E6 FB D0  2 E6 FC B1 FB  E6 FB D0  2 E6 FC CA CA   ...B.......B....
CC30  95  1 68 95  0 A0  1 B1  FB 85 FF 88 B1 FB 85 FE   .A..@ A.........
CC40  18 A5 FB 69  2 85 FB B0   3 4C FD  0 E6 FC 4C FD   X...B...CL.@..L.
CC50   0 85 FF 88 B1 FB 85 FE  18 A5 FB 69  2 85 FB B0   @.......X...B...
 OK
CONSOLE

That's as far as I am in the redesign of Fleet Forth's metacompiler, so that's all for now.


Top
 Profile  
Reply with quote  
PostPosted: Thu Jul 28, 2022 12:07 am 
Offline

Joined: Fri May 05, 2017 9:27 pm
Posts: 895

I did not mention in my last post that the metacompiler's assembler is linked to the host assembler at the host assembler's word NOT . This means that the host assembler words from the first one up to and including NOT are common to both assemblers
Code:
host assembler   target assembler
v----            v----
v----            v----
 ...              ...
v----            v----  \ first word defined in meta assembler
v---- <----------       \ NOT
v----
 ...
v---- \ first word defined in host assembler
0

The first word defined in the metacompiler's assembler will have a link field that points to the link field of the word NOT in the host assembler. In Fleet Forth, a header's link field points to another header's link field.
The search order when assembling to the target is still:
    metacompiler's assembler vocabulary
    target forth vocabulary
    shadow vocabulary
    meta vocabulary
    host (original) Forth vocabulary
Linking the metacompiler's assembler to the host assembler is done to avoid redefining assembler words which are defined EXACTLY the same. The search order is not altered by this because vocabularies in Fleet Forth do not have a false name linking them to a parent vocabulary. In Fleet Forth, the address of the parent vocabulary is stored in the second cell of a vocabulary and (FIND) , the dictionary search primitive, has an outer loop to deal with this.
Here are the words from the host assembler which are shared with the metacompiler's assembler:
Code:
SCR# 4
// OPCODE OFFSET TABLE AND MODES
HEX  VOCABULARY ASSEMBLER
ASSEMBLER DEFINITIONS
CREATE TABLE
   0008 , 0810 , 1404 , 2C14 ,
   1C0C , 0818 , 1000 , 0400 ,
   1414 , 0C2C , 1C1C ,
VARIABLE MODE
: .A   ( -- )   MODE OFF ;
: X)   ( -- )   1 MODE ! ;
: )Y   ( -- )   2 MODE ! ;
: #    ( -- )   3 MODE ! ;
: )    ( -- )   7 MODE ! ;
: MEM  ( -- )   8 MODE ! ;
: ,X   ( -- )   9 MODE ! ;
: ,Y   ( -- )  0A MODE ! ;

SCR# 5
// Z
HEX
: Z  ( OA? ADR -- OA? BOP BMAP )
   COUNT SWAP @
   MODE @ 7 >        0EXIT
   2PICK $100 U<     0EXIT
   1 MODE @ 2- 2-
   LSHIFT  OVER AND  0EXIT
   -4 MODE +!        ;

SCR# 6
// ?EXEC BO BRANCHES NOT
HEX  FORTH DEFINITIONS
: ?EXEC  ( -- )  STATE @
   ABORT" FOR ASSEMBLING" ;
ASSEMBLER DEFINITIONS
: BO  ( DEST SOURCE -- BRANCH.OFFSET )
   1+ - DUP 0< OVER ABS +  7F >
   ABORT" BRANCH RANGE EXCEEDED" ;
 50 CONSTANT VS   // OVERFLOW
 90 CONSTANT CS   // CARRY SET
0D0 CONSTANT 0=   // EQUAL TO ZERO
 10 CONSTANT 0<   // LESS THAN ZERO
 90 CONSTANT >=   // NOT LESS THAN
// >= ONLY CORRECT AFTER SUB, OR CMP
: NOT  ( CC1 -- CC2 )
   20 XOR ;         // REVERSE TEST

An observant reader may have noticed that the metacompiler's assembler does not have the Forth virtual machine constants IP , UP , W , or the scratchpad N , or XSAVE . Nor does it have the constants NEXT , PUT , PUSH and the rest.
This is by design. The location of the virtual machine constants, as well as N and XSAVE are chosen when the new kernel is designed and so are in the kernel source as DEFINE words. Words which are constants in the SHADOW vocabulary.
Code:
// FORTH VIRTUAL MACHINE REGISTERS
 $85 DEFINE N   $8D DEFINE XSAVE
 $8E DEFINE UP  $FB DEFINE IP
 $FE DEFINE W

As for the others, their location is determined by the source code and are set with LABELS . A label is a constant defined in the SHADOW vocabulary. Its value is the address of THERE when the label was created.
Code:
: DEFINE  ( N -- )
   ORDER@
   [SHADOW] SHADOW DEFINITIONS
   CONSTANT ORDER! ;
HOST

: LABEL  ( -- )
   HERE ORDER@
   [SHADOW] SHADOW DEFINITIONS
   THERE CONSTANT
   ORDER! HERE
   SWAP - CDP +! ; IMMEDIATE
HOST

Since a LABEL can be used while assembling or compiling, the manipulation of the variable CDP is so the increase in the size of the host dictionary doesn't cause a "COMPILED TO HOST" error.
Here is the actual source for Fleet Forth's LIT
Code:
CODE LIT
   IP )Y LDA  PHA  IP INC
   0= IF  IP 1+ INC  THEN
   IP )Y LDA
   LABEL 1.IP.+!.PUSH
   IP INC
   0= IF  IP 1+ INC  THEN
   LABEL PUSH
   DEX  DEX
   LABEL PUT
   1 ,X STA  PLA  0 ,X STA
   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

Notice the labels PUSH , PUT , and NEXT .
The use of two jumps at the end of NEXT to reduce a cycle for most cases is an idea from Garth Wilson.

This post explains Fleet Forth's header and vocabulary structure and the following post gives my rationale.

So... Any questions? Suggestions?


Last edited by JimBoyd on Tue Aug 02, 2022 12:25 am, edited 1 time in total.

Top
 Profile  
Reply with quote  
PostPosted: Thu Jul 28, 2022 3:27 pm 
Offline
User avatar

Joined: Sun Jun 30, 2013 10:26 pm
Posts: 1949
Location: Sacramento, CA, USA
JimBoyd wrote:
So... Any questions? Suggestions?

Would a compliment suffice? I'm not yet qualified to offer suggestions, but I admire your productivity and your willingness to share. I read 99% of what you post, and understand a significantly lower percentage of it (my shortcoming, not yours).

_________________
Got a kilobyte lying fallow in your 65xx's memory map? Sprinkle some VTL02C on it and see how it grows on you!

Mike B. (about me) (learning how to github)


Top
 Profile  
Reply with quote  
PostPosted: Tue Aug 02, 2022 2:11 am 
Offline

Joined: Fri May 05, 2017 9:27 pm
Posts: 895

Thank you for the complement.
Please let me know if there is anything I didn't adequately cover. Sometimes it's easy to overlook something important and miss it when proofreading.


Top
 Profile  
Reply with quote  
PostPosted: Tue Aug 02, 2022 2:15 am 
Offline

Joined: Fri May 05, 2017 9:27 pm
Posts: 895

Here are the definitions for ORDER@ and ORDER! used by DEFINE and LABEL .
Code:
: ORDER@  ( A: -- W1 W2 )
   CURRENT @ CONTEXT @  2>A ;
: ORDER!  ( A: W1 W2 -- )
   2A>  CONTEXT ! CURRENT ! ;

They save and restore the search order and compilation vocabulary. Notice that they use the auxiliary stack. If their use is not nested, a double variable could be used.
Here are better definitions for DEFINE and LABEL .
Code:
: DEFINE  ( W -- )
   ORDER@
   [SHADOW] SHADOW DEFINITIONS
   CONSTANT  ORDER! ;
META DEFINITIONS
: LABEL  ( -- )
   ?CDP THERE DEFINE !CDP ;
   IMMEDIATE
HOST

I've already mentioned elsewhere that using labels within a definition is not a problem. The label is defined in the host dictionary while the target is built in virtual memory. This is why labels can be defined as needed.
When testing a kernel word on the host system, labels can not be created in the middle of a word. Here is a version of LABEL which does not create a new word. It resides in the host Forth vocabulary and requires a label to be a VALUE which has already been defined.
Code:
: LABEL  ( -- )
   ORDER@ FORTH // HOST FORTH VOCABULARY
   HERE ' DUP @
   [ ' #BUF @ ] LITERAL <>
   ABORT" NOT A LABEL"
   >BODY !  ORDER! ; IMMEDIATE

Both versions of LABEL exist in the metacompiler. The first version is defined in the META vocabulary and is found when metacompiling. The second is defined in the host FORTH vocabulary and is found when loading a kernel word into the host for testing.

Here are some words to go from one part of a target word's name field in virtual memory to another part.
Code:
: VTRAVERSE  ( VADR DIR -- VADR2 )
   SWAP
   BEGIN
      OVER + $7F OVER VC@ <
   UNTIL  NIP ;
: V>NAME  ( VCFA -- VNFA )
   1- TRUE VTRAVERSE ;
: VNAME>  ( VNFA -- VCFA )
   1 VTRAVERSE 1+ ;
: V>LINK  ( VCFA -- VLFA )
   V>NAME 2- ;
: VLINK>  ( VLFA -- VCFA )
   2+ VNAME> ;
: VN>LINK  ( VNFA -- VLFA )
   2- ;
: VL>NAME  ( VLFA -- VNFA )
   2+ ;
: V>BODY  ( VCFA -- VPFA )
   2+ ;
: VBODY>  ( VPFA -- VCFA )
   2- ;


Some useful aliases defined in the META vocabulary so they will be found while metacompiling.
Code:
META DEFINITIONS
: >NAME   V>NAME ;
: NAME>   VNAME> ;
: >LINK   V>LINK ;
: LINK>   VLINK> ;
: N>LINK   VN>LINK ;
: L>NAME   VL>NAME ;
: >BODY   V>BODY ;
: BODY>   VBODY> ;
: HERE   THERE ;
: ALLOT   VALLOT ;
: C@   VC@ ;     : @   V@ ;
: C!   VC! ;     : !   V! ;
: C,   VC, ;     : ,   V, ;
HOST



Top
 Profile  
Reply with quote  
PostPosted: Wed Aug 03, 2022 8:01 pm 
Offline

Joined: Sun May 13, 2018 5:49 pm
Posts: 255
barrym95838 wrote:
Would a compliment suffice? I'm not yet qualified to offer suggestions, but I admire your productivity and your willingness to share. I read 99% of what you post, and understand a significantly lower percentage of it (my shortcoming, not yours).
I'm with Mike B. on this one. I don't believe there's anything missing or unclear in the descriptions of what is going on, but it's a complex topic that I find interesting and would like to know a little more about (without jumping down the rabbit hole myself). Even when I only understand a fraction of what is in the post, I learn something new or get to think about something new. That's enough to keep me interested in following along to see where things are going, but I'm also not qualified to offer any suggestions.
-SamCoVT
P.S. I like how Mike says he is not "yet" qualified.


Top
 Profile  
Reply with quote  
PostPosted: Sat Aug 06, 2022 2:38 am 
Offline

Joined: Fri May 05, 2017 9:27 pm
Posts: 895

Here's a detail I overlooked in my explanation.
In the target FORTH vocabulary, There are a few words which just return the address in virtual memory of a subroutine for use by some of the target's primitives. Most of the words in the target FORTH vocabulary are CREATE DOES> words. The target under construction in virtual memory can not perform a dictionary search, so these words are 'handles' to the target system's words. Each handle has three cells. The first cell holds the address in virtual memory of the handle's corresponding code field in the target. The second cell holds the address of the target word's counterpart on the host. When the handle is defined, a word with a matching name is sought. If found, the address of its code field is stored, otherwise a zero is stored. The third cell is for statistical data.
When metacompiling, the behavior of the compiler is modified so that when compiling, if a word that is found is a handle, the address from its first cell is fetched and placed into virtual memory with V, , otherwise the search text is passed to NUMBER? .
Any word found when interpreting, regardless of vocabulary, is executed.
When a handle is executed, the value of its second cell is fetched. If this value is zero, an abort occurs with the message "COUNTERPART NOT FOUND". If this value is not zero, it is the address of the counterpart on the host and is executed. This is so that Forth can still be used while interpreting to perform math functions, address calculations, or whatever needs to be done when the kernel source is loaded.
Here is an example of such a use:
Code:
CREATE DPT   #DRIVES
" TARGET 2 C, 1- ?DUP 0=
  HOST >IN !"
COUNT EVALUATE  TARGET

#DRIVES is a DEFINE word. Its value is the number of drives which can be used for block storage. Access for blocks in the range 0 - 4095 are directed to the first drive ( drive 8 ). Access for blocks in the range 4096 to 8191 are directed to the second drive ( drive 9 ) Access for blocks in the range 8192 to 12287 are directed to the third drive, and so on. Each drive sees blocks in the range 0 to 4095. This does not mean that many blocks are available with each drive. Most Commodore drives can't handle that range. To allow different types of drives (since block access directly maps to individual sectors.) there is a drive properties table, DPT . the string
Code:
" TARGET 2 C, 1- ?DUP 0=
  HOST >IN !"

is counted and evaluated once for each drive which is to be used for block access.
The words 2 C, 1- ?DUP and 0= already exist in the target at this point so they have their handles in the target FORTH vocabulary. Since the string is evaluated while interpreting, each handle executes its counterpart. C, is defined in the META vocabulary as an alias for VC, . The others are defined in the host FORTH vocabulary.


Top
 Profile  
Reply with quote  
PostPosted: Thu Aug 25, 2022 2:45 am 
Offline

Joined: Fri May 05, 2017 9:27 pm
Posts: 895

I've changed the name of ?TFIND to ?TARGET .
To avoid writing metacompiler versions of any and all Fleet Forth control flow words, or words using LITERAL , which might be useful in compiling the kernel source, certain key Fleet Forth words are patched by the metacompiler. Fleet Forth is an ITC Forth, so all words have a code field. The code field of a colon definition can be changed to point to low level code. For this reason, the metacompiler version of the patched words all start out as code words. The patched word can be restored by storing the address of do-colon in its code field like so:
Code:
   ' : @       \ colon is itself a colon definition
   ' LITERAL ! \ make LITERAL's code field point
               \ to do-colon (it normally does).

I've also added META? which returns a true flag if metacompiling.
Code:
: META?  ( -- F )
   ['] LITERAL @  [ ' : @ ] LITERAL
   <> ;

The words FIND and , do NOT get patched with MFIND and M, .
Code:
: MFIND  ( ADR1 -- ADR2 F )
   0 OVER FIND DUP STATE @ <>
   2PICK ?TW OR
   IF  2SWAP  THEN
   2DROP ;
: M,  ( CFA -- )
   DUP ?TW ?TARGET
   >BODY  1 OVER  2+ 2+ +!  @ V, ;

MFIND replaces FIND in the first cell of (I/C) and M, replaces , .
The following words do get patched:
Code:
COMPILE
LITERAL
>MARK
<MARK
>RESOLVE
<RESOLVE

And here are their metacompiler counterparts. As I said, they all start out as code words. They transition to high level with >FORTH .
Code:
CODE MCOMPILE  ( -- )
   >FORTH
   ?COMP
   R> DUP 2+ >R @
   >NAME COUNT $1F AND >HERE CLIP
   TFIND ?TARGET M, ;

CODE MLITERAL  ( N -- )
   >FORTH
   DUP SPLIT NIP
   IF
      MCOMPILE LIT  V,
      EXIT
   THEN
   MCOMPILE CLIT  VC, ;

CODE >MMARK  ( -- ADR 1 )
   >FORTH
   THERE 0 V, 1 ;
CODE <MMARK  ( -- ADR 2 )
   >FORTH
   THERE 2 ;
CODE >MRESOLVE  ( ADR 1 -- )
   >FORTH
   1 ?PAIRS  THERE SWAP V! ;
CODE <MRESOLVE  ( ADR 2 -- )
   >FORTH
   2 ?PAIRS V, ;

When metacompiling, MCOMPILE is executed in place of COMPILE . It fetches the address of the next word in the threaded code just like COMPILE . It does not compile the address of this word into virtual memory. The name is copied to HERE and used as a search string to find the corresponding name in the target.
The following source is used to find the location of , in (I/C) and store it on the auxiliary stack.
Code:
' (I/C)
" 2+ DUP @ ' , = >IN !"
COUNT EVALUATE >A

META.ON is the word to patch the key Fleet Forth words.
Code:
: META.ON  ( -- )
   ['] MFIND
   [ ' (I/C) >BODY ] LITERAL !
   ['] M,  [ A@ ] LITERAL !
   ['] MLITERAL @ ['] LITERAL !
   ['] >MMARK @ ['] >MARK !
   ['] <MMARK @ ['] <MARK !
   ['] >MRESOLVE @ ['] >RESOLVE !
   ['] <MRESOLVE @ ['] <RESOLVE !
   ['] MCOMPILE @ ['] COMPILE !
   ['] V," @ ['] ," ! ;

META.OFF restores them.
Code:
: META.OFF  ( -- )
   ['] FIND
   [ ' (I/C) >BODY ] LITERAL !
   ['] ,  [ A> ] LITERAL !
   ['] : @ DUP ['] LITERAL !
           DUP ['] >MARK !
           DUP ['] <MARK !
           DUP ['] >RESOLVE !
           DUP ['] <RESOLVE !
           DUP ['] COMPILE !
               ['] ," ! ;

The word compiled by Fleet Forth's ABORT" executes ABORT . ABORT executes the deferred word ERR , which is normally set to the no-op, NOOP . For now, as a precaution, it's a good idea to set ERR to execute META.OFF . Later, it will be set to M(ERR) which turns metacompiling off and displays the contents of all three of Fleet Forth's stacks.
Code:
: M(ERR)
   META.OFF (ERR) ;

The words RESUME and FINISH have been added. START was redefined to execute RESUME .
Code:
: RESUME
   [COMPILE] TARGET  META.ON
   CR CLEAR.TIME ; IMMEDIATE
: START  ( -- )
   WLINK OFF  (ORIGIN) ON
   HEAD ON  HEADS OFF
   HEADLESS OFF  PNAMES OFF
   [COMPILE] RESUME ; IMMEDIATE
: FINISH
   [COMPILE] HOST [COMPILE] [
   META.OFF
   CR ." ELAPSED TIME" ELAPSED
   CR ." FINISHED" ; IMMEDIATE

With RESUME , metacompiling can resume after it is (temporarily) finished. This was necessary because the source for Fleet Forth's kernel spans more than 165 blocks, the maximum blocks in Fleet Forth, other than block zero, a 1541 disk drive can support.
META-STATUS will now show if metacompiling is on or off.
Code:
: META-STATUS
   SETWIDTH
   CR ." METACOMPILING "  META?
   IF  ." ON"  ELSE  ." OFF"  THEN
   CR ."    STATE: " STATE @ U.
   CR ."    WLINK: " WLINK @ U.
   CR ."     HEAD: " HEAD @ U.
   CR ."    HEADS: " HEADS @ U.
   CR ." HEADLESS: " HEADLESS @ U.
   CR ."   ORIGIN: " (ORIGIN) @ U.
   CR ."    THERE: " TDP @ U.
   CR ."   PADDED: " PNAMES @ U.
   ORDER ;

The metacompiler versions of ' (tick) ['] (bracket tick) and [COMPILE] have the same names because they are meant to be used in the kernel source.
Code:
: '  ( -- N )
   '  META?  0EXIT
   DUP ?TW ?TARGET >BODY @ ;
: [']  ( -- )
   '  [COMPILE] LITERAL ; IMMEDIATE
: [COMPILE]  ( -- )
   ?COMP  ' META?
   IF  V,  EXIT  THEN
   , ; IMMEDIATE

tick executes the original tick and tests for metacompiling. It exits if not metacompiling. If metacompiling, it fetches the virtual memory address of the target word from its handle in the target Forth vocabulary.
The definition of ['] looks just like its counterpart in the host Forth vocabulary, but it uses the new definition of tick.
[COMPILE] also used the new definition of tick. It also checks for metacompiling and either compiles the address returned by tick to virtual memory or the host dictionary.
These three words function identically to their host counterparts when not metacompiling. When metacompiling, they will only work with target words, the 'handles' defined in the target Forth vocabulary.

With these words, it is possible to define metacompiler constants, create labels, and define some primitives. I typed LOGGER to dump everything typed and Forth's responses to a print file.
Code:
 OK
DECIMAL  OK
START
 OK
1024 ORIGIN  OK
META-STATUS
METACOMPILING ON
   STATE: 0
   WLINK: 0
    HEAD: 65535
   HEADS: 0
HEADLESS: 0
  ORIGIN: 1024
   THERE: 1024
  PADDED: 0
CONTEXT: FORTH
         SHADOW
         META
         FORTH
         
CURRENT: FORTH
         SHADOW
         META
         FORTH
         
 OK
2 LOAD  OK
14 23 THRU 14 15 16 17 18 19 20 21
PAGE CROSSING ^^ 507 : (?DO)
PAGE CROSSING ^^ 50D : (?DO)
PAGE CROSSING ^^ 513 : (?DO)
PAGE CROSSING ^^ 515 : (?DO)
22 23  OK

Although the headers for colon definitions still can't be created on the target, their bodies can be.
After some of the primitives were built on the target, I built the following fragments of threaded code to test what I've written so far.
Code:
] BEGIN -1 WHILE -1 AGAIN -1 THEN [  OK
#2048 ORIGIN  OK
] IF -1. ELSE -1. THEN [  OK
] BEGIN -1 WHILE -1 AGAIN -1 THEN [  OK
FINISH
ELAPSED TIME
 00:03:39.8
FINISHED OK
META-STATUS
METACOMPILING OFF
   STATE: 0
   WLINK: 1387
    HEAD: 65535
   HEADS: 0
HEADLESS: 0
  ORIGIN: 1024
   THERE: 2092
  PADDED: 0
CONTEXT: FORTH
         
CURRENT: FORTH

The contents of virtual memory can be examined with VDUMP , defined here.

I'd like to briefly discuss headers. In Fleet Forth, all words which create a header execute CREATE . CREATE builds a header and lays down the code field for VARIABLE . VARIABLE is just:
Code:
: VARIABLE
   CREATE  0 , ;

DOES> and ;CODE compile a word to patch, or replace, the code field of the latest word. This is fairly straight forward and I'm not going to go into depth on it. With the metacompiler, things get a bit more complicated. The address of a variable or the value of a constant might be used while assembling a code word. None of the words in virtual memory can be executed on the host. A variable in the target needs a constant with the same name in the shadow vocabulary which holds the virtual memory address of that variable. A constant needs a constant in the shadow vocabulary which holds the value of that constant. Code words were the easiest to implement in the metacompiler. This is why the metacompiler version of CREATE is not the foundation of all words which create a header. I'm saving the metacompiler's CREATE words, DOES> and ;CODE for later. I'll just say that the complexity of the metacompiler version of these words is one reason I wanted to redesign Fleet Forth's metacompiler.


Top
 Profile  
Reply with quote  
PostPosted: Tue Aug 30, 2022 1:27 am 
Offline

Joined: Fri May 05, 2017 9:27 pm
Posts: 895

Some of the words in Fleet Forth's kernel need to work with the Commodore 64 kernal. Some of these words need to set or read zero page locations used by the C64 kernal. It is good to give these locations a name, but it is wasteful to define constants in Fleet Forth's kernel which will not be used outside the kernel.
The DEFINE constants (defined on the host, but not the target) work fine for code words
Code:
 $85 DEFINE N   $8D DEFINE XSAVE
 $8E DEFINE UP  $FB DEFINE IP
 $FE DEFINE W

The only way to use a DEFINE constant in a high level word would be something like this:
Code:
4 DEFINE #DRIVES


: SOMEWORD
   [ #DRIVES ] LITERAL


The metacompiler word MACRO was added to make the source for Fleet Forth's kernel easier on the eyes. Macros can be used in a code word or a high level word. A metacompiler macro is just an immediate word with a built in string which is evaluated when the macro is executed.
Code:
: MACRO  ( ADR CNT -- )
   CREATE IMMEDIATE
   >HERE C@ 1+ ALLOT
   [ HERE >A ]
   DOES>
   RP@ $11F <
   ABORT" RECURSIVE ERROR"
   COUNT EVALUATE ;
A> 2+ CONSTANT MACRO-CF
META DEFINITIONS
: MACRO  ( ADR CNT -- )
   ORDER@
   [SHADOW] SHADOW DEFINITIONS
   [HOST] MACRO ORDER! ;
HOST

Here are some macros used in the source for Fleet Forth's kernel.
Code:
" $98"  COUNT MACRO #OPEN.FILES
" $99"  COUNT MACRO INPUT
" $C6"  COUNT MACRO #KBD
" $C7"  COUNT MACRO REV
" $CC"  COUNT MACRO BLINK.ENABLE
" $CD"  COUNT MACRO BLINK.TIMER
" $CF"  COUNT MACRO BLINK.ON?
" $D3"  COUNT MACRO CURSOR.COL
" $D4"  COUNT MACRO QUOTE.MODE
" $258" COUNT MACRO LFN-1
" $277" COUNT MACRO KBD.BUFFER
" $292" COUNT MACRO AUTO.SCROLL.DN

Here is a word to save a section of Commodore 64 memory to a disk as a program.
Code:
: TSAVE  ( -- )
   CMD  CR ." FILENAME? "
   PAD 16 EXPECT  " ,P,W" COUNT
   PAD SPAN @ + SWAP CMOVE
   (ORIGIN) @ THERE PAD SPAN @ 2+ 2+
   VMSAVE
   ?DISK  CLOSE ;

VMSAVE is defined with Fleet Forth's virtual memory words.
Next time I'll present the metacompiler's versions of IS and TO . I've already written them. They are not the same as the original metacompiler versions and I still need to test them.


Top
 Profile  
Reply with quote  
PostPosted: Sat Sep 03, 2022 1:44 am 
Offline

Joined: Fri May 05, 2017 9:27 pm
Posts: 895

Here are the metacompiler versions of IS TO and RECURSE . As with ' (tick) ['] and [COMPILE] , they replace the originals on the host. Each one is written so that when metacompiling is off it exhibits the behavior of the word it replaced, otherwise it exhibits its metacompiler behavior.
I could have defined the new versions of these words in the META vocabulary and defined them to only exhibit the metacompiling behavior. The META vocabulary would be searched before the host FORTH vocabulary when metacompiling. I did exactly that when I wrote the metacompiler I currently use. I wasn't exactly pleased with the results, which is why I'm doing it differently for this metacompiler.
Code:
: RECURSE  ( -- )
   ?COMP  META?
   ?BRANCH [ ' RECURSE >BODY , ]
   LAST >BODY @ V, ; IMMEDIATE
: IS  ( -- )     // COMPILING
      ( N -- )   // INTERPRETING
   META?
   ?BRANCH [ ' IS >BODY , ]
   '
   STATE @
   IF
      MCOMPILE (IS) V,  EXIT
   THEN
   >BODY V! ; IMMEDIATE
: TO  ( -- )     // COMPILING
      ( N -- )   // INTERPRETING
   META?
   ?BRANCH [ ' TO >BODY , ]
   [COMPILE] IS ; IMMEDIATE

In these three words I've used a control structure which may seem unorthodox. Each of these words tests if metacompiling is on with META? . If metacompiling is off, it branches to the word it replaces.
BRANCH and ?BRANCH are in the Forth-83 Standard and they are not immediate.

I've simplified the word M, by factoring out the code which counts how many times a word is used in the new kernel. This data is stored in the third cell of the TARGET word 'handle' in the host system's TARGET vocabulary. By placing this new word, ?TCOMP in the metacompiler's version of ' (tick) and the metacompiler words M, and MCOMPILE , I hope to obtain a more accurate count of word usage.
Code:
: ?TCOMP  ( CFA -- )
   DUP ?TW ?TARGET
   >BODY 2+ 2+ 1 SWAP +! ;

: M,  ( CFA -- )
   DUP ?TCOMP
   >BODY @ V, ;

Note that if the CFA passed to ?TCOMP is not for a TARGET word, it will abort with the message "NOT IN TARGET".

Here is an excerpt from the last use of my current metacompiler.
Code:
(+LOOP)          B86:   2
LIT              B6C:  14
EXIT             B64:  8E
LEAVE            B5B:   0
(?DO)            B3D:   B
(DO)             B0B:   3
?BRANCH          ADD:  1C
2DROP            AC6:   3
(LOOP)           A82:   C

The first number after the name is the word's CFA in the new kernel. The second number is (or should be) the number of times this word was compiled in the new kernel.


Top
 Profile  
Reply with quote  
PostPosted: Sat Sep 03, 2022 2:46 am 
Offline
User avatar

Joined: Fri Aug 30, 2002 1:09 am
Posts: 8545
Location: Southern California
Obviously you know your FleetForth extremely well, far beyond what any casual observer can follow. What do you use it for? There must be applications, at least planned if not in process already, and perhaps already completed ones, motivating this work.

_________________
http://WilsonMinesCo.com/ lots of 6502 resources
The "second front page" is http://wilsonminesco.com/links.html .
What's an additional VIA among friends, anyhow?


Top
 Profile  
Reply with quote  
PostPosted: Sun Sep 04, 2022 7:16 pm 
Offline

Joined: Fri May 05, 2017 9:27 pm
Posts: 895

I don't have anything concrete planned. The Commodore 64 I'm using isn't even real. I run VICE on my desktop and it's just a simulation without the ability to connect actual hardware to the C64. Back when I had a real C64, I would build circuits I could connect to the user port and control with Forth. Someday I'd like to be able to use a small computer programmed in Forth to experiment in robotics and generally have fun controlling home brew devices. Maybe one day I'll build a device around the 65C02 or 65C816. I'd have to change Fleet Forth to port it. Although I have a background in electronics, that was in the past and all I have these days is an old soldering iron, a logic probe, and a DMM. From a financial perspective, any plans to build any electronic device will have to wait.
As for why I keep working on Fleet Forth:
I could say I do it for the nostalgia, which is true.
I could say it's good cerebral exercise, also true.
I could even say I like to explore programming ideas such as the virtually parallel machine architecture used by New Micro's MaxForth or non deterministic operations or whatever other interesting idea I run across.
It is a much needed creative outlet that helps take my mind off how lonely these past seventeen years have been.

I also hope someone will actually get some use out of this. Besides, it's fun.


Top
 Profile  
Reply with quote  
PostPosted: Tue Sep 13, 2022 2:12 am 
Offline

Joined: Fri May 05, 2017 9:27 pm
Posts: 895
GARTHWILSON wrote:
Obviously you know your FleetForth extremely well, far beyond what any casual observer can follow. What do you use it for? There must be applications, at least planned if not in process already, and perhaps already completed ones, motivating this work.


I'd like to add that, in my opinion, it has been easier to make modifications to Fleet Forth because I build the kernel with a metacompiler. If I want to test a change to how a word is implemented, I can develop and test it on the host. After the testing, I don't have to translate the source into something which will work with a traditional assembler. So, not as much work has been put into it compared to making all these changes and reassembling the kernel. I also admit that I do like tinkering on it.
Since I wrote the metacompiler, any problems with the metacompiler which arise will just motivate me to fix them.
And no, I'm not redesigning the metacompiler because of problems with it. I'm trying to make it easier to extend in the direction of target compilation. I don't know if I will actually extend it once it has been redesigned, but it might be interesting to be able to metacompile an entire application rather than just the kernel. Even if the Forth interpreter were still used by the application as a user interface, any words not needed by the end user could be headerless. Also, any words which don't get used at all could be eliminated. Just food for thought.


Top
 Profile  
Reply with quote  
PostPosted: Tue Sep 13, 2022 3:43 am 
Offline
User avatar

Joined: Fri Aug 30, 2002 1:09 am
Posts: 8545
Location: Southern California
My introduction to 6502 Forth was with a metacompiler that I have not used in years and will not use again because of its bugs, from a company whose name I'll disguise here so the search-engine crawlers won't find it: Labber at or rhee My crow cyst emz ink, usually abbreviated with three letters. As the source code got longer and longer, the metacompiler's bugs, which were initially just little pot holes, gradually turned into sink holes, and I had to pick through the hex machine code it produced to figure out where things went wrong, and then enter raw machine code at various places in the source code to get it to take it. What a headache. The writer, whom I won't name here, retired long ago. He had a Forth that ran on PCs which was apparently really good, whose name sounds exactly like "You are 4th." My employer bought me that, too, but I never really used it, so I can only go on the report of another user I've had a lot of communication with. He spoke very highly of it.

The workbench computer can compile high-level Forth and assemble assembly-language source code though, so I can develop right on the target, interactively, and I have not modified the portion of the Forth that's in ROM in 23 years (although I have refreshed the EPROM to make sure it doesn't gradually lose its information). Every application I run is one I load in by text source code.

_________________
http://WilsonMinesCo.com/ lots of 6502 resources
The "second front page" is http://wilsonminesco.com/links.html .
What's an additional VIA among friends, anyhow?


Top
 Profile  
Reply with quote  
PostPosted: Sat Sep 17, 2022 2:41 am 
Offline

Joined: Fri May 05, 2017 9:27 pm
Posts: 895
GARTHWILSON wrote:
My introduction to 6502 Forth was with a metacompiler that I have not used in years and will not use again because of its bugs


One more reason my metacompiler is completely open, and why I'm trying to simplify it.

GARTHWILSON wrote:

The workbench computer can compile high-level Forth and assemble assembly-language source code though, so I can develop right on the target, interactively, and I have not modified the portion of the Forth that's in ROM in 23 years (although I have refreshed the EPROM to make sure it doesn't gradually lose its information). Every application I run is one I load in by text source code.


I like having a complete Forth system and only build Fleet Forth's kernel with the metacompiler, which gets saved to a disk (or rather a disk image since I'm using a simulation of a C64). The new kernel is used to load the rest of the system from blocks on a disk.
I mentioned extending the metacompiler as a possibility. Some people think it would be good to build an application without any unneeded words and without headers.
What I'm trying to do is make it easier to add new CREATE DOES> or CREATE ;CODE words to the kernel. I don't need any new ones now, but I remember when I added the word SARRAY to the kernel. The use of string arrays made it possible to write a version of IOERR which was so much smaller that it more than made up for the memory used by SARRAY .
When I added SARRAY to the kernel, I had to first extend the metacompiler to include support for it.


Top
 Profile  
Reply with quote  
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 51 posts ]  Go to page 1, 2, 3, 4  Next

All times are UTC


Who is online

Users browsing this forum: No registered users and 7 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to: