6502.org Forum  Projects  Code  Documents  Tools  Forum
It is currently Thu Nov 21, 2024 5:51 pm

All times are UTC




Post new topic Reply to topic  [ 19 posts ]  Go to page 1, 2  Next
Author Message
PostPosted: Mon Jun 24, 2019 1:45 pm 
Offline

Joined: Mon Jun 24, 2019 1:13 pm
Posts: 34
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.


Top
 Profile  
Reply with quote  
PostPosted: Mon Jun 24, 2019 2:42 pm 
Offline
User avatar

Joined: Fri Dec 11, 2009 3:50 pm
Posts: 3367
Location: Ontario, Canada
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


Top
 Profile  
Reply with quote  
PostPosted: Mon Jun 24, 2019 11:45 pm 
Offline

Joined: Mon Jun 24, 2019 1:13 pm
Posts: 34
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.


Top
 Profile  
Reply with quote  
PostPosted: Tue Jul 02, 2019 8:02 pm 
Offline

Joined: Fri May 05, 2017 9:27 pm
Posts: 895
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:
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 ?


Top
 Profile  
Reply with quote  
PostPosted: Thu Jul 04, 2019 6:12 am 
Offline

Joined: Mon Jun 24, 2019 1:13 pm
Posts: 34
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:
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:
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:
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:
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.


Top
 Profile  
Reply with quote  
PostPosted: Sat Jul 06, 2019 6:14 pm 
Offline

Joined: Fri May 05, 2017 9:27 pm
Posts: 895
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).


Top
 Profile  
Reply with quote  
PostPosted: Sat Jul 06, 2019 7:12 pm 
Offline
User avatar

Joined: Fri Aug 30, 2002 1:09 am
Posts: 8543
Location: Southern California
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?


Top
 Profile  
Reply with quote  
PostPosted: Sat Jul 06, 2019 8:28 pm 
Offline

Joined: Fri May 05, 2017 9:27 pm
Posts: 895
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:
   <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:
   <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> ;


Top
 Profile  
Reply with quote  
PostPosted: Mon Jul 08, 2019 3:00 am 
Offline

Joined: Mon Jun 24, 2019 1:13 pm
Posts: 34
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:
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.


Top
 Profile  
Reply with quote  
PostPosted: Mon Jul 08, 2019 3:45 am 
Offline
User avatar

Joined: Fri Aug 30, 2002 1:09 am
Posts: 8543
Location: Southern California
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?


Top
 Profile  
Reply with quote  
PostPosted: Mon Jul 08, 2019 5:44 am 
Offline

Joined: Mon Jun 24, 2019 1:13 pm
Posts: 34
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.


Top
 Profile  
Reply with quote  
PostPosted: Wed Jul 24, 2019 11:36 am 
Offline

Joined: Sun Apr 10, 2011 8:29 am
Posts: 597
Location: Norway/Japan
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.


Top
 Profile  
Reply with quote  
PostPosted: Sat Jul 27, 2019 10:55 pm 
Offline

Joined: Fri May 05, 2017 9:27 pm
Posts: 895
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.


Top
 Profile  
Reply with quote  
PostPosted: Mon Aug 17, 2020 11:37 pm 
Offline

Joined: Fri May 05, 2017 9:27 pm
Posts: 895
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:
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:
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.


Top
 Profile  
Reply with quote  
PostPosted: Wed Aug 19, 2020 8:39 pm 
Offline

Joined: Fri May 05, 2017 9:27 pm
Posts: 895

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:
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:
CREATE SOMETABLE
B/BUF 2* ALLOT
MARKER FORGET.ME
: FILL.TABLE
   B/BUF 0
   DO
      I DUP 2* SOMETABLE + !
   LOOP ;
FILL.TABLE
FORGET.ME



Top
 Profile  
Reply with quote  
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 19 posts ]  Go to page 1, 2  Next

All times are UTC


Who is online

Users browsing this forum: No registered users and 10 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to: