Page 7 of 19
Re: Introducing Tali Forth for the 65c02 (ALPHA)
Posted: Mon Mar 05, 2018 7:28 am
by scotws
I had copied and pasted the word into Gforth, which did just fine, so it's definitely some problem with Tali somewhere. I'm wondering if the gods of computing are trying to tell me that I should finally switch from 0BRANCH/BRANCH to CS-ROLL/CS-PICK ...
(The space after twenty just makes sure the string doesn't run into the next number, though it does look weird. The balance is okay because of the DUP -- IF always eats one I and . (that's DOT) always prints the other.)
I'm assuming there is one stupid one-byte-off mistake somewhere. Will try to see this evening if Tali 1 has the same problem first, which would make it more fundamental.
Re: Introducing Tali Forth for the 65c02 (ALPHA)
Posted: Mon Mar 05, 2018 4:07 pm
by barrym95838
... The balance is okay because of the DUP -- IF always eats one I and . (that's DOT) always prints the other.)
... except that when I is 20
." is executed
instead of
. which would leave the duped 20 on the stack because
." doesn't consume it, right?
Mike B.
P.S. Where is your control stack, BTW? I haven't dug deeply enough to know yet.
A.3.2.3 does a very thorough job of explaining what you should be doing, but it's at the limit of my abilities to fully grok.
Re: Introducing Tali Forth for the 65c02 (ALPHA)
Posted: Mon Mar 05, 2018 7:16 pm
by GARTHWILSON
There's no ELSE or UNLOOP or EXIT or LEAVE or anything that wold keep . from getting executed.
Re: Introducing Tali Forth for the 65c02 (ALPHA)
Posted: Mon Mar 05, 2018 8:39 pm
by scotws
Well, the inside of the loop looks sort of like this:
Code: Select all
i ( u )
dup ( u u )
20 ( u u 20 )
= ( u f )
if ." twenty " then ( u )
. ( )
The whole
IF/THEN construct doesn't touch the stack, so the number gets passed on; the
." twenty " just prints "twenty", but doesn't touch the stack (well, stuff happens in the background, but it all cancels out).
At the moment, Tali uses the old
0BRANCH and
BRANCH structures from FIG Forth, and the command stack is the Return Stack, thanks to some code magic suggested by Garth. What I probably should do is implement
CS-ROLL and
CS-PICK using the Data Stack ... having old FIG stuff in what is supposed to be an ANSI Forth is sort of cheating

.
Re: Introducing Tali Forth for the 65c02 (ALPHA)
Posted: Mon Mar 05, 2018 9:09 pm
by scotws
So, it seems that the issue was a stupid typo while copying the routine from TF1 to TF2, which was pretty clear once I found that Tali Forth 1 didn't show the same issue. Will test various incarnations to make sure it's gone, though.
Re: Introducing Tali Forth for the 65c02 (ALPHA)
Posted: Tue Mar 06, 2018 2:42 am
by barrym95838
There's no ELSE or UNLOOP or EXIT or LEAVE or anything that wold keep . from getting executed.
Ah, got it. Please excuse my ignorance.
Mike B.
Re: Introducing Tali Forth for the 65c02 (ALPHA)
Posted: Tue Mar 06, 2018 8:30 am
by scotws
There's no ELSE or UNLOOP or EXIT or LEAVE or anything that wold keep . from getting executed.
Please excuse my ignorance.
Don't worry, I've given up pretending I'm clever enough to write, let alone read, Forth without stack comments after every single word; I condense it somewhat later, but Forth is always a humbling experience.
This is good example of a line that should be broken into two words anyway:
Code: Select all
: .twenty ( u -- ) 20 = if ." twenty " then ;
followed by
Code: Select all
: aaa ( -- ) 100 10 do i dup .twenty . loop ;
which is a lot clearer.
(Where I still totally suck are loops, which still tend to have a rather Pythonic appearance when I write them; I know that mentally, I'm trying to build something with
BREAK and
CONTINUE, which Forth simply doesn't have ...)
Re: Introducing Tali Forth for the 65c02 (ALPHA)
Posted: Tue Mar 06, 2018 10:08 am
by GARTHWILSON
Rather than factor it out and give it its own memory-consuming header and incurring the extra nest-unnest overhead, you can factor it in place whichever way it becomes most visually intuitive. Some people say a definition should be only a line or two, but then they put too much on a line and make it hard to read at a glance. A couple of the many ways you could do it are:
Code: Select all
: AAA
100 10
DO I
DUP 20 =
IF ." twenty " THEN
.
LOOP ;
Code: Select all
: AAA
100 10
DO I
DUP 20 = IF
." twenty " THEN
.
LOOP ;
The DO could be put at the end of the line that sets up the loop limit and index, but if I were teaching a class, I would insist that the accompanying LOOP then be straight down from it. It drives me nuts when I have to go looking for a word's pair because it's diagonal and buried so it doesn't stand out. I suppose that's what syntax highlighting is for; but I maintain that if it's laid out correctly, syntax highlighting is not necessary (except that I do like it in html which is an entirely different ball game).
In systems where DUP is no faster than I, I would keep the stack shallower, this way:
Code: Select all
: AAA
100 10
DO I 20 =
IF ." twenty " THEN
I .
LOOP ;
(and again, there are several ways to do it).
With exaggerated commenting:
Code: Select all
: AAA ( -- )
100 10 \ <tell significance of the limit and index> ^ lim, index
DO I 20 = \ Is the index 20? <And what is 20?> ^ f
IF ." twenty " THEN \ If so, print/display this. ^ <empty>
I . \ Regardless, display the index value. ^ <empty>
LOOP ; \ Go back for the next one. ^ <empty>
I'm trying to build something with BREAK and CONTINUE, which Forth simply doesn't have ...)
Add them!
That's a benefit of Forth. You can add virtually anything. What do they do in Python? There might already be an equivalent in Forth.
Re: Introducing Tali Forth for the 65c02 (ALPHA)
Posted: Wed Mar 07, 2018 12:03 am
by scotws
@Garth -
CONTINUE skips the rest of the loop and goes to the next iteration,
BREAK exits the loop. I'm sure we could figure something out, but first, I need to get this running stable

.
@Mike - I've applied the patch for branch_runtime, and it works fine, thanks! Zero_branch_runtime has different code now, and for some reason, after the first patch,
SEE crashes with garbage:
I have no idea what that is about, since words other than
SEE seem to work, but will keep this in mind and check later, because this could very well due to a totally different bug somewhere. Thanks again!
Re: Introducing Tali Forth for the 65c02 (ALPHA)
Posted: Wed Mar 07, 2018 12:30 am
by GARTHWILSON
@Garth - CONTINUE skips the rest of the loop and goes to the next iteration
Without adding words, CONTINUE might be done this way:
Code: Select all
: FOOBAR
<set up lim & index>
DO <bla bla bla>
<bla bla bla>
<condition> \ "CONTINUE" is what you get if condition false.
IF <more stuff>
<more stuff>
<more stuff>
THEN
LOOP
<more instructions> ;
I wouldn't add the word CONTINUE, but it could be done, as an IMMEDIATE compile-only word, using the address left by DO during compilation.
That sounds like it's exactly the same as LEAVE in Forth. I also use ?LEAVE, a more-concise way to do IF LEAVE THEN.
Re: Introducing Tali Forth for the 65c02 (ALPHA)
Posted: Wed Mar 07, 2018 6:36 am
by leepivonka
Here is a Fibonacci routine that prints all the numbers as it goes:
Code: Select all
: fib ( -- )
0 1 begin dup . swap over + dup 0< until 2drop ;
Re: Introducing Tali Forth for the 65c02 (ALPHA)
Posted: Wed Mar 07, 2018 7:04 am
by barrym95838
In native_words.asm:
Save 4 bytes with:
Code: Select all
_stack_ok:
; Display system prompt if all went well. If we're interpreting,
; this is " ok", if we're compiling, it's " compiled"
lda state
beq _print ; zero is "ok" string
lda #1 ; one is "compiled" string
_print:
jsr print_string
; Awesome line, everybody! Now get the next one
bra _get_line
z_cold:
z_abort:
z_quit: ; no RTS required
Save 6 bytes with:
Code: Select all
; ## BOUNDS ( addr u -- addr+u addr ) "Prepare address for looping"
; ## "bounds" src: Gforth b: 36 c: TBA status: tested
; """Given a string, return the correct Data Stack parameters for
; a DO/LOOP loop; over its characters. This is realized as
; OVER + SWAP in Forth, but we do it a lot faster in assembler
; """
xt_bounds:
cpx #dsp0-3
bmi +
lda #11 ; underflow
jmp error
*
clc
lda 0,x ; <u
ldy 2,x ; <addr
adc 2,x
sta 2,x ; <(addr+u)
sty 0,x ; <addr
lda 1,x ; >u
ldy 3,x ; >addr
adc 3,x
sta 3,x ; >(addr+u)
sty 1,x ; >addr
z_bounds: rts
Save 1 byte with:
Code: Select all
; ## CELL_PLUS ( u -- u ) "Add cell size in bytes"
; ## "cell+" src: ANSI core b: 22 c: TBA status: tested
; """Add the number of bytes ("address units") that one cell needs.
; Since this is an 8 bit machine with 16 bit cells, we add two bytes.
; """
.scope
xt_cell_plus:
cpx #dsp0-1
bmi +
lda #11
jmp error
*
inc 0,x
bne +
inc 1,x
*
inc 0,x
bne z_cell_plus
inc 1,x
z_cell_plus: rts
.scend
Save 13 bytes with:
Code: Select all
; ## CMOVE ( addr1 addr2 u -- ) "Copy bytes going from low to high"
; ## "cmove" src: ANSI string b: 78 c: TBA status: coded
; """Copy u bytes from addr1 to addr2, going low to high (addr2 is
; larger than addr1). Based on code in Leventhal, Lance A.
; "6502 Assembly Language Routines", p. 201
; """
.scope
xt_cmove:
cpx #dsp0-5
bmi +
lda #11 ; underflow
jmp error
*
; move dst address to where we can work with it
lda 2,x
sta tmp2 ; use tmp2 because easier to remember
lda 3,x
sta tmp2+1
; move src address to where we can work with it
lda 4,x
sta tmp1 ; use tmp1 because easier to remember
lda 5,x
sta tmp1+1
ldy #0
lda 1,x ; number of whole pages to move
beq _dopartial
_page:
lda (tmp1),y
sta (tmp2),y
iny
bne _page
inc tmp1+1
inc tmp2+1
dec 1,x
bne _page
_dopartial:
lda 0,x ; length of last page
beq _done
_partial:
lda (tmp1),y
sta (tmp2),y
iny
dec 0,x
bne _partial
_done: ; clear the stack
txa
clc
adc #6
tax
z_cmove: rts
.scend
Save 28 bytes with:
Code: Select all
; ## CMOVE_UP ( add1 add2 u -- ) "Copy bytes from high to low"
; ## "cmove>" src: ANSI string b: 93 c: TBA status: coded
; """Note addr1 is larger than ; ; addr2). Based on code in
; Leventhal, Lance A. "6502 Assembly Language Routines", p. 201.
; """
.scope
xt_cmove_up:
cpx #dsp0-5
bmi +
lda #11 ; underflow
jmp error
*
; move dst address to where we can work with it
lda 2,x
sta tmp2 ; use tmp2 because easier to remember
lda 3,x
clc
adc 1,x
sta tmp2+1 ; point to last page of destination
; move src address to where we can work with it
lda 4,x
sta tmp1 ; use tmp1 because easier to remember
lda 5,x
clc
adc 1,x
sta tmp1+1 ; point to last page of source
inc 1,x ; allows us to use bne with dec 1,x below
; move the last partial page first
ldy 0,x ; length of last page
beq _nopartial
_outerloop:
dey
beq _finishpage
_innerloop:
lda (tmp1),y
sta (tmp2),y
dey
bne _innerloop
_finishpage:
lda (tmp1) ; handle y = 0 separately
sta (tmp2)
_nopartial:
dec tmp1+1 ; back up to previous pages
dec tmp2+1
dec 1,x
bne _outerloop
_done:
; clear up the stack and leave
txa
clc
adc #6
tax
z_cmove_up: rts
.scend
These are all untested, and cmove_up is highly experimental.
Mike B.
Re: Introducing Tali Forth for the 65c02 (ALPHA)
Posted: Wed Mar 07, 2018 7:07 am
by leepivonka
Here are more possible code change suggestions. I'm still learning the Tali way of things, so these aren't tested code yet.
If you can live without the native & called compilation variants for some routines, it is sometimes much easier to native compile a few bytes of machine code instead of making the runtime routine do it all.
The defer word could native compile
and need no library routine at all.
The >r word could native compile
Code: Select all
jsr PluYA
phy ;no library routine return address on the control stack to worry about here
pha
and the library routine to pop a cell off the parameter stack to registers YA is
Code: Select all
PluYA:
cpx #dsp0-1
bmi +
jmp param_stack_underflowed
*
lda 0,x
ldy 1,x
inx
inx
rts
The literal word could native compile
and the library routine to push registers YA onto the parameter stack is
Code: Select all
PsuYA:
; cpx #???
; bpl +
; jmp param_stack_overflowed
*
dex
dex
sta 0,x
sty 1,x
rts
Re: Introducing Tali Forth for the 65c02 (ALPHA)
Posted: Wed Mar 07, 2018 9:42 am
by scotws
@leepivonka - Thanks for fib, is included!
@Mike - Thanks (again) for the enhancements, I'll be testing them ASAP. For
CMOVE and
CMOVE>, I first need to define a standardized test "by hand", which I already had for Liara but then didn't think to write down

. I mainly remember it being a pain in the rear ...
As for the division between native and subroutine compile -- the idea is currently to have one routine, and then modify that depending on the size limit given in
NC-LIMIT (currently set to zero for testing), with special cases modified by the Always Native (
AN) and Never Native (
NN) header flags. So if
NC-LIMIT is 20, any word with a length less than that will be native compiled (unless it is Always Native anyway). That way, there is only one routine for each word, and the clever stuff is done during compilation.
This actually works quite well for Liara Forth. Take
>R, which you correctly say is horrible in subroutine compilation. If you look at
https://github.com/scotws/LiaraForth/bl ... forth.tasm starting line 2288 in
COMPILE,, you'll see that the code recognizes when it has been asked to native compile one of a bunch of special words like
>R. It then strips off the whole push-me-pull-you stack antics required for subroutine jumps and only compiles the little bit left over.
For Tali Forth 2, I plan to include a second step that should strip off the underflow checks on words that have them (those with the new
UF flag, soon to be added to the headers) so that native compiled
DROP ends up as pure
INX INX again. The user will be able to set a flag to decide between stability for developing (underflow checks enabled) or speed when the bugs are gone (no underflow checking).
My hope is that the clever stuff all in one places uses less space than adding a second version of the words to the dictionary, with extra pointers in the header etc. Not sure yet how that will turn out

.
Re: Introducing Tali Forth for the 65c02 (ALPHA)
Posted: Sun Mar 11, 2018 2:37 pm
by scotws
@Mike - both the CMOVE and CMOVE> seem to work after initial testing, thank you again.