Jump to content
IGNORED

fbForth—TI Forth with File-based Block I/O [Post #1 UPDATED: 06/09/2023]


Lee Stewart

Recommended Posts

10 hours ago, TheBF said:

I took a look at the TF loader. Are these object files relocatable?

I think I get how Mark's loader works, but I don't understand how it would relocate.

(I have some ideas on how to do the loading with my favourite /STRING word.) :) 

 

They are not relocatable. Implementing relocatable code is a good bit more complicated. The only tags implemented are those associated with

  • AORG.................9
  • DATA.................B
  • BYTE.................B
  • BSS..................B
  • DEF..................6
  • <checksum>...........7—the checksum itself is ignored
  • <end-of-file text>...:

 

All other tagged words are ignored.

 

...lee

  • Like 2
Link to comment
Share on other sites

52 minutes ago, Lee Stewart said:

 

They are not relocatable. Implementing relocatable code is a good bit more complicated. The only tags implemented are those associated with

  • AORG.................9
  • DATA.................B
  • BYTE.................B
  • BSS..................B
  • DEF..................6
  • <checksum>...........7—the checksum itself is ignored
  • <end-of-file text>...:

 

All other tagged words are ignored.

 

...lee

OK good to know.

I started studying this tag meanings in the E/A manual and made a rather large case statement.

I will prune it with your information.

 

To further check my assumptions, would a workable strategy be to load the object code into the dictionary and but do some computation on the addresses so they are correct for the location you put them at?

The objective would be to allow the Forth system to take code that was assembled for ORG = X   but re-jig it so it can load at HERE but re-compute the all the addresses to be HERE relative.

 

It would give Forth the ability to use external code modules. :)

 

  • Like 2
Link to comment
Share on other sites

4 hours ago, TheBF said:

The objective would be to allow the Forth system to take code that was assembled for ORG = X   but re-jig it so it can load at HERE but re-compute the all the addresses to be HERE relative.

 

Your loader would need to be able to understand all instructions with address references—possible, but complicated, with branch statements and statements that use symbolic address references, but I do not think possible with other uses of address labels.

 

The only reason relocatable object code can be managed (and fairly easily, at that) is that the assembler marks all relocatable addresses in the tagged object code with segment addresses and offsets in a linked chain for each unique, relocatable address reference. The loader merely needs to walk each of those chains backwards to replace the segment+offset with the relocated addresses.

 

For REF, prior loading of tagged object code containing the relevant DEF labels (per @Willsy’s loader) would provide the necessary variable definitions with the relevant addresses.

 

Regarding using DEF and REF the way I implied in my earliest post on this topic, DEF would need to define the relevant word to contain the address of the DEFed label rather than the data at that address. I suppose you could flag the loader to manage DEFs as EXECUTE objects (CFAs per @Willsy’s loader) or direct branches (BL, BLWP) that would return where they left. @Willsy’s use of CFAs is probably wisest because it makes the code part of Forth. The only down side to this is that you must have the original ALC, which must be modified to have DEFed labels contain the address of the executable code rather than its own address and the return changed to B *NEXT to get back to the Forth environment.

 

I am sure I have oversimplified (misconstrued?) some of the above, but it could be a fun project. At the very least, these musings provide something of a springboard for going forward,

 

...lee

  • Like 1
  • Thanks 1
Link to comment
Share on other sites

Yes I came to that conclusion too, that I would need to look ahead at some instructions to find B and BL at a minimum to recompute those addresses.

 

Now that I have slightly better understanding I find myself wondering if the REF/DEF stuff could be done with a vocabulary for all DEFs.

When you encounter a 6 tag you: 

1. Extract the name from the object code

2. Search the DEF vocabulary for the tag..

3. If found it means there is already a reference to this code so take the address of that reference and patch it into the address of this new DEF. 

 

Not sure I am getting this yet. :)  That logic might be faulty.

 

Alternatively a DEF vocabulary does give you a linked list of all the names that you can walk and do the relocation updates. Maybe? 

 

I think it would easier if the TI assembler used more of those tags to give us more context.

 

  • Like 1
Link to comment
Share on other sites

20 hours ago, TheBF said:

I took a look at the TF loader. Are these object files relocatable?

I think I get how Mark's loader works, but I don't understand how it would relocate.

(I have some ideas on how to do the loading with my favourite /STRING word.) :) 

