Page 6 of 19
Re: Introducing Tali Forth for the 65c02 (ALPHA)
Posted: Sun Nov 26, 2017 10:35 am
by scotws
So now Tali 2 has a repo at GitHub:
https://github.com/scotws/TaliForth2 (I tried using a different branch for a while but it just got too messy, and at some point I would have shot myself in the foot, so a new repo it is). Though I am more or less just using it as a decentralized backup for the moment, it will assemble to 32 KiB of "doesn't work". We must almost be done!
Two things possibly of interest even at this stage:
First, in response to feedback most recently from rwiker and others, I have a kernel.asm file that will hopefully isolate all hardware dependencies in one well-commented place. By default, it's set to run with py65mon, so people can test an 8-bit Forth the moment they have downloaded the repo. I'd be grateful if the people here who have gone through the porting process could tell me if this is what would help them, how we could make the process even easier, and any other suggestions.
Second, after two Forths, I got fed up with typing the same boilerplate label stuff all over again for the Dictionary and word routines. So wrote a bunch of Python scripts to create skeletons of the routines for Ophis assembler though a JSON file -- in fact, that's basically all there is at the moment to Tali 2, that and the stuff lifted from Tali 1 and Liara. Though it is specific to Ophis and there are some Liara/Tali special words, this might save somebody else some time as well. See the tools folder.
In the coming weeks, I hope to slowly add real code -- and ye gods, I'm missing those 65816 features already. Again, feedback and suggestions are most welcome.
Re: Introducing Tali Forth for the 65c02 (ALPHA)
Posted: Tue Nov 28, 2017 8:43 am
by scotws
Ah, the old proverb: A Forth of 200+ words begins with a single DROP.
Re: Introducing Tali Forth for the 65c02 (ALPHA)
Posted: Sun Feb 18, 2018 9:08 pm
by scotws
All words coded, so I'm declaring this version of Tali Forth 2 as an ALPHA release (
https://github.com/scotws/TaliForth2/releases/tag/alpha). "Alpha" in this context means "all words do something, usually even the right thing". There are still a lot of bugs (
MARKER is screwy, for some reason), and smaller stuff is missing, and nothing is optimized, but it can be downloaded and run with
GitHub claims that as a release, you can just get the zip file at he address above; the main GitHub location is
https://github.com/scotws/TaliForth2. The list of goals has been expanded:
Easy to try. Download the source -- or even just the binary ophis.bin -- and run the emulator with py65mon -m 65c02 -r ophis.bin to get it running. This lets you experiment with a working 8-bit Forth for the 65c02 without any special configuration.
I've tried to isolate the hardware stuff in one single file, so it should be easier to port to real hardware.
For the record, the current word list is:
Code: Select all
buffer: /string within to d.r d. ud.r ud. .r u.r u. */mod */ mod /mod / action-of is defer@ defer! while until repeat else then if .( ( drop dup swap ! @ over >r r> r@ nip rot -rot tuck , c@ c! +! execute emit type . ? false true space 0 1 2 2dup ?dup + - abs dabs and or xor rshift lshift pick char [char] char+ chars cells cell+ here 1- 1+ 2* = <> < > 0= 0<> 0> 0< min max 2drop 2swap 2over 2variable 2r@ 2r> 2>r invert negate dnegate c, bounds spaces bl -trailing refill accept unused depth key allot create does> variable constant value s>d d>s d- d+ erase fill find-name ' ['] name>int int>name name>string >body defer latestxt latestnt parse-name parse source source-id : ; compile, [ ] 0branch branch literal sliteral ." s" postpone immediate compile-only never-native always-native nc-limit abort abort" do ?do i j loop +loop exit unloop leave recurse quit begin again state evaluate base digit? number >number hex decimal count m* um* * um/mod ud/mod sm/rem fm/mod \ move cmove> cmove pad >in <# # #s #> hold sign output input cr page at-xy marker words wordsize aligned align bell dump .s find word cold bye
This fills up about 10k. Next up are a whole bunch of testing and bug fixes. Feedback, comments and corrections are of course most welcome.
And yes, I still miss the 65816. Seriously, once you go 16 bit ...
Re: Introducing Tali Forth for the 65c02 (ALPHA)
Posted: Mon Feb 19, 2018 1:02 am
by Martin_H
I'll take a look at it soon.
I find macros help tame the different between an eight bit and sixteen bit machine. Ophis allows macro invocation using the `, so they almost feel like new opcodes.
Re: Introducing Tali Forth for the 65c02 (ALPHA)
Posted: Mon Feb 19, 2018 6:46 am
by rwiker
I've been doing the occasional "git pull" to check the state of TaliForth 2; I'm happy to see that it's now reached a releasable state!
Re: Introducing Tali Forth for the 65c02 (ALPHA)
Posted: Mon Feb 19, 2018 11:30 pm
by jgroth
All words coded, so I'm declaring this version of Tali Forth 2 as an ALPHA release (
https://github.com/scotws/TaliForth2/releases/tag/alpha). "Alpha" in this context means "all words do something, usually even the right thing". There are still a lot of bugs (
MARKER is screwy, for some reason), and smaller stuff is missing, and nothing is optimized, but it can be downloaded and run with
It seems a regression bug is present. Tali 2 thinks 731 / 10 is -6480 just like Tali 1 did before you fixed the bug Scot.
Re: Introducing Tali Forth for the 65c02 (ALPHA)
Posted: Tue Feb 20, 2018 5:30 am
by scotws
It seems a regression bug is present. Tali 2 thinks 731 / 10 is -6480 just like Tali 1 did before you fixed the bug Scot.
Argh. It's even the same bug in
S>D. Thanks (again), should be fixed now (again).
Re: Introducing Tali Forth for the 65c02 (ALPHA)
Posted: Tue Feb 27, 2018 10:29 am
by scotws
Distinct progress: Tali can now run Martin's Mandelbrot without crashing. I haven't timed it yet,
because people are blocking my chair in front of the computer and I have to log in via Chromebook and ssh, and no,
I don't have issues ...
...anyway, it's safe to say it will render in minutes, not seconds. Included, but commented out by default in user_words.asm (
https://github.com/scotws/TaliForth2/bl ... _words.asm) are also little Forth routines to generate primes, Fibonacci and factorials, with original sourcing. They all work.
(I'll be changing Fibonacci to a version that will print one number after another -
instead of just the nth number, because that is more impressive for the kids, but at the moment I'm just happy the recursion works.)
No crashes at the moment, and my little list of Forth tests by hand passes, but I'm going to leave it in ALPHA until I've tested the native compiling feature some more, because I think it might be allocating far too much memory.
Re: Introducing Tali Forth for the 65c02 (ALPHA)
Posted: Tue Feb 27, 2018 10:32 pm
by whartung
because people are blocking my chair in front of the computer
Oh, you have cats too?
Re: Introducing Tali Forth for the 65c02 (ALPHA)
Posted: Wed Feb 28, 2018 8:30 am
by scotws
because people are blocking my chair in front of the computer
Oh, you have cats too?
LOL - yes, but they usually stand
on the desk in front of the monitor until I pet them for about ten minutes as a form of tribute. This time it was humans. Humans, I tell you ...
Re: Introducing Tali Forth for the 65c02 (ALPHA)
Posted: Thu Mar 01, 2018 9:20 pm
by scotws
In case this is of any use to somebody else: I've written a small Python tool to strip comments out of Forth code and compact the whitespace so that the result can easily be included in an assembler file:
https://github.com/scotws/TaliForth2/bl ... phisbin.py This makes it easier to write and test Forth code with (say) Gforth and then include it as high level code with (say) the
.incbin directive of Ophis.
Re: Introducing Tali Forth for the 65c02 (ALPHA)
Posted: Fri Mar 02, 2018 7:14 am
by barrym95838
Congratulations, Scot! I remembered that I had made an offer some time ago to help you shave a few bytes and cycles, so here goes (untested):
==========================================================================
In taliforth.asm:
Save 9 bytes with:
Code: Select all
cmpl_subroutine:
lda #$20 ; compile "JSR" opcode first
byte $2c ; "bit $4ca9" opcode
cmpl_jump:
lda #$4c ; compile "JMP" opcode first
; Compile the opcode in A
sta (cp)
cmpl_word:
; The cmpl_word routine is the body of all these routines
; and compiles the value on the Return Stack
ply ; LSB of return address
pla ; MSB of return address
iny
bne +
inc
*
sty tmp1
sta tmp1+1
ldy #1
pla ; LSB of word to compile
sta (cp),y
iny
pla ; MSB of word to compile
sta (cp),y
tya
sec ; advance cp by three bytes
adc cp
sta cp
bcc +
inc cp+1
*
jmp (tmp1)
Save 16 bytes with:
Code: Select all
dodefer:
.scope
; """Execute a DEFER statement at runtime: Execute the address we
; find after the caller in the Data Field
; """
; The xt we need is stored in the two bytes after the JSR
; return address, which is what is on top of the Return
; Stack. So all we have to do is replace our return jump
; with what we find there
pla ; LSB
sta tmp1
pla ; MSB
sta tmp1+1
ldy #1
lda (tmp1),y
sta tmp2
iny
lda (tmp1),y
sta tmp2+1
jmp (tmp2) ; This is actually a jump to the new target
.scend
Save 1 byte with:
Code: Select all
dodoes:
.scope
; """Execute the runtime portion of DOES>. See DOES> and
; docs/create-does.txt for details and
; http://www.bradrodriguez.com/papers/moving3.htm
; """
; Assumes the address of the CFA of the original defining word
; (say, CONSTANT) is on the top of the Return Stack. Save it
; for a later jump, adding one byte because of the way the
; 6502 works
ply ; LSB
pla ; MSB
iny
bne +
inc
*
sty tmp2
sta tmp2+1
; Next on the Return Stack should be the address of the PFA of
; the calling defined word (say, the name of whatever constant we
; just defined). Move this to the Data Stack, again adding one.
dex
dex
ply
pla
iny
bne +
inc
*
sty 0,x ; LSB
sta 1,x ; MSB
; This leaves the return address from the original main routine
; on top of the Return Stack. We leave that untouched and jump
; to the special code of the defining word. Its RTS instruction
; will take us back to the main routine
jmp (tmp2)
.scend
===============================================================================
In native_words.asm:
Save 12 bytes with:
Code: Select all
branch_runtime:
.scope
; The address on the Return Stack points to the last byte
; of the JSR address, one byte below the branch literal
pla
sta tmpbranch
pla
sta tmpbranch+1
; Keep in mind: the address we just popped points one byte
; lower than the branch literal we want to grab
ldy #1
lda (tmpbranch),y ; LSB
sta tmp1
iny
lda (tmpbranch),y ; MSB
sta tmp1+1
jmp (tmp1)
.scend
Save 2 bytes with:
Code: Select all
literal_runtime:
.scope
; During runtime, we push the value following this word back
; on the Data Stack. The subroutine jump that brought us
; here put the address to return to on the Return Stack -
; this points to the data we need to get. This routine is
; also called (LITERAL) in some Forths
dex
dex
; The 65c02 stores <RETURN-ADDRESS>-1 on the Return Stack,
; so we are actually popping the address-1 of the literal
pla ; LSB
sta tmp1
pla ; MSB
sta tmp1+1
; Fetch the actual literal value and push it on Data stack
ldy #1
lda (tmp1),y ; LSB
sta 0,x
iny
lda (tmp1),y ; MSB
sta 1,x
; Adjust return address and push back on the Return Stack
tya
clc
adc tmp1
tay
lda tmp1+1
adc #0
pha
phy
rts
.scend
Save 4 bytes with:
Code: Select all
xt_negate:
lda #0
sec
sbc 0,x ; LSB
sta 0,x
lda #0
sbc 1,x ; MSB
sta 1,x
z_negate: rts
Save 14 bytes with:
Code: Select all
zero_branch_runtime:
; """In some Forths, this is called (0BRANCH)"""
.scope
; See if the flag is zero, which is the whole purpose of
; this all
inx
inx
lda $fe,x
ora $ff,x
bne _skip
_zero:
; Flag is FALSE, so we take the jump to the address given
; in the two bytes following the JSR
pla
sta tmpbranch
pla
sta tmpbranch+1
; Keep in mind: the address we just popped points one byte
; lower than the branch literal we want to grab
ldy #1
lda (tmpbranch),y
sta tmp1
iny
lda (tmpbranch),y
sta tmp1+1
jmp (tmp1) ; Execute the branch
_skip:
; Flag is TRUE, so we skip over the branch address and
; proceed with the part between IF and THEN
pla ; LSB
clc
adc #2
tay
pla ; MSB
adc #0 ; only need carry
pha
phy
rts
.scend
Mike B.
P.S. All of the return stack gymnastics caused by STC have given me a renewed appreciation of DTC

Re: Introducing Tali Forth for the 65c02 (ALPHA)
Posted: Sun Mar 04, 2018 8:55 am
by scotws
Wow, thank you Mike! I hope to be able to include it during the day ... 12 bytes, 16 bytes, those are serious savings, too. ALPHA indeed!
(If it would be easier for you to send stuff via GitHub pull requests, please feel free ... I've grown to appreciate Git during development, hard to remember I used to do things without version control and experimental branches.)
Yeah, the STC stack games are a bit annoying. I still have to write the native compiling for
>R and such where it is worse: First, strip the part off that saves the return value from both ends of the routines; then, in a future version, strip off the underflow check if the user flags that with a
true flag in
uf-strip. The next Forth is definitely going to be DTC

.
Re: Introducing Tali Forth for the 65c02 (ALPHA)
Posted: Mon Mar 05, 2018 12:21 am
by scotws
So, thanks again. It turns out that there is a problem with three of the patches, though two of those seem to be an underlying bug in the previous code.
The first change (cmpl_subroutine) seems to work fine until I try the word
SEE, at which point it prints garbage. SEE is a high-level word, so I'm going to skip that for a moment because it might have to do with the other two:
Both branch_runtime and zero_branch_runtime changes work with simple loops and branches, but this fails both with my original code and your patches. Watch this:
Code: Select all
aaa 100 10 do i dup 20 = if ." twenty " then . loop ; ok
aaa 10 11 12 13 14 15 16 17 18 19 IM
size (decimal): -10
000A 03 00 03 00 9C 07 1C F0 16 F0 00 00 00 00 10 00
001A 00 00 2A 07 2C 09 03 02 18 00 76 00 00 00 2C 09
002A 14 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
The "IM" and "size (decimal) parts belong to
SEE, which is the last word defined when Tali starts (via user_forth.fs). I hadn't noticed this bug before because all the simpler stuff passes, even
Code: Select all
: aaa 100 10 do i 20 = if ." twenty " then loop ; ok
aaa twenty ok
Something is not working when we ask the code to jump between
THEN and
LOOP it seems. I'll have to take a look at the code, and then retry those three patches. Thanks again!
Re: Introducing Tali Forth for the 65c02 (ALPHA)
Posted: Mon Mar 05, 2018 3:44 am
by barrym95838
Code: Select all
: aaa 100 10 do i dup 20 = if ." twenty " then . loop ;
I think you need to insert a
drop before your
then to keep your data stack balanced, but I am not qualified to comment further ... at least not yet ...
Mike B.
P.S. Is your
." and/or your
: parsing that space between the
y in twenty and the closing
" properly?