6502.org Forum  Projects  Code  Documents  Tools  Forum
It is currently Sat May 11, 2024 11:31 pm

All times are UTC




Post new topic Reply to topic  [ 5 posts ] 
Author Message
PostPosted: Sat Mar 12, 2022 5:23 pm 
Offline

Joined: Thu Jan 21, 2016 7:33 pm
Posts: 269
Location: Placerville, CA
Not strictly 6502-related, but this place is the best collection of brains I have to pick on the subject ;) I have a running project to develop a stack-oriented homebrew CPU (details here and here, if you want 'em,) and now that I have a mostly-functional simulator for the architecture, naturally enough I'm trying to develop a Forth implementation for it. Figure I may as well create a standing thread for this; I only have the one real question at the moment, but I'm sure I'll have others down the line...

So I've browsed over Brad Rodriguez's "Moving Forth" a few times in the past as I try to wrap my head around how Forth works on an internal level, and I'm back to working through it as I try to roll up some sample code for this project to evaluate my own design decisions. I'm currently looking at the part where he explains DOES> - he makes a fair production out of it, and it seems to me like it's maybe not as complicated as all that, but on the other hand I'm not 100% sure I've got it, either. Seems to me, if I'm following it all correctly, that all the DODOES routine really is is a way for a common "handler" routine invoked by a class of words to get the "return address" - in other words, the address of the parameter field for any specific word invoking that handler - pushed onto the parameter stack, no?

Because if that's all it is, this becomes fairly trivial. I'm using an STC model, since the CPU architecture is designed around that, and based on Rodriguez's example, the DODOES subroutine could be implemented like so:
Code:
   CTD      ; Pop top-of-return-stack to the parameter stack
   ; ( -- dodoes-return )
   CTD      ; Pop next item from return stack to parameter stack
   ; ( -- dodoes-return handler-return )
   SWN      ; Swap parameter-stack top and next items
   ; ( -- handler-return dodoes-return )
   JMP      ; Jump indirect to @TOS (return from DODOES)
   ; ( -- handler-return )

Better yet, if I'm understanding it correctly, it could be inlined as a single CTD instruction (popping the parameter-field address to the parameter stack and leaving only the parent-thread return address on the return stack.) But, as I said, I'm not 100% clear on whether I am understanding this all correctly, plus I've seen some comments 'round here about the whole DOES> thing being both simpler and yet a little trickier than it looks in STC models since there's no distinction between the code and parameter fields...? Curious to know if I've grasped this properly or not; I've looked at the standard documentation, but it gives a whole lot of what and not a lot of why.


Top
 Profile  
Reply with quote  
PostPosted: Sun Mar 13, 2022 4:56 am 
Offline
User avatar

Joined: Sun Jun 30, 2013 10:26 pm
Posts: 1929
Location: Sacramento, CA, USA
Dr. Brad's Moving Forth Part 3 hints that once you fully understand defining words, the rest is a walk in the park. I don't understand your assembly language example, so I'll just whip out my own foreign example, from my imaginary DTC FORTH for my imaginary 65m32 (a=dTOS, y=IP, x=rSP, s=dSP):
Code:
                 `  168 `-------------------------------------------------------------- dodoes
                 `  169 dodoes_: ` (  -- a )( R:  -- a ) code action of DOES> clause
                 `  170 ` Entered by            ...
                 `  171 `                  jsr fragment
                 `  172 `                 .dcw parameter field
                 `  173 `                       ...
                 `  174 `        fragment: jsr dodoes_
                 `  175 `                 .dcw high-level thread
                 `  176 ` Enters high-level thread with address of parameter field on TOS
                 `  177 `  (internal code fragment, not a Forth word)
00000046:9102c000`  178     sly ,-x         ` push old IP to R:, IP = new HLA from caller's
00000047:da054000`  179     exa ,s          `   "jsr dodoes_", TOS = PFA from "jsr fragment"
00000048:ae018000`  180     lde ,y+         ` aka jmp (,y+) aka NEXT
I used Dr. Brad's article to make this, but I have no way to test it because I'm a FORTH novice and my simulator still hasn't made it through its first compile. Maybe an advanced FORTHer here can provide a relatively simple but free-standing example use case that we can hand-simulate to see if either, both or neither of us are on the right track.

I can't find it at the moment, but I recently read somewhere [edit: here] that Dr. Bruce had a broken dodoes that he hadn't fixed yet, so there's some deceptive trickiness in the concept.

_________________
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)


Last edited by barrym95838 on Mon Mar 14, 2022 6:40 pm, edited 2 times in total.

Top
 Profile  
Reply with quote  
PostPosted: Sun Mar 13, 2022 7:46 am 
Offline
User avatar

Joined: Fri Aug 30, 2002 1:09 am
Posts: 8433
Location: Southern California
At risk of muddying the waters with ITC DOES>:

John, if I'm understanding you correctly (which I might not be), that's not quite it—although I have not thought about how STC would work contrasted to my ITC. Here's what I have, which I think I tested many years ago:
Code:
 COMPILE-TIME AND RUN-TIME BEHAVIOR OF DOES> and does> :

                                                                      (calling
                           (parent)                                      word)

                            HEADER              (child)                   bla
                             nest                                         bla
                            CREATE               HEADER       W           bla
                              bla         ┌──── code field <──────────────CHILD
                              bla         │    param field         IP───> bla
                              bla         │         .                     bla
 DOES> compiles ;code and    ;code        │         .                     bla
   the JSR does here, plus   JSR does <───┘         .
   a 00 byte.  ;code makes   nul byte
   the CFA of the child       bla       The code following the nul byte is in
   word point to the JSR      bla       high-level Forth.
   does instruction.          bla
                            unnest


 does is a runtime routine, like const or nest (not a Forth word).  It must:

 1. put the child's PFA on the data stack.

 2. change W to make it look like Forth execution came from this part of the
    parent word and will continue in the parent word.  Since now the child's
    PFA has been put on the stack, neither W nor IP need to keep any child
    addresses.

 ;-------------------

: DOES>         ( -- )                                        \      SF262-264
   ?COMP
   COMPILE ;code
   20 C,    ['] does ,              \ ($20 is the op code for JSR.)  Then a
    0 C,        ;       IMMEDIATE   \ null alignment byte after the 3-byte JSR
and the '816 assembly language is:
Code:
 COMMENT
   DOES> is an immediate word that runs when the parent is being defined.  It
   compiles ;code into the parent, followed by JSR _does.  Since the JSR is a
   3- byte instruction and I'd like to have the following Forth CFAs
   word-aligned, DOES> also leaves a nul byte after the JSR instruction.  This
   works out nicely for subroutine _does, because it eliminates the need to
   decrement what you pull off the stack before storing it in W.

   Although a JSR is used to jump to _does, it's not really a subroutine.  The
   JSR is needed to save the address you came from so Forth knows where to
   resume execution.

   At the final run time, the parent's final unnest pops the old IP off the
   return stack so high-level Forth execution can finally resume in the code
   that had called the child word.
 END_COMMENT


_does:  LDA     W                       ; Put child's PFA on the stack.
        INA2
        DEX2
        STA     0,X

        PLA                             ; Get ready to start execusion of high-
        STA     W                       ; level Forth in the parent word.
        JMP     nest
 ;-------------------
        HEADER "DOES>", IMMEDIATE               ; ( -- )
DOES:   DWL     nest, ?COMP
        DWL     COMPILE, _scode
        DWL     BL, Ccomma              ; ┐ Compile JSR does
        DWL     lit, _does, COMMA       ; ┘
        DWL     ZERO, Ccomma            ; Add a nul alingment byte after the
        DWL     unnest                  ;                            3-byte JSR.
 ;-------------------

_________________
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: Sun Mar 13, 2022 9:28 pm 
Offline

Joined: Wed Aug 21, 2019 6:10 pm
Posts: 217
Yes, DODOES is not so tricky in a subroutine threaded Forth in a system with normal return vectors... you should enter DODOES with ( R: ... PFA XT_Created_Word ) on the return stack, so get the PDA to the top of the data stack and branch to the DOES> compiled code and you are good.

Where debugging a broken CREATE DOES> system is sometimes harder is sorting out whether you have messed up the DOES> compilation or the DODOES code. The CREATE part can be tested incrementally, but DOES> and DODOES are a system, and so it helps to know how the compiled DOES> should look so you can be sure the problem is not somewhere in the DOES> compilation process itself.

Or at least, when I have time to debug xForth's broken DOES> system, that's the plan.


Top
 Profile  
Reply with quote  
PostPosted: Thu May 05, 2022 2:26 am 
Offline

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

Two threads discussing CREATE DOES> are here and here.
Scot W. Stevenson's Tali Forth is an STC Forth.


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

All times are UTC


Who is online

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