Relocatable is the desired feature, yes. 
 

For symbols within the object file, there is a tag that means “add the base address to me”. 
 

Bonus features:

 

1. Create constants on the dictionary for each DEF table entry. Then caller says

 

[ THESYM ] BLWP,

 

(I am not familiar with the forth assembler) 

 

2. Resolve REF table entries by looking up constants

 

  • Like 1
Link to comment
Share on other sites

I took a run at this with the CAMEL Forth code.

Below is the logic used to deal with DEF/REF resolution.  I used a vocabulary 

 

I init the memory space to >FFFF and I stopped setting the tag 6 entries to zero.

I use that >FFFF to determine if the address has been resolved. I guess I assumed that DATA and BYTE statements will not init to >FFFF so that's flawed.

 

The ANS Forth search order control is handy with the PREVIOUS word.

 

This code does what I expect with the test object file. Do you think this close to what is required?


: DEF/REF ( addr len -- )
        PARSE# >R         ( -- addr' len') ( r: -- ref_addr)
        ALSO REFS DEFINITIONS
        /TAG 6 CHOP -TRAILING FIND-NAME ( -- nfa)
        ?DUP
        IF  ( Reference found)
           R@  @ TRUE =   \ fetch the ref_addr to see if UN-resolved
           IF  ( empty reference )
                NFA>BODY @  R>  !       \ store NEW address
           ELSE
                R> DROP   DROP
           THEN
        ELSE ( new reference)
           HEADER,  COMPILE DOCON R> ,  \ make a Forth Constant
        THEN
        PREVIOUS DEFINITIONS
;

It also means I can do this: 

\ create some external system references
ALSO REFS DEFINITIONS
HEX
8300 CONSTANT PAD
83E0 CONSTANT GPLWS
8400 CONSTANT SOUND
8800 CONSTANT VDPRD
8802 CONSTANT VDPSTA
8C00 CONSTANT VDPWD
9000 CONSTANT SPCHRD
9400 CONSTANT SPCHWT
9800 CONSTANT GRMRD
9802 CONSTANT GRMRA
9C00 CONSTANT GRMWD
9C02 CONSTANT GRMWA
000E CONSTANT SCAN   \ key scan entry
0020 CONSTANT BREAK  \ break key sub-routine

DEAD CONSTANT KSCAN  \ dummies for testing DSK2.TEST-OBJ
BEEF CONSTANT VBLANK
AABB CONSTANT KSTAT

PREVIOUS DEFINITIONS
Spoiler

.( EA3 object file loader Aug 7 2021 Fox)

NEEDS WORDLIST FROM DSK1.WORDLISTS

ONLY FORTH ALSO DEFINITIONS
NEEDS .S        FROM DSK1.TOOLS
NEEDS +TO       FROM DSK1.VALUES
NEEDS CASE      FROM DSK1.CASE
NEEDS -TRAILING FROM DSK1.TRAILING
NEEDS READ-FILE FROM DSK1.ANSFILES
NEEDS S=        FROM DSK1.COMPARE

VOCABULARY REFS

FORTH DEFINITIONS
DECIMAL
0 VALUE #1  \ a file handle

