New here, but not to Forth or the 6502s

Topics relating to various Forth models on the 6502, 65816, and related microprocessors and microcontrollers.
pbj
Posts: 34
Joined: 24 Jun 2019

New here, but not to Forth or the 6502s

Post by pbj »

Forth seems to be quite active here on the 6502 forum, perhaps that's because Forth is being used where it is used best IMO, in controlling hardware.

I've used Forth ever since the 80's when I first decided that the R6511AQ would the CPU in my new POS terminal design. I already knew about Forth from having played with it on Apple IIs but when I say play, I mean that I was writing useful software but having fun. I didn't want the chip with the Forth built-in so I purchased and hacked the ROMs. After designing suitable hardware I was up and running in no time with my POS terminal software even though this was probably the first time I had written any large application in Forth or handled 6502 assembler. I went on to using 65816s and writing Forths for that and also Mitsubishi's single-chip version based on that, the M37702 which I used in many industrial designs for most of the 90's.

But single-chip micros in the 90's never really had Flash or much RAM so unfortunately I ended up using MSP430s and then LPC2148 ARM chips having written Forths for these too. The LPC2148 is still being used in product to this day running my Forth (which also came 2nd in the Circuit Cellar Philips ARM Design Contest in 2005).

Since then I have mainly used the Parallax Propeller although initially I didn't use Forth for this chip and the Forths that were available were not good enough for commercial use. All that changed in 2012 when I finally decided what the heck, I need more speed and more code in the same amount of memory, how hard could it be to write a Forth for this chip? So Tachyon Forth was born and went through new versions over the years while being deployed in commercial product until I finally stopped at V5.4. That's because I had developed Tachyon on the successor to the Propeller, dubbed the P2, whereas the original Prop is now referred to as the P1. Although I have had Tachyon running on the P2 in various forms on FPGA for several years, it was only last year that engineering samples were made with my Tachyon (now called TAQOZ) embedded in mask ROM. Production quantities of this very very cool chip will be available in the next few months. I can play back audio, images, and even video from FAT32 SD cards, and that's just the start.

So I have lots and lots of code for Forth and the 6502/65816/M37702 etc and just thought I'd introduce myself to this very active and interesting forum, and maybe I might even dig out some of my old 65xx boards and plug them in. Maybe I might even port Tachyon across as well and have some fun there too.
User avatar
Dr Jefyll
Posts: 3526
Joined: 11 Dec 2009
Location: Ontario, Canada
Contact:

Re: New here, but not to Forth or the 6502s

Post by Dr Jefyll »

pbj wrote:
maybe I might even dig out some of my old 65xx boards and plug them in.
Hooray! That's the spirit! :P

Welcome, pbj -- it's a very interesting introduction you've written, and I can see there'll be lots to talk about with the members here. I'll be looking forward to hearing more from you.

cheers
Jeff
In 1988 my 65C02 got six new registers and 44 new full-speed instructions!
https://laughtonelectronics.com/Arcana/ ... mmary.html
pbj
Posts: 34
Joined: 24 Jun 2019

Re: New here, but not to Forth or the 6502s

Post by pbj »

One of the aspects of Tachyon has been that it primarily compiles interactive text input word by word and runs this temporary code on end of line. So there are no special print words etc and I can just as easily write a quick one-liner complete with DO LOOP IF THEN etc that runs fast as compiled code like this:
$80 $20 DO I EMIT LOOP

My first few versions of Tachyon were all bytecode based but then I moved to 16-bit wordcode based instructions that mostly were addresses but there were a range of addresses that are used for encoding instructions such as conditional branches and short literals etc. Which reminds me, DO is an actual instruction (there is no (DO) ) and it pushes the IP onto a dedicated loop stack so that that LOOP can read this address directly from the loop stack. The loop index I is available in words called from the DO LOOP.

There are lots of design decisions that make Tachyon fast and compact so it will be interesting to see how I can implement it on the 65816/M37702 perhaps as a 16-bit wordcode with 32-bit wide stack as standard.
JimBoyd
Posts: 931
Joined: 05 May 2017

Re: New here, but not to Forth or the 6502s

Post by JimBoyd »

Welcome.
pbj wrote:
One of the aspects of Tachyon has been that it primarily compiles interactive text input word by word and runs this temporary code on end of line. So there are no special print words etc and I can just as easily write a quick one-liner complete with DO LOOP IF THEN etc that runs fast as compiled code like this:
$80 $20 DO I EMIT LOOP
I assume the temporary code is compiled somewhere other than the dictionary. That would be handy for building tables, or other structures, without defining support words.

Code: Select all

