fig-FORTH EXECUTE

Topics relating to various Forth models on the 6502, 65816, and related microprocessors and microcontrollers.
noneya
Posts: 39
Joined: 12 Feb 2021
Contact:

fig-FORTH EXECUTE

Post by noneya »

Hi All,

With fig-FORTH 1.0, I've noticed that I may issue the following, which jumps to the reset vector as expected and starts my kernal.

HEX
FFFC
EXECUTE

The Kernal reset is at $8530. From Wozmon, a 8530R starts it, and from EHBASIC a CALL $8530 works as well.

From fig-FORTH however, though the above execute for address FFFC works, the following does not, fig-FORTH just hangs:

HEX
8530
EXECUTE

I have also tried creating short assembly things at various addresses which it does not seem to call either, again just hangs. Tali forth on the other hand works "as I expect" whereas execute calls, in my example, 8530, or my address to start wozmon, etc.

I'm left wondering, am I missing something, should I expect fig-FORTH to jump to and execute 8530 as in my example above, or do I have some sort of problem with my fig-FORTH source, etc.

Any insight is appreciated and thanks!

PS - I am new to forth, so although I have also been trying to use CODE in order to test if I could make the desired jumps via. a assembly using a CODE instruction, I'm unfortunately not up to speed with that yet, though I continue to dig. However, even if I get that to work, I still want to understand if EXECUTE should handle it as described above.

I placed the post here as I'm thinking this is a newbie question, but of course please move to the FORTH section if more appropriate.

Thanks
Shaking out the dirty bits!

https://github.com/DonaldMoran
User avatar
GARTHWILSON
Forum Moderator
Posts: 8773
Joined: 30 Aug 2002
Location: Southern California
Contact:

Re: fig-FORTH EXECUTE

Post by GARTHWILSON »

Welcome. EXECUTE's input is the desired word's CFA (code-field address) on the stack. The CFA points to the code that is to be run. It is not the beginning address of the code itself. In the case of a primitive, ie, a code definition, ie, a word that is defined in assembly language (as opposed to being defined in terms of other Forth words), the CFA just points to the PFA (parameter-field address), which immediately follows the CFA. If you do HEX 8530 EXECUTE, it will pick up an address from $8530 and $8531, and jump to whatever that said. If those two bytes contained instructions rather than an address, then yes, you'll take a left turn into the weeds.
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?
noneya
Posts: 39
Joined: 12 Feb 2021
Contact:

Re: fig-FORTH EXECUTE

Post by noneya »

Garth! Thank you so much, that cleared it up and I have it working already.

You are much appreciated!

For anyone that may also struggle with this below is an example:

fig-FORTH 1.0

HEX OK
: LOW 50 ; OK
: HIGH 51 ; OK
30 LOW C! OK
85 HIGH C! OK
LOW EXECUTE

Note that execute works differently in Taliforth2
Last edited by noneya on Sun Mar 20, 2022 7:18 am, edited 2 times in total.
Shaking out the dirty bits!

https://github.com/DonaldMoran
User avatar
GARTHWILSON
Forum Moderator
Posts: 8773
Joined: 30 Aug 2002
Location: Southern California
Contact:

Re: fig-FORTH EXECUTE

Post by GARTHWILSON »

Here's a graphic of the ITC Forth header structure, plus some explanation which should help. I think the only difference between this and FIG is the comment here about the need for aligning 16-bit cells to even addresses. On the NMOS 6502, this had to be done because of the JMP(xxFF) bug (which was fixed in the CMOS 65c02).

ForthHeaderGraphic.gif

Code: Select all

After the name, there will be a zero byte if necessary to have the link field
 start on an even-numbered address.  Making the dummy byte a zero makes it
 easier to find the NFA given the LFA when we allow characters above 7F in
 names.  The name field can start on any addr.  [Edit: It especially makes SEE,
 the de-compiling word easier.]

 LINK FIELD:    A two-byte address (low byte first, as usual) of the name
                field of the previous word in the vocabulary.  Link field always
                starts on an even address.

 CODE FIELD     A two-byte address of the code to execute for this word.  For a:
                primitive: it points to the parameter field (its own addr + 2).
                secondary: it points to the CFA of nest.
                constant:  it points to the addr of const runtime routine.
                variable when the word is in RAM:  it points to the addr of
                   create (not CREATE ).
                variable when the word is in ROM:  it works the same as a
                   constant that gives the applicable RAM addr.
                (etc.  Also see explanations of DOES> does ;code etc.)

 PARAMETER FIELD  (body)  This could be machine-language code (in the case of a
                primitive), a string of two-byte Forth code field addresses (in
                the case of a secondary), data (in the case of a constant,
                array, etc) or combinations of these.  Some words may not even
                have a parameter field, as is the case with DROP for example,
                whose code field points to the POP routine, which has no need to
                look back at DROP's parameter field for any information.

If code is compiled without headers, the name field and link field will be
absent.  This saves memory, and if all the code is compiled without headers, it
will be nearly impossible for someone else to look at your compiled program and
figure it out, ie, reverse-engineer it.  Headerless code may be acceptable for
systems where further compilation (requiring searching the dictionary for names)
is not needed.

Note that a runtime routine (or runtime, for short) is not a Forth word per se,
and not only has no header, but no CFA either.  Other words' CFAs will point to
the address where the runtime routine starts.  An example would be const , the
runtime for constants.  const knows how to get the next cell (the only cell in
the parameter field of a word created by CONSTANT ) and put it on the stack.

Code fragments like POP2 and PUSH_FALSE are not particularly runtime routines,
but can be used as such by being called by the CFA of other words.  In this
particular case, the address of POP2 is pointed to by the CFA of 2DROP , and the
address of PUSH_FALSE is pointed to by DUMMYCELL and a couple others.  Usually
primitives will end by jumping to these fragments to save some memory when doing
things that a lot of primitives do at the end.
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?
User avatar
GARTHWILSON
Forum Moderator
Posts: 8773
Joined: 30 Aug 2002
Location: Southern California
Contact:

Re: fig-FORTH EXECUTE

Post by GARTHWILSON »

BTW, note these bugs in fig-Forth, and their fixes:

  • unsigned division of a 32-bit dividend by a 16-bit divisor, resulting in a 16-bit quotient and a 16-bit remainder. Presented for the 65C02 (with changes for use on 6502) and 65816, with notes of interest to Forth users (for UM/MOD).
  • unsigned multiplication (on forum), with 16-bit factors and 32-bit result, correcting a bug in the public-domain 6502 Forth multiplication, as the division article above
  • D< bug in common Forths, plus a fix (on forum)
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?
noneya
Posts: 39
Joined: 12 Feb 2021
Contact:

Re: fig-FORTH EXECUTE

Post by noneya »

Thank you again! I will defiantly dig in to this.
Shaking out the dirty bits!

https://github.com/DonaldMoran
User avatar
Dr Jefyll
Posts: 3525
Joined: 11 Dec 2009
Location: Ontario, Canada
Contact:

Re: fig-FORTH EXECUTE

Post by Dr Jefyll »

GARTHWILSON wrote:
I think the only difference between this and FIG is the comment here about the need for aligning 16-bit cells to even addresses. On the NMOS 6502, this had to be done because of the JMP(xxFF) bug (which was fixed in the CMOS 65c02).

Code: Select all

After the name, there will be a zero byte if necessary to have the link field start on an even-numbered address.
Allow me to clarify slightly, Garth. FIG Forth doesn't avoid 16 bit words at odd addresses. Instead, the potential problem is having the two bytes of a Code Field straddle a page boundary. Thus, it's somewhat uncommon for the extra byte to be necessary (and then only for NMOS, as you say).

The extra byte is only inserted when CREATE is about to lay down a Link Field and Code Field and the low-byte of DP = $FD. If an extra byte is inserted it will, as a side effect, cause the Link Field to be even-aligned, but this is unimportant.