: NFA>BODY ( addr -- addr')  NFA>CFA >BODY ;
: 2OVER    ( a b c d -- a b c d a b) 3 PICK  3 PICK ;
: 2NIP     ( a b c -- c)  NIP NIP ;

: FIND-NAME ( addr len -- nfa ) \ nfa is "name field address"
           CONTEXT @ @  ( -- NFA )
           BEGIN DUP
           WHILE ( tos<>0)
              DUP 1+ 2OVER S=
           WHILE ( compare<>0)
              NFA>LFA @   ( follow link to next name)
           REPEAT
           THEN 2NIP  ;

\ heap memory management
: HEAP! ( addr -- ) H ! ;  \ set heap pointer
: HEAP   ( -- addr) H @ ;  \ current heap pointer
: HALLOT ( n -- )  H +! ;  \ move heap pointer
: HEAP,  ( n -- )  HEAP ! 2 HALLOT ; \ compile n into heap

HEX
: NEW.   2000 HEAP!  HEAP 2000 FF FILL ;

\ string utilities
: CHOP   ( addr len n --  addr' len' addr2 len2 )
          >R                  \ Rpush n
          2DUP DROP R@        \ dup $, do left$
          2SWAP               \ put original $ on top
          R> 1- /STRING       \ cut remainder string, leave tag at front
          2SWAP               \ put chopped string (output) on top
;

: /TAG     ( addr len -- addr' len') 1 /STRING ; \ cut tag character

: PARSE# ( addr len -- n )
        BASE @ >R
        HEX /TAG  4 CHOP NUMBER? ABORT" Bad number"
        R> BASE ! ;

: DEF/REF ( addr len -- )
        PARSE# >R         ( -- addr' len') ( r: -- ref_addr)
        ALSO REFS DEFINITIONS
        /TAG 6 CHOP -TRAILING FIND-NAME ( -- nfa)
        ?DUP
        IF  ( Reference found)
           R@  @ TRUE =   \ fetch the ref_addr to see if UN-resolved
           IF  ( empty reference )
                NFA>BODY @  R>  !       \ store NEW address
           ELSE
                R> DROP   DROP
           THEN
        ELSE ( new reference)
           HEADER,  COMPILE DOCON R> ,  \ make a Forth Constant
        THEN
        PREVIOUS DEFINITIONS
;

VARIABLE PROGLENGTH
CREATE PROGNAME  10 ALLOT

: PROG-ID  ( addr len -- addr len)
          PARSE# PROGLENGTH !
          8 CHOP  PROGNAME PLACE ;

: .TOOLVER  ( addr len -- addr 0)
          /TAG  40 CHOP -TRAILING CR TYPE  DROP 0 ;

: ParseLine ( add len -- )
      BEGIN
        DUP ( len<>0)
      WHILE
        OVER C@ ( 1stChar)
        CASE
          [CHAR] 0 OF  PROG-ID        ENDOF
          [CHAR] 6 OF  DEF/REF        ENDOF
          [CHAR] 7 OF  DROP 0         ENDOF
          [CHAR] 9 OF  PARSE# HEAP!   ENDOF
          [CHAR] B OF  PARSE# HEAP,   ENDOF
          [CHAR] : OF  .TOOLVER       ENDOF
        ENDCASE
        1 /STRING 0 MAX   \ advance to next char
     REPEAT
     2DROP ;

: ?PATH ( addr len -- addr len)
       2DUP [CHAR] . SCAN NIP 0= ABORT" Path expected" ;

DECIMAL
: EA3LOAD ( "DSKx.FILE" -- )
      ?PATH DV80 R/O OPEN-FILE ?FILERR  TO #1
      NEW.
      BEGIN
         #1 EOF
      0= WHILE
         PAD DUP 80 #1 READ-LINE ( pad len ? ior) ?FILERR  DROP
       ( pad len ) ParseLine
      REPEAT
      #1 CLOSE-FILE ABORT" CLOSE error"
;

\ create some external system references
ALSO REFS DEFINITIONS
HEX
8300 CONSTANT PAD
83E0 CONSTANT GPLWS
8400 CONSTANT SOUND
8800 CONSTANT VDPRD
8802 CONSTANT VDPSTA
8C00 CONSTANT VDPWD
9000 CONSTANT SPCHRD
9400 CONSTANT SPCHWT
9800 CONSTANT GRMRD
9802 CONSTANT GRMRA
9C00 CONSTANT GRMWD
9C02 CONSTANT GRMWA
000E CONSTANT SCAN   \ key scan entry
0020 CONSTANT BREAK  \ break key sub-routine

DEAD CONSTANT KSCAN  \ dummies for testing DSK2.TEST-OBJ
BEEF CONSTANT VBLANK
AABB CONSTANT KSTAT

PREVIOUS DEFINITIONS
.( Usage: S" DSKx.FILENAME" EA3LOAD)

 

 

  • Like 1
Link to comment
Share on other sites

3 minutes ago, FarmerPotato said:

Relocatable is the desired feature, yes. 
 

For symbols within the object file, there is a tag that means “add the base address to me”. 
 

Bonus features:

 

1. Create constants on the dictionary for each DEF table entry. Then caller says

 

[ THESYM ] BLWP,

 

(I am not familiar with the forth assembler) 

 

2. Resolve REF table entries by looking up constants

 

The version I posted here is maybe close.

It does have a lot of what you want.

 

The references are in a separate vocabulary.

I need to learn more about that other tag. Is it supported in the Assembler?

Can you Assemble your routines into an object file and posted it or PM it to me?

Calling is pretty simple if you never want to come back.

 

MYREF @@ B,  

If they are sub-routines end them with B *R11.

Call from FbForth with:

 

ASM: NEWORD     MYREF @@ BL,   ;ASM

 

  • Like 1
Link to comment
Share on other sites

1 hour ago, TheBF said:

\ create some external system references 
ALSO REFS DEFINITIONS
HEX 
8300 CONSTANT PAD 
83E0 CONSTANT GPLWS
\ ...

 

 

You should not need to anticipate these references. Simply include them as EQUates and, if they are used, they will appear tagged with ‘6’ at the end of the tagged object file and will be created by your loader’s code.

 

...lee

Link to comment
Share on other sites

17 minutes ago, Lee Stewart said:

 

You should not need to anticipate these references. Simply include them as EQUates and, if they are used, they will appear tagged with ‘6’ at the end of the tagged object file and will be created by your loader’s code.

 

...lee

Ok. So they would come along for the ride if the program uses them. That's easier.

 

If you get  a minute, do you think the logic in that DEF/REF word looks correct?

I am out of my depth on how these things actually work. 

 

Link to comment
Share on other sites

Ok. We can shuffle along together then. :)

