Getting started in Forth

Topics relating to various Forth models on the 6502, 65816, and related microprocessors and microcontrollers.
User avatar
GARTHWILSON
Forum Moderator
Posts: 8775
Joined: 30 Aug 2002
Location: Southern California
Contact:

Post by GARTHWILSON »

Quote:
I am guessing you're using this on a 64k 65C816 which ignores the bank byte.
Actually, a 65802. I guess I better check into that more when I go to more than bank 0. I was able to be kind of careless, I suppose.
User avatar
8BIT
Posts: 1787
Joined: 30 Aug 2002
Location: Sacramento, CA
Contact:

Post by 8BIT »

GARTHWILSON wrote:
...Again, one of the best books for getting started in Forth is Leo Brodie's humorous book "Starting Forth" which you can read online, free, at http://www.forth.com/starting-forth/index.html .
I just finished this book. I found it easy to read and the examples were clear. The problems at the end of each chapter (with answers) were a great way to help explore the topics.

I would recommend this to anyone just starting out with Forth.

Now I intend to dissect FigFORTH with the hopes of understanding its inner-workings better.

Daryl
User avatar
GARTHWILSON
Forum Moderator
Posts: 8775
Joined: 30 Aug 2002
Location: Southern California
Contact:

Post by GARTHWILSON »

Quote:
I just finished this book. I found it easy to read and the examples were clear. The problems at the end of each chapter (with answers) were a great way to help explore the topics.
I remember my own journey into Forth, but I would be interested to hear someone else's thoughts (yours in this case) on various aspects of Forth while you're still pretty new to it, to find out how we can be more effective at helping others to successfully get into it.
User avatar
8BIT
Posts: 1787
Joined: 30 Aug 2002
Location: Sacramento, CA
Contact:

Post by 8BIT »

GARTHWILSON wrote:
... I remember my own journey into Forth, but I would be interested to hear someone else's thoughts (yours in this case) on various aspects of Forth while you're still pretty new to it, to find out how we can be more effective at helping others to successfully get into it.
I spent two+ years on college using an HP-41CV so the whole stack-based math was easy for me to grasp. The structure is also pretty easy - you just have to keep the "backward" order in mind. The IF ELSE THEN structure makes sense, but as someone commented elsewhere, the word THEN could be better named (too much time in BASIC and C).

One principle that has caused some internal struggle is the idea of keeping word definitions short and having a lot of them. I struggle with that as I see Forth could be spending as much time moving from word to word as it does performing the word's operation. Kind of equivalent to having too many JSR's in your assembly language code. That's one reason I gravitate towards assembly for most of my code (6502 and AVR).

Since the disk I/O in FigFORTH does not work as is, I implemented the RAM disk workaround for use in the Kowalski Simulator. But without an editor, it's pretty limited. I also find the Simulator really loads up my CPU, with the internal fans all running up to full speed while the Simulator is running. I switched to a Windows Forth for the bulk of the Getting Started book work.

I will play more the FigFORTH on my SBC-4P. At least on that, I can exit to the monitor and look "under the hood" at what's going on.

I plan to spent more time with console and disk I/O operation to get a better feel for how to best use those as well.

I'm not sure if I should plan on using the "screen/block/buffer" method or instead plan on implementing an "include text file" approach that more modern Forth's seem to use. Again, I have a lot more research to do.

Eventually, I may try some hardware I/O (SPI, RS-232, Ethernet, Video) along with some IRQ experiments.

I would encourage anyone who is curious to explore Forth for themselves. There are several free Forth environments available along with free documentation. The biggest investment will be your time.

Daryl
User avatar
GARTHWILSON
Forum Moderator
Posts: 8775
Joined: 30 Aug 2002
Location: Southern California
Contact:

Post by GARTHWILSON »

8BIT wrote:
I spent two+ years on college using an HP-41CV so the whole stack-based math was easy for me to grasp.
That helps. I started with HP4-1cx experience, and you've no doubt seen my related pictures. Forth of course takes the stack thing much further.
Quote:
The structure is also pretty easy - you just have to keep the "backward" order in mind. The IF ELSE THEN structure makes sense, but as someone commented elsewhere, the word THEN could be better named (too much time in BASIC and C).
Yeah, it's
<Is condition true?>
<IF so, do this>
<ELSE, do that>
<THEN when you're done, pick up here>
Quote:
One principle that has caused some internal struggle is the idea of keeping word definitions short and having a lot of them. I struggle with that as I see Forth could be spending as much time moving from word to word as it does performing the word's operation. Kind of equivalent to having too many JSR's in your assembly language code.
I have a bit of an issue with some people's insistance on keeping them that short too, the major issue being that it does not really make things clear if you factor out things that you can't even give a descriptive name. And yes, it does cut performance a bit, and if you're compiling with headers, all those headers take up a lot more memory too. I wrote an article on Forth readability for Forth Dimensions when the magazine was in print. One man responded with a letter to the editor saying my definitions were entirely too long. Later however, he and I corresponded on another subject, and he sent me some code where one of his definitions was about 100 lines!
Quote:
That's one reason I gravitate towards assembly for most of my code (6502 and AVR).
You can use it where you need the speed or control over something like the interrupt-disable processor flag, but you'll develop the application much faster and with very little if any speed penalty if you do most of it in Forth and use assembly only for a few small critical places. You can even put a little assembly inside a colon definition with Forth before and after it (if you don't want to factor it out and make it a primitive, which again I don't think is always justified).
Quote:
I'm not sure if I should plan on using the "screen/block/buffer" method or instead plan on implementing an "include text file" approach that more modern Forth's seem to use. Again, I have a lot more research to do.
I worked with screen files for a little while and it drove me nuts. Inserting lines and trying to move stuff around are the first things that come to mind. I'm all text source code files now. Screen files have a couple of advantages, but more serious disadvantages. I can see why they were used in the early years when technology was more limited, but there's not really any compelling reason to anymore.
Quote:
Eventually, I may try some hardware I/O (SPI, RS-232, Ethernet, Video) along with some IRQ experiments.
My article on servicing interrupts in high-level Forth with zero overhead is at http://6502.org/tutorials/zero_overhead ... rupts.html .
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
8BIT
Posts: 1787
Joined: 30 Aug 2002
Location: Sacramento, CA
Contact:

Post by 8BIT »

GARTHWILSON wrote:
My article on servicing interrupts in high-level Forth with zero overhead is at http://6502.org/tutorials/zero_overhead ... rupts.html .
I've already read that one and will use it as reference when I get to that point!

thanks!

Daryl
User avatar
JeeK
Posts: 18
Joined: 14 Aug 2012
Location: Austria - Vienna
Contact:

Re:

Post by JeeK »

dclxvi wrote:
GARTHWILSON wrote:

Code: Select all

         HEADER "0branch", NOT_IMMEDIATE
0branch: PRIMITIVE
         INX2
         LDA   FFFE,X
         BEQ   branch+2
          .
          .
          .
By the way, you might want to make that $FFFFFE,X (i.e. long,X addressing) since abs,X will cross bank boundaries, so this will read from bank 1 (assuming the DBR is 0). I am guessing you're using this on a 64k 65C816 which ignores the bank byte.
OMG, I should read old threads more accurate ... trapped into this while porting Garth's Forth to C64 SuperCPU with a real 65816 ...
The long absolute variant went not into my mind ...

I found three places: ?EXIT, ?LEAVE and the mentioned 0BRANCH.
The way I solved this is based on reordering the code. I just used the faster 0,X for the (small, IMHO) cost to duplicate INX_INX. The reuse of code has been reversed. Considering 0BRANCH, BRANCH's CFA points to the branch code of 0BRANCH and in that way it's not a real primitive anymore from structural point of view.

(originally in C32 format, I transcoded the source into a Tass64 format)

Code: Select all

        #HEADER "branch", NOT_IMMEDIATE          ; ( -- )
branch: .WORD   branchcode
 ;-------------------
         #HEADER "0branch", NOT_IMMEDIATE        ; ( n -- )
Zbranch: #PRIMITIVE
;
; only on 65802 (64K wrap-around)
;       #INX_INX
;       LDA     $FFFE,X         ; Get the value that was at TOS before INX_INX .
;       BEQ     branchcode      ; Do the branch if TOS was 0.
;
; fixed for 65816, no bank wrapping!
        LDA      0,X
        BEQ      dbranch                ; Do the branch if TOS was 0.
        #INX_INX                        ; drop and bump
bump:   LDA     G.IP              ; bump (advance) the instruction pointer by two
        #INA_INA                 ; LDA, INA, INA, STA  is faster than  INC INC.
        STA     G.IP
        #GO_NEXT
dbranch:
        #INX_INX                        ; drop
branchcode:                             ; Set the G.IP to the absolute addr
        LDA     (G.IP)                  ; pointed to by the cell following the
        STA     G.IP                    ; execution token of branch. It's faster
        #GO_NEXT                        ; this way not making it relative.

Code: Select all

        #HEADER "leave", NOT_IMMEDIATE   ; ( -- )
USleave: .WORD  USleavecode               ; leave is compiled by LEAVE .
 ;-------------------
        #HEADER "?leave", NOT_IMMEDIATE  ; ( f -- )
QM_leave: #PRIMITIVE              ; QM_leave is compiles by QMLEAVE
;
; only on 65802 (64K wrap-around)
;       #INX_INX
;       LDA     $FFFE,X         ; Get the value that was at TOS before INX_INX .
;       BNE     USleavecode      ; If not 0, then do the same as USleave does.
;
; fixed for 65816, no bank wrapping!
        LDA     0,X
        BNE     doleave         ; If not 0, then do the same as USleave does.
        #INX_INX                ; drop TOS
        #GO_NEXT
doleave:
        #INX_INX                ; drop TOS
USleavecode:
        .AL
        LDA     #$FFFF
        STA     LOOP_LEAVEdata  ; Show that LEAVE was taken,
        BRA     lv_lp           ; then end the same way as when a loop finishes.

Code: Select all

        #HEADER "?EXIT", NOT_IMMEDIATE           ; ( f -- )      IF R> DROP THEN
QMEXIT:  #PRIMITIVE
;
; only on 65802 (64K wrap-around)
;       #INX_INX
;       LDA     $FFFE,X         ; Get the value that was at TOS before INX_INX .
;       BNE     unnestcode      ; If not 0, then do the same as unnest does.
;
; fixed for 65816, no bank wrapping!
        LDA     0,X
        BEQ     doexit
        #INX_INX                         ; Drop
        #GO_NEXT
doexit:
        #INX_INX                         ; Drop
unnestcode:
        PLA                                     ; nest, and the same as EXIT.
        STA     G.IP                              ; It is often called SEMIS
        #GO_NEXT                                 ; because it's compiled by ;
Johann
Post Reply