CREATE SOMETABLE
HEX
10 0 DO I C, LOOP
Quote:
Which reminds me, DO is an actual instruction (there is no (DO) ) and it pushes the IP onto a dedicated loop stack so that that LOOP can read this address directly from the loop stack. The loop index I is available in words called from the DO LOOP.
Does it support ?LEAVE and LEAVE ?
pbj
Posts: 34
Joined: 24 Jun 2019

Re: New here, but not to Forth or the 6502s

Post by pbj »

Tachyon compiles temporary code at the end of the code dictionary while words are stored end to end in the word dictionary while variables occupy data space. So code definitions can cascade into the next and names can be removed selectively while you can ERASE all variables and buffers in the data area without impacting code or dictionary.

As for LEAVE all it does is adjust the index to the limit so that it leaves on the next loop. (come to think of it I could just adjust the limit instead and still access the index after it leaves the loop). The separate loop stack will never interfere with code addresses stored on the return stack which otherwise would not crash gently (recoverable). Not an option on fail-soft software.

Console output testing LEAVE, disjointed DO I LOOP, code vs word dictionary vs data space.

Code: Select all

TAQOZ# $80 $20 DO I EMIT I 'D' = IF LEAVE THEN LOOP ---  !"#$%&'()*+,-./0123456789:;<=>?@ABCD ok
TAQOZ# : IEMIT  I EMIT LOOP ; ---  ok
TAQOZ# $80 $20 DO IEMIT ---  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~ ok
TAQOZ# ' IEMIT .L --- $0000_5BAA ok
TAQOZ# NFA' IEMIT .L --- $0000_DFA3 ok
TAQOZ# 4 longs samples ---  ok
TAQOZ# 32 bytes inbuf ---  ok
TAQOZ# samples 48 erase ---  ok
TAQOZ# samples 48 DUMP --- 
0001_2343: 00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00     '................'
0001_2353: 00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00     '................'
0001_2363: 00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00     '................' ok
BTW, Since tables are used so often I have a special word that can preallocate space if needed or just tack on data. Being a table it resides in code space.
Here is a table of 16 byte values using the more unobtrusive and readable | instead of the C, (still use , for 32-bit longs)

Code: Select all

0 TABLE ma	0 | 1 | 5 | 10 | 25 | 35 | 60 | 100 | 1 | 5 | 10 | 25 | 35 | 45 | 80 | 200 |
TAQOZ# ma 16 DUMP --- 
05BC0: 00 01 05 0A  19 23 3C 64  01 05 0A 19  23 2D 50 C8     '.....#<d....#-P.' ok
But sometimes I define a forgettable helper stub to build a table in which case I just preallocate.

Code: Select all

100 7 * TABLE FONT5X7
TACHYON does not try to be ANS compatible which might be fine for PCs but the embedded world needs far more flexibility.
Default base is always decimal with % # $ prefix to force binary, decimal, hex. The # in the prompt is the current decimal base.

EDIT: After posting this I revisited my kernel code and streamlined it a bit more. Now FOR NEXT and DO LOOP etc use the same stack structure so they can even be intermixed. FOR NEXT seems a bit redundant now since DO LOOP runs just as fast but FOR is equivalent to a 0 DO which means a FOR NEXT loop supports an incrementing I index. A loop takes 32 cycles or 107ns @300MHz.

Code: Select all

TAQOZ# 1,000,000 LAP FOR NEXT LAP .LAP --- 32,000,096 cycles= 106,666,986ns @300MHz ok
TAQOZ# 1,000,000 0 LAP DO LOOP LAP .LAP --- 32,000,105 cycles= 106,667,016ns @300MHz ok
It will be interesting to see how I implement that on the 65816.
JimBoyd
Posts: 931
Joined: 05 May 2017

Re: New here, but not to Forth or the 6502s

Post by JimBoyd »

pbj wrote:
As for LEAVE all it does is adjust the index to the limit so that it leaves on the next loop.
From what I remember, Forth's LEAVE worked like that at one time.The Forth-83 Standard changed the behavior of LOOP and +LOOP to terminate the loop if the new index is incremented across the boundary between limit-1 and limit ( in either direction ). At the same time, the behavior of LEAVE was changed to leave the loop immediately ( and discard the loop parameters).
User avatar
GARTHWILSON
Forum Moderator
Posts: 8773
Joined: 30 Aug 2002
Location: Southern California
Contact:

Re: New here, but not to Forth or the 6502s

Post by GARTHWILSON »