So one thing you could do better than me by far is provide some normal ALC code assembled to obj file.

If you already have some code that consists of a few sub-routines we should be able to figure out how well these ideas work to make callable words from normal ALC code.

Then whatever we get working we can port to both systems.

The code will diverge in file words and dynamic word creation but the other stuff can be quite similar I think.

 

It's always been a weakness of Forth that it doesn't play nice in the sandbox with other languages so this might be a way to fix that.

In theory we might even be able to take GCC output, if it can generate TI object code.

 

  • Like 2
Link to comment
Share on other sites

14 hours ago, TheBF said:

Ok. We can shuffle along together then. :)

 

The attached ALC from Thierry Nouspikel’s disassembly of the Editor/Assembler utilities may aid in our effort:

 

EditorAssemblerLoMemUtilities_Nouspikel.a99

 

I changed all register references from numbers to ‘R’ notation. Hopefully, I got them all without screwing up non-register numbers.

 

The loader starts at A23BA. The tag jump table is near the end at A2662. You probably guessed correctly that the labels are the actual addresses of the assembled code with a prefix of ‘A’.

 

...lee

  • Like 1
Link to comment
Share on other sites

1 minute ago, Lee Stewart said:

 

The attached ALC from Thierry Nouspikel’s disassembly of the Editor/Assembler utilities may aid in our effort:

 

EditorAssemblerLoMemUtilities_Nouspikel.a99 21.57 kB · 1 download

 

I changed all register references from numbers to ‘R’ notation. Hopefully, I got them all without screwing up non-register numbers.

 

The loader starts at A23BA. The tag jump table is near the end at A2662. You probably guessed correctly that the labels are the actual addresses of the assembled code with a prefix of ‘A’.

 

...lee

Thank you. This will be just what I needed to get some corner cases.

 

I am just writing up a test I did with a tiny program found on the Assembly topic by mathew180.

I am making progress. :)

 

  • Like 1
Link to comment
Share on other sites

TI 99 Object code load and run from Forth.

 

With @mathew180 's little training program plus a couple of lines of code the loader works.

We need AORG >2000   because Forth takes offense if we load code on top of it. :) 

And to return to Forth we just B *R10. 

We can do this because CAMEL99 does not use R0,R1,R2 or R3.

 

* Training program by @mathew180
        AORG >2000
        
        DEF  START

* VDP Memory Map
*
VDPRD   EQU  >8800       * VDP read data
VDPSTA  EQU  >8802       * VDP status
VDPWD   EQU  >8C00       * VDP write data
VDPWA   EQU  >8C02       * VDP set read/write address

* Workspace
WRKSP   EQU  >8300       * Workspace
R0LB    EQU  WRKSP+1     * R0 low byte reqd for VDP routines

* Program execution starts here
START   LIMI 0
*        LWPI WRKSP
        CLR  R0                * Set the VDP address to zero
        MOVB @R0LB,@VDPWA      * Send low byte of VDP RAM write address
        ORI  R0,>4000          * Set read/write bits 14 and 15 to write (01)
        MOVB R0,@VDPWA         * Send high byte of VDP RAM write address

        LI   R1,>2000          * Set high byte to 32 (>20)
        LI   R2,768            * Set every screen tile name to >20
