6502.org Forum  Projects  Code  Documents  Tools  Forum
It is currently Sun May 12, 2024 6:28 pm

All times are UTC




Post new topic Reply to topic  [ 12 posts ] 
Author Message
 Post subject: Forth sub-forum kick-off
PostPosted: Wed Jul 07, 2004 6:26 am 
Offline
User avatar

Joined: Fri Aug 30, 2002 1:09 am
Posts: 8433
Location: Southern California
[title changed from "Introductions" on 4/20/14 to avoid confusion]

This new section of the forum is for discussing Forth implementations on the 65-family processors. I asked Mike Naberezny to open it up because several of us have been discussing this material privately in E-mail over the last few years, without the benefit of possible contributions from others, and without leaving any archives for others to benefit from either.

On my workbench computer, I'm using an indirect-threaded 65c02 Forth kernel that had its roots back in the public-domain fig-Forth model written by Ragsdale, was picked up by a metacompiler supplier that made small changes to it, and ultimately given a ton of additions and modifications through my own use over the last 14 years. One of my early additions was zero-overhead interrupt service in high-level Forth. It's very simple and does not require setting up another pair of stacks or any of the stuff people usually think is necessary. The article is at http://6502.org/tutorials/zero_overhead ... rupts.html.

I've written an extensive indirect-threaded 65816 Forth assembly source which Wally Daniels is "beta testing." He went for a long time without finding any bugs, but finally found one a couple of weeks ago and just yesterday discovered a problem in DOES> that I'll have to find a way to correct.

Samuel Falvo has been interested in writing a subroutine-threaded '816 Forth and has some great ideas for dictionary hashing and very fast compilation.

It sounds like Bruce Clark has some performance improvements to my UM/MOD article that are waiting to be posted. Since I'm not in a competition, this doesn't bother me at all. If it does the job just as well and can improve the performance of my Forths, terriffic. That's what the website is for.

Additionally, Bruce Clark, Douglas Beattie, Phillip Eaton, and others on the 6502.org forum whose names escape me at the moment have a good head on their shoulders and I look forward to some beneficial discussion.

The 6502 is very becoming of Forth. One write-up I read on implementations of high-level languages said Forth would be entirely impractical on the 6502 because of the 6502's small stack space. The writer must not be experienced in the field. The 6502's hardware stack in page 1 which we use for the return stack, as well as the ZP space for the data stack, are several times as much as you need to run just Forth. (Maybe he was thinking of putting a large array on the stack instead of just the address?) X makes the perfect data stack pointer too, even though it's only 8 bits. Indirect-threaded Forth is extremely memory-thrifty compared to other languages, allowing surprisingly large applications to be run within the 6502's memory space.