JimBoyd wrote:
At the same time, the behavior of LEAVE was changed to leave the loop immediately ( and discard the loop parameters)
, not executing the part between LEAVE and LOOP. I added a flag LOOP_LEAVE in mine which you can test later to see if the loop finished the normal way or was aborted. No initialization is necessary, even in do (which is compiled by DO). loop (compiled by LOOP) and +loop (compiled by +LOOP) include STZ LOOP_LEAVE, and leave (compiled by LEAVE) includes LDA #$FFFF STA LOOP_LEAVE, and ?leave (compiled by ?LEAVE) does the same action if the flag it examines was true and it leaves. unloop removes the loop limit, index, and exit address from the stack and must be followed (although not necessarily immediately) by EXIT.
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: New here, but not to Forth or the 6502s

Post by JimBoyd »

GARTHWILSON wrote:
I added a flag LOOP_LEAVE in mine which you can test later to see if the loop finished the normal way or was aborted
That sounds useful. I have a word in Fleet Forth that does some stuff at the end of the loop only if the loop did not exit prematurely ( i.e. what was sought was not found). I may have written it differently if I'd thought of this. Then again, I'm trying to squeeze all the performance ( size and speed ) that I can from the C64.
Quote:
unloop removes the loop limit, index, and exit address from the stack and must be followed (although not necessarily immediately) by EXIT.
The aforementioned word in Fleet Forth has UNLOOP in the loop, but it is not followed by EXIT . It is followed by a BRANCH past the words that are performed if the loop runs to completion.

Code: Select all

   <SET UP THE LOOP>
   ?DO
      <TEST SOMETHING>
      IF  DROP I UNLOOP
      ELSE
      CS-ROT CS-ROT
   LOOP
      <DO THIS ONLY IF LOOP COMPLETES>
   THEN
   <ALWAYS DO THIS PART> ;
Although, now that Fleet Forth has an auxiliary stack, the following is better. It compiles the same thing, but does not require knowledge of how much control flow data DO LOOPs use.

Code: Select all

   <SET UP THE LOOP>
   ?DO
      <TEST SOMETHING>
      IF  DROP I UNLOOP
      ELSE
      CS>A
   LOOP
      <DO THIS ONLY IF LOOP COMPLETES>
      A>CS
   THEN
   <ALWAYS DO THIS PART> ;
pbj
Posts: 34
Joined: 24 Jun 2019

Re: New here, but not to Forth or the 6502s

Post by pbj »

I'm aware of different ways that loops can be handled and I have never really had a need for anything special beyond using a dummy result value before I enter the loop that is modified by any LEAVE condition. I do have the equivalent of an UNLOOP which I never use but I'm thinking of just making this EXIT at the same time but then again since DO and LOOP are actual runtime words I can still jump over them with IF like this:

Code: Select all

TAQOZ#  : LOOPING 0 100 0 DO I 5 = IF 1+ UNLOOP ELSE I . SPACE LOOP THEN . ;  ---  ok
TAQOZ# LOOPING --- 0 1 2 3 4 1 ok
TAQOZ# SEE LOOPING

E086: pub LOOPING
5D1C: F800     0
5D1E: F864     100   $0064 d
5D20: F800     0
5D22: 010D     DO
5D24: 0103       I
5D26: F805       5
5D28: 00B6       =
5D2A: FC03       IF $5D32
5D2C: 0087         1+
5D2E: 0121         UNLOOP
5D30: 5D3B         ELSE $5D3A 
5D32: 0103         I
5D34: 1AFA         .
5D36: 1220         SPACE
5D38: 011D       LOOP
               THEN
5D3A: 1AFB     . ; 
      32 bytes 
 ---  ok
So maybe that is useful as it is.

The index crossing the limit is a better test which I have implemented before in my 65816 Forths IIRC and I could make it strict I guess but I'm trying to think where I need it.
User avatar
GARTHWILSON
Forum Moderator
Posts: 8773
Joined: 30 Aug 2002
Location: Southern California
Contact:

Re: New here, but not to Forth or the 6502s

Post by GARTHWILSON »

We've had a few conversations about deviating from "official" Forth standards; so without repeating them, I'll refer to this post and the ones around it, and this post. Deviating from standards seems to give people more reason to turn up their noses at Forth; so I try to stick with what's standard as far as is convenient, but I don't hold back from doing my own thing when it works out better particularly for the 65xx. The C crowd's insistence on conforming to C standards seems to be a barrier to getting better C performance for the 6502. On another 6502 forum, I have suggested certain improvements, and the answer I get is that "the standards don't allow that." My answer is, "So??"
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?
pbj
Posts: 34
Joined: 24 Jun 2019

Re: New here, but not to Forth or the 6502s

Post by pbj »