CLS     MOVB R1,@VDPWD    * Write byte to VDP RAM
        DEC  R2
        JNE  CLS
        B    *R10              * return to Forth

        END

The DEF START lines creates the Forth word START . It is put into a separate name space called REFS just for assembly language labels. (Maybe that should be called DEFS ?) 

 

To run START we wrap in a Forth Code definition:

ALSO ASSEMBLER ALSO REFS   ( expose the name spaces to Forth)

CODE  CLEAR     START @@ B,   ENDCODE 

 

 

 

 

  • Like 1
Link to comment
Share on other sites

Lee,

 

Your code assembled and the loader seems to have loaded it.

I looked a the table at the upper end of low ram and it looks correct.

I removed the extra logic that I put in yesterday in the DEF/REF word.

I will address that when something stops working. 

 

So we can do AORG >2000 programs or AORG >E000 for short programs.

In we invoke SAMS memory we could put a lot of CODE in low RAM and make the Forth wrapper do the page selection before calling it.

 

Spoiler has the working version which includes the assembler now as well.

Spoiler

CR .( EA3 object file loader Aug 7 2021 Fox)

NEEDS WORDLIST FROM DSK1.WORDLISTS

VOCABULARY REFS
VOCABULARY ASSEMBLER

ONLY FORTH DEFINITIONS
NEEDS .S        FROM DSK1.TOOLS
NEEDS +TO       FROM DSK1.VALUES
NEEDS CASE      FROM DSK1.CASE
NEEDS -TRAILING FROM DSK1.TRAILING
NEEDS READ-FILE FROM DSK1.ANSFILES
NEEDS S=        FROM DSK1.COMPARE


ALSO ASSEMBLER DEFINITIONS
INCLUDE DSK1.ASM9900


ONLY FORTH DEFINITIONS
DECIMAL
0 VALUE #1  \ a file handle

