Is this the optimal 6502 NEXT?

Topics relating to various Forth models on the 6502, 65816, and related microprocessors and microcontrollers.
agsb
Posts: 31
Joined: 09 Jan 2023

Re: Is this the optimal 6502 NEXT?

Post by agsb »

Also >R R> R@ must look for 2nd cell at stack while runs, because 1st is the real return reference
User avatar
GARTHWILSON
Forum Moderator
Posts: 8774
Joined: 30 Aug 2002
Location: Southern California
Contact:

Re: Is this the optimal 6502 NEXT?

Post by GARTHWILSON »

agsb wrote:
Also >R R> R@ must look for 2nd cell at stack while runs, because 1st is the real return reference
In 6502 fig-Forth, release 1.1 from September 1980, >R (not including the header) is:

Code: Select all

TOR:    .WORD *+2
        LDA  1,X
        PHA
        LDA  0,X
        PHA
        INX
        INX
        JMP  NEXT

R> is:

Code: Select all

RFROM:  .WORD *+2
        DEX
        DEX
        PLA
        STA  0,X
        PLA
        STA  1,X
        JMP  NEXT

R@ is:

Code: Select all

R:      .WORD  *+2
        STX  XSAVE
        TSX
        LDA  $101,X
        PHA
        LDA  $102,X
        LDX  XSAVE
        JMP  PUSH

There's no return address to step over, because they're primitives.

In my 65816 ITC Forth, I have for these:

Code: Select all

        HEADER ">R", NOT_IMMEDIATE      ; ( n -- )  ; Should be compile-only.
TO_R:   PRIMITIVE                                   ; Will crash in command line.
        LDA     0,X
        PHA
        POP1
 ;-------------------
        HEADER "DUP>R", NOT_IMMEDIATE   ; ( n -- n )
DUP2R:  PRIMITIVE
        LDA     0,X
        PHA
        GO_NEXT
 ;-------------------
        HEADER "R>", NOT_IMMEDIATE      ; ( -- n )
R_FR:   PRIMITIVE
        PLA
        DEX2                            ; These 2 lines are like JMP PUSH but
        PUT_TOS                         ; 2 bytes longer to save 3 clocks.
 ;-------------------
        HEADER "R@", NOT_IMMEDIATE      ; ( -- n )
Rfetch: PRIMITIVE                       ; I uses this code too.
        LDA     1,S                     ; Stack-relative addressing.
        DEX2                            ; These 2 lines are like JMP PUSH but
        PUT_TOS                         ; 2 bytes longer to save 3 clocks.
 ;-------------------

(with a little use of short macros to improve the source-code clarity and length, for example PUT_TOS is just STA 0,X followed by a jump to NEXT).

Quote:

Code: Select all

next:
; as is, classic ITC from fig-forth 6502
        sty  y_save
        <snip>

The fig-Forth NEXT is this:

Code: Select all

NEXT:   LDY  #1
        LDA  (IP),Y
        STA  W+1
        DEY
        LDA  (IP),Y
        STA  W
        CLC
        LDA  IP
        ADC  #2
        STA  IP
        BCC  L54
        INC  IP+1
L54:    JMP  W-1

Note that there's no saving and restoring of Y.  Many primitives need Y to start as 0 anyway; and this starts with LDY #1, not 0, then DEY's to 0; so it's already initialized for them.  My '816 Forth shortens NEXT quite a bit by using the 816's ability to handle 16 bits at a time, and also putting NEXT in direct page to take advantage of self-modifying code to avoid a couple of indirects, having IP and W be operands of the instructions themselves, rather than separate variables.

I kind of like your idea though of using 0000 in the CFA to indicate a primitive, and anything else to indicate a secondary (also called "colon definition"—we do not call these Forth words "compound words" in English), to save some memory.  It would take some experimentation to evaluate the tradeoffs.  On the '816, it becomes much more worthwhile to make a lot more words primitives, and in my '816 Forth, I have several hundred, which is partly why my 65816 Forth runs two to three times as fast as my '02 Forth at a given clock rate.

As for TOS (top of stack, the top data-stack cell) in register (basically in the 16-bit accumulator for the 65816), I went through some exercises to see if it would be beneficial, and although there are places where it would be, there are others where it actually adds overhead.  So I'd have to actually write an entire kernel and run programs on both kernels to find out if it was a wash or not.

Quote:
sorry long post.

There's no need to apologize.  A post should be as long as necessary to make the point, and there are many, many posts on this forum that are much, much longer.  A few are like presenting a paper at a conference, which is fine.
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?
agsb
Posts: 31
Joined: 09 Jan 2023

Re: Is this the optimal 6502 NEXT?

Post by agsb »

MITC also eliminates JSR/RTS, all goes to be: unnest->next-->leaf? jump : nest

Push all references until a primitive then execute and pull a reference

"There's no return address to step over, because they're primitives." and the return reference is at IP in Fig-Forth, but in MITC it will be at top of return stack
JimBoyd
Posts: 931
Joined: 05 May 2017

Re: Is this the optimal 6502 NEXT?

Post by JimBoyd »

GARTHWILSON wrote:

I kind of like your idea though of using 0000 in the CFA to indicate a primitive, and anything else to indicate a secondary (also called "colon definition"—we do not call these Forth words "compound words" in English), to save some memory.  It would take some experimentation to evaluate the tradeoffs. 

It's not as simple as "if the first cell is 0000 jump to the body of this word otherwise nest". A variable has a code field which does not point to its body, yet it is not a secondary. The same for constants and other child words of CREATE DOES> and CREATE ;CODE . These type of words do not have a code field which points to nest (or docolon) nor do they have a code field which points two bytes forward.
User avatar
GARTHWILSON
Forum Moderator
Posts: 8774
Joined: 30 Aug 2002
Location: Southern California
Contact:

Re: Is this the optimal 6502 NEXT?

Post by GARTHWILSON »

Good point.  For example, fig-Forth's R@ which I listed above is also used for I (getting a copy of the loop counter), and I's CFA points to R@'s code.  There are lots of those.
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?
agsb
Posts: 31
Joined: 09 Jan 2023

Re: Is this the optimal 6502 NEXT?

Post by agsb »

Quote:
It's not as simple as "if the first cell is 0000 jump to the body of this word otherwise nest". A variable has a code field which does not point to its body, yet it is not a secondary. The same for constants and other child words of CREATE DOES> and CREATE ;CODE . These type of words do not have a code field which points to nest (or docolon) nor do they have a code field which points two bytes forward.
No problem the reference for those is processed as any compound list of references, same for DOCON, DOVAR, DODOES, etc

anyway that's what happen in any Forth: push references, till a primitive, execute it, then pull a reference, repeat

;CODE is a primitive that does a direct jump for a reference (address) wich code ends with jmp unnest.

Any value at top of return stack could be moved without warn, just will be momentarily at 2nd cell while >R R> R@ is running, nothing change
JimBoyd
Posts: 931
Joined: 05 May 2017

Re: Is this the optimal 6502 NEXT?

Post by JimBoyd »

agsb wrote:
No problem the reference for those is processed as any compound list of references, same for DOCON, DOVAR, DODOES, etc

anyway that's what happen in any Forth: push references, till a primitive, execute it, then pull a reference, repeat

A quick perusal of your pdf file leads me to suspect this is actually a modification of direct threaded code (DTC), not ITC.
agsb wrote:
;CODE is a primitive that does a direct jump for a reference (address) wich code ends with jmp unnest.

;CODE is not a primitive, it compiles another word which is also not a primitive.
From the fig-forth installation manual:

Code: Select all

; CODE
Used in the form:
   : cccc   ....  ;CODE
         assembly mnemonics

Stop compilation and terminate a new defining word cccc by compiling (;CODE). Set the CONTEXT vocabulary to ASSEMBLER, assembling to machine code the following mnemonics.

Concerning your use of EXIT . Although the fig-Forth name for unnest is ;S (semicolon S), EXIT has been the name for unnest since the Forth-79 Standard, possibly earlier. It is what semicolon compiles.
JimBoyd
Posts: 931
Joined: 05 May 2017

Re: Is this the optimal 6502 NEXT?

Post by JimBoyd »

GARTHWILSON wrote:
Good point.  For example, fig-Forth's R@ which I listed above is also used for I (getting a copy of the loop counter), and I's CFA points to R@'s code.  There are lots of those.

My Forth's I works differently because its DO LOOP's use the overflow flag to determine when the limit has been crossed in either direction.
There are several words in the kernel which have a code field pointing into another word.

Code: Select all