Forth is the ugly word on other forums whereas on a Forth forum it is "standards" believe it or not! So I just say yeah, standards are great .... for the majority of tasks on the majority of larger systems such as PCs. After all, the standards are PC centric yet the embedded world has its own demands and constraints, and the standards would only hobble a Forth embedded system, making it effectively unusable.

Embedded apps require that it just works 24/7 and without the memory and processing power of a PC, so it has to be efficient in whatever it does. If it does not do it you can't upgrade "the PC" and your product fails. Tachyon is there to make the supplier and the customer happy, not the standards people poking keys on their PCs.

The inventor of Forth writes his own standards, he does what needs to be done, which is also how Forth was invented. Forth will never be a language for the unwashed masses or education that requires strong typing and syntax to teach and grade. Those who grok it will use it. New processor architectures, new Forths! I started out primarily from a hardware background and so I really appreciate the ability to interact with the hardware down to the bare silicon.
Tor
Posts: 597
Joined: 10 Apr 2011
Location: Norway/Japan

Re: New here, but not to Forth or the 6502s

Post by Tor »

GARTHWILSON wrote:
The C crowd's insistence on conforming to C standards seems to be a barrier to getting better C performance for the 6502. On another 6502 forum, I have suggested certain improvements, and the answer I get is that "the standards don't allow that." My answer is, "So??"
C is a very special case among programming languages. All the Unix tools were written in C (you would have something like /usr/src/ with tons of programs, everything from 'ls' to 'emacs'). So, when you ported Unix to something else, you needed to be able to compile all of that code. That enforced strictly conforming C compilers, and that turned out to be maybe the most important reason for why C became so widespread. C was C was C.. just about every other language has many more dialects. That tradition has continued, although there's been a transition to ANSI C (the one big change was only the function prototypes, and that started *before* ANSI C in practice).

Unfortunately for architectures like the 6502, C-style stack-based languages are not very efficient.
JimBoyd
Posts: 931
Joined: 05 May 2017

Re: New here, but not to Forth or the 6502s

Post by JimBoyd »

pbj wrote:
Forth is the ugly word on other forums whereas on a Forth forum it is "standards" believe it or not!
I don't have a problem with standards. I thought the Forth-83 Standard was a good one. I realize that with newer hardware the standard needed updating, so it wasn't so 16bit specific, but I don't care for some of the asinine aspects of the ANSI standard such as wordlists and Ragsdale's 'only' solution.
Quote:
So I just say yeah, standards are great .... for the majority of tasks on the majority of larger systems such as PCs. After all, the standards are PC centric yet the embedded world has its own demands and constraints, and the standards would only hobble a Forth embedded system, making it effectively unusable.
I can't help but wonder how much inefficiency is introduced by conformance to every little detail of those standards. Inefficiency that goes unnoticed, for the most part, because of the speed and power of modern PC processors.
JimBoyd
Posts: 931
Joined: 05 May 2017

Re: New here, but not to Forth or the 6502s

Post by JimBoyd »

JimBoyd wrote:
I assume the temporary code is compiled somewhere other than the dictionary. That would be handy for building tables, or other structures, without defining support words.

Code: Select all

CREATE SOMETABLE
HEX
10 0 DO I C, LOOP

I've since realized another way to build that table using evaluate and modifying >IN .

Code: Select all

0 " DUP C, 1+ DUP 10 = >IN !" COUNT EVALUATE DROP

Note: In Fleet Forth, any value of >IN greater than, or equal to, the size of the text source will end interpretation, or in this case, string evaluation.
the Forth word " (quote) either compiles a string into a colon definition or, if interpreting, stores the string in PAD and returns the address of PAD.
JimBoyd
Posts: 931
Joined: 05 May 2017

Re: New here, but not to Forth or the 6502s

Post by JimBoyd »


Sorry. I got intent on a complex problem. The previous version can only build a table of about eighty bytes before WORD's work area at HERE collides with the string that used to be at PAD. Your mileage may vary.
Here is a better version of how to fill a table.

Code: Select all

CREATE SOMETABLE
B/BUF 2* ALLOT
: FILL.TABLE 
   B/BUF 0 
   DO 
      I DUP 2* SOMETABLE + ! 
   LOOP ;
FILL.TABLE
FORGET FILL.TABLE

Or for the Ansi crowd.

Code: Select all

CREATE SOMETABLE
B/BUF 2* ALLOT
MARKER FORGET.ME
: FILL.TABLE 
   B/BUF 0 
   DO 
      I DUP 2* SOMETABLE + ! 
   LOOP ;
FILL.TABLE
FORGET.ME

Post Reply