Possible topics of discussion that come to mind include:
    threading types
    multitasking
    implementation of extra stacks (floating-point, ANS's control flow stack, etc.)
    algorithms
    ROM-based versus RAM-based kernels
    what to do when the host OS hogs most of ZP
    Forth philosophies and how they relate to the 65 family
    use of macros in assembly source code for Forth kernels
    projects and uses of Forth on 65-family processors
    24- or 32-bit models on the '816
    etc. etc.
Discuss!

_________________
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: Fri Jul 09, 2004 4:40 pm 
Offline

Joined: Sat Jan 04, 2003 10:03 pm
Posts: 1706
GARTHWILSON wrote:
Samuel Falvo (I hope you guys don't mind me using your names-- they'd be on the forum anyway if we had been discussing these things on it) has been interested in writing a subroutine-threaded '816 Forth and has some great ideas for dictionary hashing and very fast compilation.


Cool forum. So . . . where are the donuts?

I should point out that I am brutally masochistic when it comes to Forth implementations. My feeble mind cannot handle much implementation complexity. Hence, all my recent Forth implementations have been MachineForth implementations. Some might therefore call me a devout follower of Chuck Moore. In a sense, they would be right.

Working on my Kestrel project, I now have a MachineForth cross assembler/compiler for my FTS1001 CPU design that is about 50 lines of source long (the file actually has close to 200 lines, but much of it is comments). Porting this same MachineForth compiler to x86 would not be difficult -- the basic structure of it is intended to replace my existing FTS/Forth Cross Compiler, which is already capable of generating statically linked, self-standing Linux executables. Porting it to the 65816 wouldn't be hard either, but I would have to verify the primitives against the 65816 CPU's instruction set to tailor it for best run-time performance. For example, the 65816 makes post-incrementing a memory pointer hard, because you either increment an index register, or you increment a memory pointer. Incrementing an index register is fast, but it requires a pointer to consist of two separate fields (a base pointer and an offset), while the latter is just plain slow. Thus, while primitives like !A and @B can exist, !A+ and @B+ most likely would need to be removed and replaced with alternatives. In their place, I'd include primitives which took advantage of indexing.

It's important to remember that any port of the MachineForth compiler would be its own separate product; by definition, we're working with machine-level resources, and 100% source level compatibility cannot be guaranteed across platforms. I do not believe in one language fits all. Besides, Forth is malleable enough that it's possible to write a compatibility layer for applications written on another Forth environment in small handful of hours, and things just start working. I love it.

There is, of course, a place for more "standard" Forth implementations too. I'm not trying to dissuade their use (I note that my cross assemblers are currently written using GForth, an implementation of ANSI Standard Forth). And for the purposes of LEARNING Forth, I WHOLLY advocate their use. One should not "strike out on their own" like I am until they understand the basic concepts and philosophies behind Forth first.

Anyway, the point of this whole post is two-fold: first, I'm a weirdo when it comes to Forth. I'm out there. Not on the bleeding edge (obviously, as Chuck Moore has already experimented with these concepts), but very clearly not on solid, well-worn turf like most everyone else either. And second, because I'm more daring when it comes to Forth, I have a unique perspective on things which actually can help one understand traditional Forth systems better. Do you have a complex problem that you can't find an easy way to solve? It's possible that I can solve the problem. Maybe the solution isn't as obvious, or as likable, as you might like. But often times, it just takes a different way of looking at things -- a different philosophy.

But I'll get off my soap-box for now. :-)


Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: Sat Jul 31, 2004 10:01 am 
Offline
User avatar

Joined: Tue Mar 02, 2004 8:55 am
Posts: 996
Location: Berkshire, UK
Great idea to add a Forth topic. I've been playing around with the language sinc I got a copy of the August 1980 BYTE magazine on the subject, and Loeliger's book.

I've been working on a new 6502 Forth implementation that meets the ANS standard based on bits of FigForth and a 6809 Camel Forth. As I don't have a real SBC I've been targeting Daryls SBC emulator.

I hate writing multiply and divide primitives so I'll be borrowing Garth's UM/MOD from the library.

_________________
Andrew Jacobs
6502 & PIC Stuff - http://www.obelisk.me.uk/
Cross-Platform 6502/65C02/65816 Macro Assembler - http://www.obelisk.me.uk/dev65/
Open Source Projects - https://github.com/andrew-jacobs


Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: Thu Jul 21, 2005 11:58 pm 
Offline

Joined: Wed Jul 20, 2005 11:08 pm
Posts: 53
Location: Hawaii
BitWise wrote:
I hate writing multiply and divide primitives so I'll be borrowing Garth's UM/MOD from the library.


I don't just hate writing primitives. If at all possible, I avoid the hard work.

In a Forth system I'm writing, about 10% of the code is borrowed from others. (For instance,
Code:
2OVER
is
Code:
>R >R 2DUP R> R> 2SWAP
, guess which one this comes from (hint: it starts with an e and a Forth))

_________________
Sam

---
"OK, let's see, A0 on the 6502 goes to the ROM. Now where was that reset vector?"


Top
 Profile  
Reply with quote  
PostPosted: Fri Aug 03, 2012 6:50 pm 
Offline
User avatar

Joined: Fri Aug 30, 2002 1:09 am
Posts: 8433
Location: Southern California
2OVER in '816 Forth is just:
Code:
        DEX
        DEX
        DEX
        DEX
        LDA  8,X
        STA  0,X
        LDA  $A,X
        STA  2,X

Much faster, and, I think, easier too. There were so many things that were easier to write as primitives when I did my 65816 Forth. The '816 really is easier to program.

_________________
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 Apr 19, 2014 10:07 pm 
Offline
User avatar

Joined: Sun Jun 30, 2013 10:26 pm
Posts: 1929
Location: Sacramento, CA, USA
Yet another bump ...

As a Forth n00b, I have much better luck understanding Garth's code than asmlang_6's, but that's my own shortcoming. Am I to understand that 2OVER is the equivalent of
Code:
3 PICK 3 PICK

??? aka (on my 65m32)
Code:
        sta  ,-x
        lda  3,x
        sta  ,-x
        lda  3,x

The reason that I ask is because I need to understand the benefits and/or costs of branching from the inside of one primitive to another in an ITC implementation. Does this have the potential for causing problems during the execution of non-trivial programs that make references to to the CFA and NFA? For example, if I point the CFA of one word "A" straight into the code field of another word "B", does that invite trouble over the alternative of keeping a simple "JMP B+1" or "JMP (B)" in the code field of "A"?

Tryin to learn,

Mike


Last edited by barrym95838 on Sun Apr 20, 2014 12:33 am, edited 1 time in total.

Top
 Profile  
Reply with quote  
PostPosted: Sat Apr 19, 2014 10:45 pm 
Offline
User avatar

Joined: Fri Aug 30, 2002 1:09 am
Posts: 8433
Location: Southern California
barrym95838 wrote:
Am I to understand that 2OVER is the equivalent of
Code:
3 PICK 3 PICK

That's it.

Quote:
The reason that I ask is because I need to understand the benefits and/or costs of branching from the inside of one primitive to another in an ITC implementation.

I do it frequently. Although Forth doesn't have a GOTO (prefering structure instead), you can do anything you want in the assembly language to make the innards as efficient as possible.

Quote:
Does this have the potential for causing problems during the execution of non-trivial programs that make references to to the CFA and NFA? For example, if I point the CFA of one word "A" straight into the code field of another word "B", does that invite trouble over the alternative of keeping a simple "JMP B+1" or "JMP (B)" in the code field of "A"?

I can't think of an example where I actually jumped from inside an already running A, to B+1 (or B+2 in the case of the 6502/816, not m32), but having the CFA of A just point to the PFA of B (a primitive) is common. IOW, A doesn't have any code of its own. It just refers you elsewhere. Take for example the constant 0 which is like a primitive whose CFA just points to PUSH_FALSE which puts a 0 on the stack. It runs faster than a normal CONSTANT and takes a couple bytes less memory to define. (PUSH_FALSE is not a Forth word but a ML routine that many Forth words jump to to finish up, in 6502/816 Forth.) Another example is CELLS whose CFA points to the PFA of 2*. 2*'s code, for the '816, is just ASL 0,X, JMP NEXT. CELLS and 2* take the same number of clock cycles, because their CFAs point to the same code. There are several of these.

_________________
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 Apr 19, 2014 10:48 pm 
Offline

Joined: Tue Jan 07, 2014 8:40 am
Posts: 91
barrym95838 wrote:
Am I to understand that 2OVER is the equivalent of
Code:
3 PICK 3 PICK



I hate to say this, but the action of PICK depends on the Forth you're using. In ANS Forth, 0 PICK is equivalent to DUP, and 1 PICK is equivalent to OVER. So in that case, yes, 2OVER would be equivalent to 3 PICK 3 PICK. Its stack effect is ( a b c d -- a b c d a b )


Quote:
For example, if I point the CFA of one word "A" straight into the code field of another word "B", does that invite trouble over the alternative of keeping a simple "JMP B+1" or "JMP (B)" in the code field of "A"?


For an indirect threaded Forth, that's an acceptable practice. For compilation and execution, what matters is that the CFA is the address of some machine code somewhere.

There are some "decompilers" that identify CODE words as those having machine code in their parameter field. Such a decompiler might conclude that your word is a "defined" word (a child of CREATE..DOES>), because (a) the machine code is located somewhere else, and (b) that machine code isn't one of the core actions like DOCOLON, DOVAR, DOCON, etc. But that's what is called an "implementation dependency"; Standard Forth programs can't count on it.

_________________
Because there are never enough Forth implementations: http://www.camelforth.com


Top
 Profile  
Reply with quote  
PostPosted: Thu Oct 18, 2018 10:48 pm 
Offline

Joined: Fri May 05, 2017 9:27 pm
Posts: 858
barrym95838 wrote:
The reason that I ask is because I need to understand the benefits and/or costs of branching from the inside of one primitive to another in an ITC implementation.

In my Forth kernel I have a few cases where a high level word branches into another high level word. It's not standard practice, but it was done for the sake of efficiency.

Cheers,
Jim


Top
 Profile  
Reply with quote  
PostPosted: Thu Oct 18, 2018 11:06 pm 
Offline

Joined: Fri May 05, 2017 9:27 pm
Posts: 858
Brad R wrote:
Quote:
For example, if I point the CFA of one word "A" straight into the code field of another word "B", does that invite trouble over the alternative of keeping a simple "JMP B+1" or "JMP (B)" in the code field of "A"?


For an indirect threaded Forth, that's an acceptable practice. For compilation and execution, what matters is that the CFA is the address of some machine code somewhere.

In my kernel, I've pointed the CFA of one word into the body of a primitive.
Quote:
There are some "decompilers" that identify CODE words as those having machine code in their parameter field. Such a decompiler might conclude that your word is a "defined" word (a child of CREATE..DOES>), because (a) the machine code is located somewhere else, and (b) that machine code isn't one of the core actions like DOCOLON, DOVAR, DOCON, etc. But that's what is called an "implementation dependency"; Standard Forth programs can't count on it.

My decompiler ( SEE ) concludes that such a word is the child of a CREATE ;CODE word, but it will disassemble the code pointed to by the CFA of such a word if the variable PARENT has a value of TRUE. For example, NOOP is a do nothing word. It's CFA points to NEXT.
Code:
SEE NOOP
NOOP
 A3A ;CODE NEXT
  83F    1  # LDY
  841   FB )Y LDA IP
  843   FF    STA  W 1+
  845         DEY
  846   FB )Y LDA IP
  848   FE    STA  W
  84A         CLC
  84B   FB    LDA IP
  84D    2  # ADC
  84F   FB    STA IP
  851  856    BCS
  853   FD    JMP  W 1-
  856   FC    INC IP 1+
  858   FD    JMP  W 1-
 OK

If the value in PARENT is FALSE, the display is not so detailed.
Code:
PARENT OFF  OK
SEE NOOP
NOOP
 A3A ;CODE NEXT
  83F OK


Top
 Profile  
Reply with quote  
PostPosted: Thu Oct 18, 2018 11:19 pm 
Offline
User avatar

Joined: Sun Jun 30, 2013 10:26 pm
Posts: 1929
Location: Sacramento, CA, USA
JimBoyd wrote:
Code:
SEE NOOP
NOOP
 A3A ;CODE NEXT
  83F    1  # LDY
  841   FB )Y LDA IP
  843   FF    STA  W 1+
  845         DEY
  846   FB )Y LDA IP
  848   FE    STA  W
  84A         CLC
  84B   FB    LDA IP
  84D    2  # ADC
  84F   FB    STA IP
  851  856    BCS
  853   FD    JMP  W 1-
  856   FC    INC IP 1+
  858   FD    JMP  W 1-
 OK

Maybe I'm just feeling goofy today, but your assembler/disassembler notations are starting to grow on me (in a good way). How does your disassembler know that FD is W 1- instead of IP 2+ or a thousand other possibilities?

_________________
Got a kilobyte lying fallow in your 65xx's memory map? Sprinkle some VTL02C on it and see how it grows on you!

Mike B. (about me) (learning how to github)


Top
 Profile  
Reply with quote  
PostPosted: Fri Oct 19, 2018 9:17 pm 
Offline

Joined: Fri May 05, 2017 9:27 pm
Posts: 858
barrym95838 wrote:
Maybe I'm just feeling goofy today, but your assembler/disassembler notations are starting to grow on me (in a good way). How does your disassembler know that FD is W 1- instead of IP 2+ or a thousand other possibilities?

Strings. Seriously, there is a defining word AMONG that builds a list of numbers. The list is terminated with zero. AMONG is used in about three other places in the decompiler. The child word takes a number from the stack and returns the index into the list if it is found or -1 if it is not. [Edit: Zero is a valid index.] The index is used as the index into a string array for the names. The string array word is defined and used like this code for i/o error codes ( for the C64 ).
Code:
// from the kernel
HEX
: SARRAY  ( -- )
   CREATE
   DOES>  ( U -- )
      SWAP 0
      ?DO  COUNT +  LOOP
      $? ;
// used as
SARRAY SIOERR  ( U -- )
   ," TOO MANY OPEN FILES"
   ," FILE ALREADY OPEN"
   ," FILE NOT OPEN"
   ," FILE NOT FOUND"
   ," DEVICE NOT PRESENT"
   ," NOT INPUT FILE"
   ," NOT OUTPUT FILE"
   ," MISSING FILE NAME"
   ," ILLEGAL DEVICE NUMBER"
   ," UNKNOWN ERROR"
: IOERR  ( U -- )  ?DUP 0EXIT
   1- 9 UMIN WHERE CR SIOERR
   ABORT ;

," compiles a counted string and $? is just:
Code:
: $?  ( ADR -- )  COUNT TYPE ;

Including SARRAY in the kernel saved memory over the alternative of testing the error number several times as in:
Code:
   DUP 1 = ABORT" TOO MANY OPEN FILES"
   DUP 2 = ABORT" FILE ALREADY OPEN"
        .
        .
        .
   <etc>

Here is AMONG
Code:
: AMONG  ( -- )  CREATE
   DOES>  ( W -- U)
      DUP>R
      BEGIN
         2DUP @ ?DUP
      WHILE
         = IF
            NIP R> - 2/ EXIT
         THEN
         2+
      REPEAT
      R> 2DROP <> ;

And here are the relevant tables in the decompiler.
Code:
HEX
SARRAY LABEL  ( U -- )
   ," POPTWO" ," POP" ," SETUP"
   ," PUSH" ," PUT" ," NEXT"
   ," IP" ," IP 1+" ," XSAVE"
   ," UP" ," UP 1+" ,"  W 1-"
   ,"  W" ,"  W 1+" ,"  N 1-"
   ,"  N" ,"  N 1+" ,"  N 2+"
   ,"  N 3 +" ,"  N 4 +" ,"  N 5 +"
   ,"  N 6 +" ,"  N 7 +"
   ," APUSH" ," NEXT 2+"

HEX
AMONG ADDRESSES  ( W -- U )  ASSEMBLER
   POPTWO ,    POP ,  SETUP ,
     PUSH ,    PUT ,   NEXT ,
       IP ,  IP 1+ ,  XSAVE ,
       UP ,  UP 1+ ,   W 1- ,
        W ,   W 1+ ,   N 1- ,
        N ,   N 1+ ,   N 2+ ,
    N 3 + ,  N 4 + ,  N 5 + ,
    N 6 + ,  N 7 + ,
    APUSH ,  NEXT 2+ ,
    0 ,
FORTH

The decompiler takes the operand and checks if it is in ADDRESSES. If it is, the decompiler prints the corresponding string.


Top
 Profile  
Reply with quote  
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 12 posts ] 

All times are UTC


Who is online

Users browsing this forum: No registered users and 6 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: