Tali Forth for the 65c02

Topics relating to various Forth models on the 6502, 65816, and related microprocessors and microcontrollers.
User avatar
Dr Jefyll
Posts: 3526
Joined: 11 Dec 2009
Location: Ontario, Canada
Contact:

Re: Introducing Tali Forth for the 65c02 (ALPHA)

Post by Dr Jefyll »

The behaviors of the 'C02 NOPs certainly do seem enigmatic. I puzzled over the matter for quite a while before hitting on a plausible back story. If we were flies on the wall back when the 'C02 was on the drawing board, here's roughly what I think we would've heard:
  • "What are we gonna do about undefined opcodes? On the NMOS 6502 they had bizarre behaviors but folks managed to find a use for them anyway. Now they're an impediment to progress because there's a market segment that won't buy new chips unless the old behavior is preserved! Let's show more foresight than the NMOS team did. With the 'C02, let's make all the undefined opcodes into NOPs."

    "Yikes! That could entail a lot of changes! Do they have to be "genuine" NOPs in the sense of doing absolutely nothing except wasting time and advancing the PC?"

    "No. The goal is merely to remove motivation for using them. So it's alright to allow some of the undefined ops to inherit similarities to normal ops -- such as doing a memory access. As long as nothing gets written to the registers, flags or to memory then we can say they're NOPs and no-one will have a reason to use them."

Here's a speculation I don't find plausible. Some of the NMOS undefined opcodes have side effects such as crashing the CPU and requiring a reset. I've heard it suggested that rendering all undefined opcodes as NOPs would remedy this because NOPs execute harmlessly. But that's flawed thinking. Your program shouldn't be fetching anything unexpected in the first place! :roll: If the PC has gotten fouled up so as to point someplace inappropriate then you might as well hit reset anyway, since cogent results can't be expected.
MichaelM wrote:
Note: my processor core can support these behaviors with some minor updates to the microprogram
Interesting. The 'C02 design team wanted the undefined ops to be useless, but $DC and $FC turned out to be even better than the legitimate opcode $2C (BIT absolute) for the trick of skipping two bytes of code. And $02, $22, $42, $62, $82, $C2, and $E2 turned out to be useful for skipping over one byte of code. Michael, now you face a dilemma like that faced by the 'C02 design team! Will you choose to support the unorthodox usages or will you suppress them? :)

-- Jeff
In 1988 my 65C02 got six new registers and 44 new full-speed instructions!
https://laughtonelectronics.com/Arcana/ ... mmary.html
User avatar
MichaelM
Posts: 761
Joined: 23 Apr 2012
Location: Huntsville, AL

Re: Introducing Tali Forth for the 65c02 (ALPHA)

Post by MichaelM »

Dr Jeffyll wrote:
MichaelM wrote:
Note: my processor core can support these behaviors with some minor updates to the microprogram
Interesting. The 'C02 design team wanted the undefined ops to be useless, but $DC and $FC turned out to be even better than the legitimate opcode $2C (BIT absolute) for the trick of skipping two bytes of code. And $02, $22, $42, $62, $82, $C2, and $E2 turned out to be useful for skipping over one byte of code. Michael, now you face a dilemma like that faced by the 'C02 design team! Will you choose to support the unorthodox usages or will you suppress them? :)
As I am moving toward completion of my second core, there are no free opcodes left with which to support the "unorthodox" behaviors. Therefore, I will avoid that dilemma altogether. :)

I prefer to leave those changes to others. Personally, I have an aversion to those types of side effects. I can understand how they came about in both the 6502 and 65C02, but with today's design tools, I can't understand why anyone would implement those type of side effects.
Michael A.
theGSman
Posts: 85
Joined: 26 Jan 2015

Re: Introducing Tali Forth for the 65c02 (ALPHA)

Post by theGSman »

This is fascinating. I thought I was the only person still working on a new version of FORTH for the 6502 (in my case for the Commodore 64). I named my version DCFORTH64. It still needs an editor and file I/O before it can be useful but it has so far met all my expectations and the assembler works remarkably well.

Like Tali Forth, DCFORTH64 is a STC language. The main difference is that my version has separate name, data and code spaces (user programmable). This makes it relatively easy to write "stand alone" programs (ones that don't need the forth interpreter). You can even write ROMmable code.

One of the nicest features of STC coding is that you can switch between compiler mode and assembly mode at will. You can even write macros that lay down assembly code in either mode.

For example, : DROP, INX, INX, ; IMMEDIATE will code the DROP, instruction inline instead of coding a subroutine call to the DROP instruction.

In the interests of speed, every time a word pushes a number on the stack, assembly language instructions are compiled in line - regardless of whether the word is a CONSTANT, VARIABLE, S" or part of an instruction in another word. You can always save space with commonly used numbers by doing things like 5 CONSTANT 5.

I don't know if anybody is interested in the code I have written so far. It might be interesting to compare notes between these two versions.
User avatar
GARTHWILSON
Forum Moderator
Posts: 8773
Joined: 30 Aug 2002
Location: Southern California
Contact:

Re: Introducing Tali Forth for the 65c02 (ALPHA)

Post by GARTHWILSON »

Quote:
One of the nicest features of STC coding is that you can switch between compiler mode and assembly mode at will. You can even write macros that lay down assembly code in either mode.
I do that in ITC Forth, started from this topic, but there's some overhead in ITC of course. And probably any Forth assembler, being Forth, can naturally do macros very easily. STC is not necessary (although I would like to write an STC 6502 Forth if time were no object).
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
BigEd
Posts: 11464
Joined: 11 Dec 2008
Location: England
Contact:

Re: Introducing Tali Forth for the 65c02 (ALPHA)

Post by BigEd »

Welcome to our world, theGSman!
theGSman
Posts: 85
Joined: 26 Jan 2015

Re: Introducing Tali Forth for the 65c02 (ALPHA)

Post by theGSman »

BigEd wrote:
Welcome to our world, theGSman!
Thanks.
scotws
Posts: 576
Joined: 07 Jan 2013
Location: Just outside Berlin, Germany
Contact:

Re: Introducing Tali Forth for the 65c02 (ALPHA)

Post by scotws »

Hello theGSman, and welcome. A fellow STC soul :D !
Quote:
I don't know if anybody is interested in the code I have written so far. It might be interesting to compare notes between these two versions.
I'd love to see the code. You might have seen that Tali is hosted on GitHub (https://github.com/scotws/TaliForth), with three more words to go before I call it BETA -- ?DO, LEAVE, and RECURSE (though LEAVE is turning out to be a nightmare, I might have to rewrite a bunch of LOOP stuff). Is yours more ANS Forth or a FIG Forth?

STC stuff is pretty rare, unfortunately. Give us a bit, though, and it looks like we'll be changing that :D .
User avatar
barrym95838
Posts: 2056
Joined: 30 Jun 2013
Location: Sacramento, CA, USA

Re: Introducing Tali Forth for the 65c02 (ALPHA)

Post by barrym95838 »

Hey Scot. Could you explain how your unloop works? I can't make heads or tails of it, but it looks like it would always have to be in-lined to have much chance to work properly in an STC context.

Code: Select all

a_unloop:       ; drop top two entries off the Return Stack 
                pla
                pla
                pla
                pla

z_unloop:       rts
Would you like for me to keep crunching your source for your approval? I don't mind, but my spare time is a bit limited, so it could be a while between updates.

Mike B.
theGSman
Posts: 85
Joined: 26 Jan 2015

Re: Introducing Tali Forth for the 65c02 (ALPHA)

Post by theGSman »

scotws wrote:
Is yours more ANS Forth or a FIG Forth?
The words are based on the Forth-83 standard (I learned a lot from Leo Brodie) but "under the hood" is radically different (obviously). One consequence of separating the code and data spaces is that defining words like HERE and , (comma) become problematic since they could refer to either code or data. My brilliantly clever solution is to leave it up to the user to code these however he wishes :D. The CP, DP and NP variables are all available for the user to examine and change at will.

I haven't figured out how to make LEAVE work in my version and I am not making that a priority. In my experience, if you don't intend to run a counted loop in its entirety then you are better off using a WHILE loop and not relying on the ability of your compiler/interpreter to bail you out (minimizes portability issues). Unfortunately, EXITing a word from the middle of of the counted LOOP is also problematic although R>DROP EXIT will work for a singly nested loop.
scotws
Posts: 576
Joined: 07 Jan 2013
Location: Just outside Berlin, Germany
Contact:

Re: Introducing Tali Forth for the 65c02 (ALPHA)

Post by scotws »

barrym95838 wrote:
Could you explain how your unloop works?
It basically just takes the two loop parameters off the Return Stack. Since A is not conserved between words, that's all it should take. Note I use the "fudged" loop control for the ANS Forth version of DO/LOOP (so 0 0 DO loop through the whole number space) with the V-flag, so it's not comparable to the FIG versions.

However, LEAVE is not working at all at the moment, so I might have to rewrite the loop stuff anyway. If you see somebody banging his head in frustration against the side of a subway train on Berlin public transport these days, that would be me ...
Quote:
Would you like for me to keep crunching your source for your approval? I don't mind, but my spare time is a bit limited, so it could be a while between updates.
I'd be most grateful for any time you might have to spare, whenever, and no worries about the time. There is enough stuff in my life that is on the clock, so all this isn't, by design :D . Thanks again!
theGSman
Posts: 85
Joined: 26 Jan 2015

Re: Introducing Tali Forth for the 65c02 (ALPHA)

Post by theGSman »

scotws wrote:
If you see somebody banging his head in frustration against the side of a subway train on Berlin public transport these days, that would be me ...!
LOL That doesn't surprise me.

When I first tackled LEAVE I thought, "no problem, just set the loop counter equal to the loop limit and skip over the remainder of the DO loop". Then the questions came:
- LOOP will have to behave differently if there was a LEAVE statement - how do I let LOOP know?
- What if there is more than one LEAVE statement within the loop?
- What if LEAVE was inserted into nested IF statements?
- etc

I soon realized that coding for these contingencies meant that I was planning for a situation that goes far away from the FORTH philosophy that words should be simple. I could have stipulated a bunch of caveats that would have to apply before you could use a LEAVE statement but decided that leaving the LEAVE statement out altogether was a way of enforcing a stricter discipline on my programming style.
User avatar
GARTHWILSON
Forum Moderator
Posts: 8773
Joined: 30 Aug 2002
Location: Southern California
Contact:

Re: Introducing Tali Forth for the 65c02 (ALPHA)

Post by GARTHWILSON »

I haven't tried it in STC, but leave (the internal compiled by LEAVE) for 6502 ITC Forth is just:

Code: Select all

leave:  PLA
        PLA
        PLA
        PLA

        PLA
        STA  IP
        PLA
        STA  IP+1

        JMP  NEXT
 ;-------------------

LEAVE which compiles it is just:

Code: Select all

: LEAVE   ?COMP   COMPILE leave   ;  IMMEDIATE

You can have as many LEAVEs as you want in a loop.  LEAVE does not affect DO, ?DO, LOOP, or +LOOP.  The LEAVEs can be inside another structure too, as long as it's not another loop (since that would put more things on the return stack), and don't put LEAVE between >R and R>.  I do like to have however ?LEAVE which is just IF LEAVE THEN (but I do it as a primitive, and it's only five assembly-language instructions in my '816 ITC Forth,), and I like to add a variable LOOP_LEAVE which loop and ploop (the internals compiled by LOOP and +LOOP) zero and LEAVE sets to -1 and so does ?LEAVE if it leaves, so you can test later to see if the loop finished or was aborted.  Otherwise LOOP doesn't care if there's a LEAVE (or any number of LEAVEs) in the loop.  It's not complex (at least in ITC Forth).  There are some things that are complex but make the language more powerful and make your application more clear and maintainable.  That's good, not bad. DOES> and VOCABULARY (and friends) are the prime examples.  I know Chuck Moore doesn't (or at least didn't use to) like the CASE structure, but I think it's extremely valuable.  The way I do it is much more efficient than a set of nested IF...THENs.
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?
scotws
Posts: 576
Joined: 07 Jan 2013
Location: Just outside Berlin, Germany
Contact:

Re: Introducing Tali Forth for the 65c02 (ALPHA)

Post by scotws »

I've got a version working now, though it's ugly -- it requires an IF/THEN (no "DO LEAVE LOOP" as with Gforth), and it uses a flag to see if we have a LEAVE. Something is still very, very wrong, but it works and I have to get to bed. Also, if Garth is right with his most very simple solution, I might be prone to screaming at this point :-) ...

(I'm obviously too tired, but wouldn't there be a problem with a word such as

Code: Select all

: COUNTTOFROG  10 0 DO  I DUP . 3 = IF LEAVE THEN  LOOP ." Frog!" ; 
if you just jump out of the word at the moment of the LEAVE? How do you get to any stuff right after the LOOP?)

This might be a STC problem, with all the jumping around and using the Return Stack. I'm going to get my last two words coded -- ?DO and RECURSE -- and then see if I can figure out something cleaner during the rewrite.
User avatar
barrym95838
Posts: 2056
Joined: 30 Jun 2013
Location: Sacramento, CA, USA

Re: Introducing Tali Forth for the 65c02 (ALPHA)

Post by barrym95838 »

My point is that STC would JSR unloop, and the return address for that JSR would be in your way unless you did something with it too (or only used unloop in-line). Maybe I'm missing something, because I have become a bit befuddled with my DTC translation, in which my machine code stack and Forth return stack are one-and-the-same.

I briefly considered using a separate register like U for the return stack pointer, but my processor is not "register-rich" (which is just the way I like it) and I'm worried that I might need U for my Forth W register (although W seems so far to be much less important in DTC than in ITC). I think that I can make it work, but it's just a bit of extra effort, because my CamelForth DTC sources (from which I'm drawing inspiration) are Z80 in standard syntax and 6809 in Forth assembler syntax, and they are both a bit confusing to my old brain (Z80 because it's Z80, and Forth assembler syntax because it's Forth assembler syntax).

Mike B.
theGSman
Posts: 85
Joined: 26 Jan 2015

Re: Introducing Tali Forth for the 65c02 (ALPHA)

Post by theGSman »

scotws wrote:
(I'm obviously too tired, but wouldn't there be a problem with a word such as

Code: Select all

: COUNTTOFROG  10 0 DO  I DUP . 3 = IF LEAVE THEN  LOOP ." Frog!" ; 
if you just jump out of the word at the moment of the LEAVE? How do you get to any stuff right after the LOOP?)
Tired or not, you are correct. If the purpose of LEAVE was to exit the word entirely then coding it would be a trivial matter. However, the purpose of LEAVE is to exit the loop and continue with the code following LOOP.

This is the example that Leo Brodie gives in Starting Forth:

Code: Select all

 : DOUBLED   
          6 1000 21 1 DO  CR ." YEAR " I 2 U.R
                          2DUP R% +  DUP ."    BALANCE " .
                          DUP 2000 > IF  CR CR ." more than doubled in " 
                                            I . ." years " LEAVE  
                                   THEN
                     LOOP 2DROP ;

The result will look like this:

   DOUBLED
        YEAR  1   BALANCE 1060
        YEAR  2   BALANCE 1124
        YEAR  3   BALANCE 1191
        YEAR  4   BALANCE 1262
        YEAR  5   BALANCE 1338
        YEAR  6   BALANCE 1418
        YEAR  7   BALANCE 1503
        YEAR  8   BALANCE 1593
        YEAR  9   BALANCE 1689
        YEAR 10   BALANCE 1790
        YEAR 11   BALANCE 1897
        YEAR 12   BALANCE 2011

        more than doubled in 12 years ok
Cleaning up the stack is a common necessity at the end of a word.
Post Reply