Re: Tali Forth for the 65c02
Posted: Mon Mar 17, 2025 6:26 pm
Hi @adrianhudson, I'm happy to hear you are programming in Forth. While Tali doesn't have an RDROP word (you could write one!), it does have R> and DROP which will transfer data from the return stack to the data stack, and then discard it. This can be used to return to the word before the word that called this one with some caveats:
Tali's native compiler will get in your way. For this to work properly, you need each word to be compiled as a JSR. To make that happen, you can either:
set nc-limit to zero like so: This has the downside of compiling ALL words as JSRs, and that's not as fast as inlining them when they are small.
or you can simply mark the words in question with never-native. This goes just after you finish defining a new word, and it marks that word in the dictionary to always be compiled as a JSR (and never "native", which is Tali's term for when it inlines the assembly code instead of using a JSR). Here's a simple example of a word returning to a grandparent word:
and an example of running this code:
You can use see to investigate each word, eg. see parent gives:
Note the NN flag is set here - that makes Tali always compile this word as a JSR, so it's possible to mess with the return addresses on the return stack. You can also see the 80A jsr is a jsr to the child word - it's compiled as a jsr because that word is also marked never-native.
If you're wondering about the lda.# and unnamed JSR in there, that's the CR word, which loads $A (the CR character) into the A register and calls a function (which does not have a Forth name) to print it out.
Tali's native compiler will get in your way. For this to work properly, you need each word to be compiled as a JSR. To make that happen, you can either:
set nc-limit to zero like so:
Code: Select all
0 nc-limit !or you can simply mark the words in question with never-native. This goes just after you finish defining a new word, and it marks that word in the dictionary to always be compiled as a JSR (and never "native", which is Tali's term for when it inlines the assembly code instead of using a JSR). Here's a simple example of a word returning to a grandparent word:
Code: Select all
: child ." going back to grandparent" cr
r> drop ; never-native
: parent child ." This shouldn't print" cr ; never-native
: grandparent ." Starting main word.. " cr
parent
." Back in main word." cr ;
Code: Select all
grandparent Starting main word..
going back to grandparent
Back in main word.
okCode: Select all
nt: 83E xt: 848 header: 40 06 00 24
flags: HC 0 NN 1 AN 0 IM 0 CO 0 DC 0 LC 0 FP 0 | UF 0 ST 0
size (decimal): 36
0848 20 0A 08 20 3B A2 14 00 54 68 69 73 20 73 68 6F .. ;... This sho
0858 75 6C 64 6E 27 74 20 70 72 69 6E 74 20 A8 94 A9 uldn't p rint ...
0868 0A 20 54 86 . T.
848 80A jsr child
84B A23B jsr SLITERAL 14 This shouldn't ...
864 94A8 jsr type
867 A lda.#
869 8654 jsr
okIf you're wondering about the lda.# and unnamed JSR in there, that's the CR word, which loads $A (the CR character) into the A register and calls a function (which does not have a Forth name) to print it out.