2NIP      FORTH-83  >SLF#     VFIND     L>NAME    N>LINK    BODY>
>BODY     C!        HOLD      BUFFER    2SWAP     NIP       UNDER+
OVER      OFF       SWAP      DUP       D+        +         1-
1+        DUP>R     DNEGATE   NEGATE    CMOVE     ROFF      NOOP
[         1         0         FALSE     TRUE      BRANCH    DROP
EXIT      LEAVE     

agsb
Posts: 31
Joined: 09 Jan 2023

Re: Is this the optimal 6502 NEXT?

Post by agsb »

Quote:
Concerning your use of EXIT . Although the fig-Forth name for unnest is ;S (semicolon S), EXIT has been the name for unnest since the Forth-79 Standard, possibly earlier. It is what semicolon compiles.
Yes, I'm using Dr. Ting eForth names, also called by other names, etc.
Quote:
;CODE is not a primitive, it compiles another word which is also not a primitive.

Yes, in fig-Forth, and what it does is a jump for a assembler reference, could easy be a fast primitive. In IMMU it is.
Quote:
A quick perusal of your pdf file leads me to suspect this is actually a modification of direct threaded code (DTC), not ITC.
Please, tell me which part. The example is with DOCOL ... EXIT, not using any JSR/RTS.

Also in IMMU there is no JSR/RTS, all forth words are a uniq thread linked with JMPs.
agsb
Posts: 31
Joined: 09 Jan 2023

Re: Is this the optimal 6502 NEXT?

Post by agsb »

Quote:
There are several words in the kernel which have a code field pointing into another word.
The concept of "code field" is unnecessary in MITC, all references in compound words are treated the same way. So, the code field is just the first reference of a list as in (car cdr) :)

Really, as in any Forth, only primitives are executed and any compound is a list of address references.

Sure, some words have a "assembler code" in definition, and that part should be defined as primitive, previously.
User avatar
GARTHWILSON
Forum Moderator
Posts: 8774
Joined: 30 Aug 2002
Location: Southern California
Contact:

Re: Is this the optimal 6502 NEXT?

Post by GARTHWILSON »

agsb wrote:
Quote:
A quick perusal of your pdf file leads me to suspect this is actually a modification of direct threaded code (DTC), not ITC.
Please, tell me which part. The example is with DOCOL ... EXIT, not using any JSR/RTS.
Our own Dr. Brad Rodriguez (forum name BradR), a big man in the world of Forth, has an article on the different threading methods at http://www.bradrodriguez.com/papers/moving1.htm .  The explanation for DTC starts about 30% of the way down the page.  JSR/RTS is used a lot in STC; but while DTC uses JSR to the ENTER routine (also called nest or DOCOL) in a colon definition's code field just to keep a record of the address (minus 1) of the subsequent list of addresses, it does not use a matching RTS, if I understand it correctly.  DTC is the least clear in my mind.

Quote:
Quote:
Concerning your use of EXIT . Although the fig-Forth name for unnest is ;S (semicolon S), EXIT has been the name for unnest since the Forth-79 Standard, possibly earlier. It is what semicolon compiles.
Yes, I'm using Dr. Ting eForth names, also called by other names, etc.

I spent about 45 minutes searching his materials online.  I cannot find any reference to "compound words" in his materials.  He calls them "colon words" in a recent video.  Again, we do not call them "compound words" in English.  Please call them "colon definitions" or "secondaries."  These are the standard terms.  It was sad to read that he died last June.  He did appear to be quite old though.  I have separate words for unnest versus EXIT (although their CFAs point to the same code), so if I use the ANS word SEE to de-compile a word, it doesn't stop at an EXIT that's not at the end of the word.  As an aside, I see Dr. Ting did not like DO...LOOP, preferring instead FOR...NEXT.  The primitive laid down by NEXT (obviously different from the inner loop NEXT which is neither a primitive nor a secondary) is simpler than loop, but more limited in what it can do.  I see that Elizabeth Rather, in her book "Forth Application Techniques," ©2010, which is regarding Forth, Inc.'s ANS-compliant SwiftForth, only uses DO...LOOP, not FOR...NEXT.  I'll stick with DO...LOOP.

I know we're getting partially off the topic of optimal 6502 NEXTs; but we're 11 years and five pages into into it, and it has more or less run its course; so it's not necessary that everything be so tightly related.
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?
agsb
Posts: 31
Joined: 09 Jan 2023

Re: Is this the optimal 6502 NEXT?

Post by agsb »

Quote:
"I spent about 45 minutes searching his materials online. I cannot find any reference to "compound words" in his materials. "
I'm talking about nest, next, unnest. Primitives as leafs and Compound as twigs, https://muforth.nimblemachines.com/threaded-code/

I'm not saying that DTC, SDC must ever use JSR/RST, sorry, I try said that IMMU does not use.

And IMMU does not have ~~ call them "colon definitions" or "secondaries." ~~ because nest and unnest are incorporated to inner address interpreter, there is only primitives and "list of references", and any word could be at CFA, including (do), dovar, docon, dodoes etc

Also DO LOOP +LOOP LEAVE FOR NEXT IF ELSE THEN etc
Post Reply