: NFA>BODY ( addr -- addr')  NFA>CFA >BODY ;
: 2OVER    ( a b c d -- a b c d a b) 3 PICK  3 PICK ;
: 2NIP     ( a b c -- c)  NIP NIP ;

: FIND-NAME ( addr len -- nfa ) \ nfa is "name field address"
           CONTEXT @ @  ( -- NFA )
           BEGIN DUP
           WHILE ( tos<>0)
              DUP 1+ 2OVER S=
           WHILE ( compare<>0)
              NFA>LFA @   ( follow link to next name)
           REPEAT
           THEN 2NIP  ;

\ heap memory management
: HEAP! ( addr -- ) H ! ;  \ set heap pointer
: HEAP   ( -- addr) H @ ;  \ current heap pointer
: HALLOT ( n -- )  H +! ;  \ move heap pointer
: HEAP,  ( n -- )  HEAP ! 2 HALLOT ; \ compile n into heap

HEX
: NEW.   2000 HEAP!  HEAP 2000 FF FILL ;

\ string utilities
: CHOP   ( addr len n --  addr' len' addr2 len2 )
          >R                  \ Rpush n
          2DUP DROP R@        \ dup $, do left$
          2SWAP               \ put original $ on top
          R> 1- /STRING       \ cut remainder string, leave tag at front
          2SWAP               \ put chopped string (output) on top
;

: /TAG     ( addr len -- addr' len') 1 /STRING ; \ cut tag character

: PARSE# ( addr len -- n )
        BASE @ >R
        HEX /TAG  4 CHOP NUMBER? ABORT" Bad number"
        R> BASE ! ;

: DEF/REF ( addr len -- )
        PARSE# >R         ( -- addr' len') ( r: -- ref_addr)
        REFS DEFINITIONS
        /TAG 6 CHOP 2DUP CR ." DEF: " TYPE  -TRAILING
        HEADER,  COMPILE DOCON R> ,  \ make a Forth Constant
        FORTH DEFINITIONS
;

VARIABLE PROGLENGTH
CREATE PROGNAME  10 ALLOT

: PROG-ID  ( addr len -- addr len)
          PARSE# PROGLENGTH !
          8 CHOP  PROGNAME PLACE ;

: .TOOLVER  ( addr len -- addr 0)
          /TAG  40 CHOP -TRAILING CR TYPE  DROP 0 ;

: ParseLine ( add len -- )
      BEGIN
        DUP ( len<>0)
      WHILE
        OVER C@ ( 1stChar)
        CASE
          [CHAR] 0 OF  PROG-ID        ENDOF
          [CHAR] 6 OF  DEF/REF        ENDOF
          [CHAR] 7 OF  DROP 0         ENDOF
          [CHAR] 9 OF  PARSE# HEAP!   ENDOF
          [CHAR] B OF  PARSE# HEAP,   ENDOF
          [CHAR] : OF  .TOOLVER       ENDOF
        ENDCASE
        1 /STRING 0 MAX   \ advance to next char
     REPEAT
     2DROP ;

: ?PATH ( addr len -- addr len)
       2DUP [CHAR] . SCAN NIP 0= ABORT" Path expected" ;

DECIMAL
: DIS/FIX    DISPLAY SEQUENTIAL 80 FIXED ; \ TI ASM object file format

: EA3LOAD ( "DSKx.FILE" -- )
      ?PATH DIS/FIX  R/O OPEN-FILE ?FILERR  TO #1
      NEW.
      BEGIN
         #1 EOF
      0= WHILE
         PAD DUP 80 #1 READ-LINE ( pad len ? ior) ?FILERR  DROP
       ( pad len ) ParseLine
      REPEAT
      #1 CLOSE-FILE ABORT" CLOSE error"
;

.( Usage: S" DSK?.FILENAME" EA3LOAD)

 

 

 

image.thumb.png.651dc866ce4b819015eb918b4110505c.png

  • Like 1
Link to comment
Share on other sites

  • 3 weeks later...
  • 2 months later...

While attempting an fbForth port of @TheBF’s Camel99 Forth code for installing the KONAMI Game Font, I realized that DATA[ does not handle line comments ( \ ), which probably means that I implemented DATA[ before implementing \ —oh, well. I will implement it in fbForth 2.0:14, but I am not sure that will be anytime soon. Right now we need to stick with only using ( and --> between DATA[ and ]DATA words.

 

...lee

  • Like 2
Link to comment
Share on other sites

50 minutes ago, Lee Stewart said:

While attempting an fbForth port of @TheBF’s Camel99 Forth code for installing the KONAMI Game Font, I realized that DATA[ does not handle line comments ( \ ), which probably means that I implemented DATA[ before implementing \ —oh, well. I will implement it in fbForth 2.0:14, but I am not sure that will be anytime soon. Right now we need to stick with only using ( and --> between DATA[ and ]DATA words.

 

...lee

Yes I had a similar issue in early versions so then I kind of cheated by resorting to EVALUATE. :) 

 

Could you make an equivalent with to my code below with:

ASCII , WORD  INTERPRET

HEX
: BYTE ( -- )
         BEGIN
           [CHAR] , PARSE-WORD  DUP
         WHILE
            EVALUATE  DUP FF00 AND  ABORT" Not a byte"
            C,
         REPEAT
         2DROP ;

: DATA ( -- )
         BEGIN
            [CHAR] , PARSE-WORD  DUP
         WHILE
            EVALUATE ,
         REPEAT
         2DROP ;

 

  • Like 1
Link to comment
Share on other sites

  • 4 weeks later...
On 11/20/2021 at 1:41 PM, TheBF said:

Yes I had a similar issue in early versions so then I kind of cheated by resorting to EVALUATE. :) 

 

Could you make an equivalent with to my code below with:


ASCII , WORD  INTERPRET
Spoiler


HEX
: BYTE ( -- )
         BEGIN
           [CHAR] , PARSE-WORD  DUP
         WHILE
            EVALUATE  DUP FF00 AND  ABORT" Not a byte"
            C,
         REPEAT
         2DROP ;

: DATA ( -- )
         BEGIN
            [CHAR] , PARSE-WORD  DUP
         WHILE
            EVALUATE ,
         REPEAT
         2DROP ;

 

 

 

The thing is, I am using DATA[ to turn INTERPRET around so that it presumes the token is a number first so that I can remove any need for the user’s use of , or C, .  DATA[ presumes the token is a number, not an executable word. Of course, I may be missing something. ?

 

...lee

Link to comment
Share on other sites

1 hour ago, Lee Stewart said:

 

The thing is, I am using DATA[ to turn INTERPRET around so that it presumes the token is a number first so that I can remove any need for the user’s use of , or C, .  DATA[ presumes the token is a number, not an executable word. Of course, I may be missing something. ?

 

...lee

Right and that is faster that my method.

I was referring to how one might make DATA xxxx,xxxx,  word in Fig-Forth.

Something like: 

: DATA ( -- )
         BEGIN
            ASCII , WORD  
            HERE C@
         WHILE
            HERE INTERPRET ,
         REPEAT
         DROP DROP ;

Would that work?

Link to comment
Share on other sites

On 12/16/2021 at 7:07 PM, TheBF said:

Right and that is faster that my method.

I was referring to how one might make DATA xxxx,xxxx,  word in Fig-Forth.

Something like: 


: DATA ( -- )
         BEGIN
            ASCII , WORD  
            HERE C@
         WHILE
            HERE INTERPRET ,
         REPEAT
         DROP DROP ;

Would that work?

 

I will need to think on it.  [EDIT: Still thinking...]

 

...lee

Edited by Lee Stewart
  • Like 1
Link to comment
Share on other sites

  • 3 weeks later...

 

Quote

 

Inline Code Simplified (from @TheBF, CAMEL99 Forth Information goes here, post #1159)

 

I tried this kind of thing a few years ago but it seemed overly complicated.

I think this code is better and it is smaller.  I also think it is easily applicable to other indirect threaded Forth systems. The big surprise to me was the new way I return to Forth.  See  ;CODE]  

 

It adds only 54 bytes to the system and you could use machine code between  [CODE     ;CODE]   

The total overhead for inserting CODE is  4 byte header + 6 byte return= 10 bytes which is about the same size as adding a short word header so not much saving, but sometimes it is clearer to see short code snippets inline.


\ INLINEASM.FTH headless code words inside Forth definition   DEC 30 2021 FOX
\ example below for usage

NEEDS .S     FROM DSK1.TOOLS
NEEDS MOV,   FROM DSK1.ASM9900

HERE
HEX
: [CODE ( -- )
          HERE CELL+ ,
          HERE CELL+ ,      \ create the ITC header for a CODE word
          POSTPONE [        \ turn off the Forth compiler
; IMMEDIATE

: ;CODE] ( -- )
          IP HERE 6 + LI,    \ (points to Forth after NEXT,)
          NEXT,              \ compile next into headless code word
          ]                  \ turn on the Forth compiler
;   IMMEDIATE

HERE SWAP - SPACE DECIMAL . .( bytes) HEX CR

\ example
VARIABLE X    2 X !
VARIABLE Y    3 Y !

: TEST  ( -- )  [CODE  Y @@ X @@ ADD,  ;CODE]   X @ .   ;
 

 

 

 

 

 

Below is my implementation for fbForth 2.0, which adds 58 bytes (4 more than for CAMEL99 Forth) to the system:

\ INLINEASM.FBF headless code words inside Forth definition  30DEC2021 FOX
\ Modified for fbForth 2.0  31DEC2021 LES
\ Example below for usage

HERE
HEX
: [CODE ( -- )
   HERE 2+ ,
   HERE 2+ ,            \ create the ITC header for a CODE word
   [COMPILE] [          \ turn off the Forth compiler
   [COMPILE] ASSEMBLER  \ ASSEMBLER vocabulary
; IMMEDIATE

: ;CODE]
   ASSEMBLER         \ following code needs ASSEMBLER vocabulary
   IP HERE 6 + LI,   \ set IP to HERE+6 (points to Forth after NEXT,)
   NEXT,             \ compile "B *NEXT" into headless code word and..
                     \ ..back to previous vocabulary
   ]                 \ turn on the Forth compiler
;

HERE SWAP - SPACE DECIMAL . ." bytes" HEX CR

\ example
2 VARIABLE X
3 VARIABLE Y

: TEST  ( -- )  [CODE  Y @@ X @@ A,  ;CODE]   X @ .   ;
 
...lee
Edited by Lee Stewart
Additional info and CORRECTION of [CODE stack effects
  • Like 1
  • Confused 1
Link to comment
Share on other sites

I can understand @HOME AUTOMATION 's   confusion emoji. 

This is outside the realm of normal Forth application programming.

We are modifying how the compiler works, which is fair game in Forth but it means you must have "carnel knowledge"  of the system.

 

Something that helps ALC programmers understand Forth a bit better is the word HERE is much like $ in assembler.

However the use of [COMPILE] and IMMEDIATE takes most people a while to wrap their heads around and I still have to do tests to get it right. ?

  • Like 2
Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...