-- Jeff
In 1988 my 65C02 got six new registers and 44 new full-speed instructions!
https://laughtonelectronics.com/Arcana/ ... mmary.html
User avatar
GARTHWILSON
Forum Moderator
Posts: 8773
Joined: 30 Aug 2002
Location: Southern California
Contact:

Re: fig-FORTH EXECUTE

Post by GARTHWILSON »

I'll take your word for it so I don't have to look into the details again (which I have not paid attention to in years); but do see my comment in the code section about keeping the alignment in my 65c02 and '816 Forths because it made it easier to find the NFA given the LFA when I frequently use the special characters above $7F in the DOS/ANSI [Edit: that should say IBM437 character set], so I can have names like ±½°C. [Edit, after further discussion below: I had forgotten it also makes SEE, the de-compiling word, easier.
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?
User avatar
Dr Jefyll
Posts: 3525
Joined: 11 Dec 2009
Location: Ontario, Canada
Contact:

Re: fig-FORTH EXECUTE

Post by Dr Jefyll »

GARTHWILSON wrote:
[...] because it made it easier to find the NFA given the LFA when I frequently use the special characters above $7F
Okay, I can see how always including an extra byte (and making that byte =0) gives you a new way to locate the end of a name. In contrast, the FIG method uses less memory but restricts you to only 128 possible characters.

But did you gloss over some details when you mentioned "keeping the alignment" in your 65c02 and '816 Forths? Either I'm missing something or you've evolved the alignment byte into something new and different that isn't really alignment related at all. I say that because aligning to even addresses means the extra byte will be absent about 50% of the time, whereas your end-of-name location scheme will require the extra byte to always be there. (Maybe we don't need to fully resolve this -- I'm okay if we don't.)

Certainly all of this is a LOT more detail than you asked for, noneya! :) Maybe the diagram (below) will help. But as a Forth novice, you needn't feel obliged to immediately master the nuances of names -- especially where non-FIG variations are concerned! Enjoy your Forth experience, and if any other issues come up, feel free to ask!

-- Jeff
Attachments
ForthHeaderGraphic.png
In 1988 my 65C02 got six new registers and 44 new full-speed instructions!
https://laughtonelectronics.com/Arcana/ ... mmary.html
User avatar
GARTHWILSON
Forum Moderator
Posts: 8773
Joined: 30 Aug 2002
Location: Southern California
Contact:

Re: fig-FORTH EXECUTE

Post by GARTHWILSON »

Dr Jefyll wrote:
GARTHWILSON wrote:
[...] because it made it easier to find the NFA given the LFA when I frequently use the special characters above $7F
Okay, I can see how always including an extra byte (and making that byte =0) gives you a new way to locate the end of a name. In contrast, the FIG method uses less memory but restricts you to only 128 possible characters.

But did you gloss over some details when you mentioned "keeping the alignment" in your 65c02 and '816 Forths? Either I'm missing something or you've evolved the alignment byte into something new and different that isn't really alignment related at all.
You're right. Since this was decades ago, I couldn't remember what it was all about (and what I thought I remembered was wrong), so I scoured my notes and code, and come up with this:

  • Cells are aligned in this kernel. The ANS decompiling word SEE works out simpler when the first byte of a cell has an even-numbered address. This is the only real reason for the alignment. DOES> compiles a null alignment byte after the JSR _does in the parent word so the CFA following it will be aligned. Interestingly, this also makes _does simpler.


FWIW, I wrote my word SEE before I knew about ANS, or probably before it even came out in '94, but I had called mine VIEW. When I saw that ANS had the same thing but called it SEE, I renamed mine to the standard. SEE is a decompiling word which makes a nice printout of what's in a secondary (ie, colon definition), its NFA, LFA, and CFA, with each cell given the word name if there's a header, the cell number, signed and unsigned value in both hex and decimal in case it's a compiled number, and text if it's a pair of ASCII characters, information might help in certain debugging situations.
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?
JimBoyd
Posts: 931
Joined: 05 May 2017

Re: fig-FORTH EXECUTE

Post by JimBoyd »

GARTHWILSON wrote:
Welcome. EXECUTE's input is the desired word's CFA (code-field address) on the stack. The CFA points to the code that is to be run. It is not the beginning address of the code itself. In the case of a primitive, ie, a code definition, ie, a word that is defined in assembly language (as opposed to being defined in terms of other Forth words), the CFA just points to the PFA (parameter-field address), which immediately follows the CFA. If you do HEX 8530 EXECUTE, it will pick up an address from $8530 and $8531, and jump to whatever that said. If those two bytes contained instructions rather than an address, then yes, you'll take a left turn into the weeds.

Something I realized when tightening up some code. EXECUTE isn't needed in the definition of a colon definition if the address to execute is known ahead of time. I used to define BYE , the word Fleet Forth uses to reset the C64, like this:

Code: Select all

: BYE  ( -- )
   SAVE-BUFFERS  ACLOSE
   $FFFC EXECUTE ; -2 ALLOT

Which compiled to something like this:

Code: Select all

SEE BYE
BYE
 4374 23F1 SAVE-BUFFERS
 4376  D3C ACLOSE
 4378  A3C LIT FFFC 
 437C 17F3 EXECUTE
A 
 OK

Now I define it like this:

Code: Select all

: BYE  ( -- )
   SAVE-BUFFERS  ACLOSE
   [ $FFFC , ] ; -2 ALLOT

Which compiles to this:

Code: Select all

SEE BYE
BYE
 4374 23F1 SAVE-BUFFERS
 4376  D3C ACLOSE
 4378 FFFC 
6 
 OK

Saving four bytes.
User avatar
GARTHWILSON
Forum Moderator
Posts: 8773
Joined: 30 Aug 2002
Location: Southern California
Contact:

Re: fig-FORTH EXECUTE

Post by GARTHWILSON »

Off the top of my head, the number-one use of EXECUTE I can think of is if you pick up the address from a table, where the address you'll need is not known at compile time. It may even be a cell in a record in the table, where other bytes in the same record may be text or other parameters, rather than CFAs.
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?
JimBoyd
Posts: 931
Joined: 05 May 2017

Re: fig-FORTH EXECUTE

Post by JimBoyd »


Another use is in INTERPRET .
User avatar
GARTHWILSON
Forum Moderator
Posts: 8773
Joined: 30 Aug 2002
Location: Southern California
Contact:

Re: fig-FORTH EXECUTE

Post by GARTHWILSON »

Ah, yes, calling either INTERPRETER or COMPILER:

Code: Select all

: INTERPRETER           ( str_addr -- )                    \ Common Forth    FIG
   FIND                         \ ^ addr f      (f=0 if not found)
   IF    EXECUTE                \ EXECUTE if word found.
   ELSE  #INT 0=                \ Else, see if it's a valid number.
         IF DROP THEN           \ DROP the high cell if not double-precision.
   THEN  ?STACK         ;


: COMPILER      ( str_addr -- )
   FIND  ?DUP           IF      \ TOS<>0 if word was found.
   0< IF ,  EXIT THEN           \ -1 means not IMMEDIATE , so compile it.
   EXECUTE  EXIT        THEN    \ Else it's IMMEDIATE , so execute it.
                                \ If word was not found, see
   #INT          IF             \ if string is a valid number.  If a decimal
   2LITERAL EXIT THEN           \ point was found, make a double literal; else
   DROP LITERAL         ;       \ drop the high cell and make a single literal.


: INTERPRET             ( -- )          \     18 CELLS                 SF283-286
   BEGIN   BL WORD                      \ ^ addr
      DUP C@ 0<>                        \ ^ addr f
   WHILE   STATE @                      \ ^ addr f
      IF COMPILER ELSE INTERPRETER THEN \ ^ empty
   REPEAT  DROP         ;
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?
IamRob
Posts: 357
Joined: 26 Apr 2020

Re: fig-FORTH EXECUTE

Post by IamRob »

OOC, where else would either INTERPRETER or COMPILER be used outside of INTERPRET that would require them to have their own definitions?

Personally I like the all-in-one combination of all three in Fig Forth.
Post Reply