6502.org Forum  Projects  Code  Documents  Tools  Forum
It is currently Sun Nov 24, 2024 7:13 am

All times are UTC




Post new topic Reply to topic  [ 266 posts ]  Go to page Previous  1 ... 3, 4, 5, 6, 7, 8, 9 ... 18  Next
Author Message
PostPosted: Tue Feb 27, 2018 10:29 am 
Offline

Joined: Mon Jan 07, 2013 2:42 pm
Posts: 576
Location: Just outside Berlin, Germany
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 -
Code:
1 1 2 3 5 8 ...
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.


Top
 Profile  
Reply with quote  
PostPosted: Tue Feb 27, 2018 10:32 pm 
Offline

Joined: Sat Dec 13, 2003 3:37 pm
Posts: 1004
scotws wrote:
because people are blocking my chair in front of the computer

Oh, you have cats too?


Top
 Profile  
Reply with quote  
PostPosted: Wed Feb 28, 2018 8:30 am 
Offline

Joined: Mon Jan 07, 2013 2:42 pm
Posts: 576
Location: Just outside Berlin, Germany
whartung wrote:
scotws wrote:
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 ...


Top
 Profile  
Reply with quote  
PostPosted: Thu Mar 01, 2018 9:20 pm 
Offline

Joined: Mon Jan 07, 2013 2:42 pm
Posts: 576
Location: Just outside Berlin, Germany
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.


Top
 Profile  
Reply with quote  
PostPosted: Fri Mar 02, 2018 7:14 am 
Offline
User avatar

Joined: Sun Jun 30, 2013 10:26 pm
Posts: 1950
Location: Sacramento, CA, USA
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:
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:
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:
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:
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:
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:
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:
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 :-)


Top
 Profile  
Reply with quote  
PostPosted: Sun Mar 04, 2018 8:55 am 
Offline

Joined: Mon Jan 07, 2013 2:42 pm
Posts: 576
Location: Just outside Berlin, Germany
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 :D .


Top
 Profile  
Reply with quote  
PostPosted: Mon Mar 05, 2018 12:21 am 
Offline

Joined: Mon Jan 07, 2013 2:42 pm
Posts: 576
Location: Just outside Berlin, Germany
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:
 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:
: 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!


Top
 Profile  
Reply with quote  
PostPosted: Mon Mar 05, 2018 3:44 am 
Offline
User avatar

Joined: Sun Jun 30, 2013 10:26 pm
Posts: 1950
Location: Sacramento, CA, USA
Code:
: 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?


Top
 Profile  
Reply with quote  
PostPosted: Mon Mar 05, 2018 7:28 am 
Offline

Joined: Mon Jan 07, 2013 2:42 pm
Posts: 576
Location: Just outside Berlin, Germany
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.


Top
 Profile  
Reply with quote  
PostPosted: Mon Mar 05, 2018 4:07 pm 
Offline
User avatar

Joined: Sun Jun 30, 2013 10:26 pm
Posts: 1950
Location: Sacramento, CA, USA
scotws wrote:
... 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.


Top
 Profile  
Reply with quote  
PostPosted: Mon Mar 05, 2018 7:16 pm 
Offline
User avatar

Joined: Fri Aug 30, 2002 1:09 am
Posts: 8546
Location: Southern California
There's no ELSE or UNLOOP or EXIT or LEAVE or anything that wold keep . from getting executed.

_________________
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: Mon Mar 05, 2018 8:39 pm 
Offline

Joined: Mon Jan 07, 2013 2:42 pm
Posts: 576
Location: Just outside Berlin, Germany
Well, the inside of the loop looks sort of like this:
Code:
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 :oops: .


Top
 Profile  
Reply with quote  
PostPosted: Mon Mar 05, 2018 9:09 pm 
Offline

Joined: Mon Jan 07, 2013 2:42 pm
Posts: 576
Location: Just outside Berlin, Germany
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.


Top
 Profile  
Reply with quote  
PostPosted: Tue Mar 06, 2018 2:42 am 
Offline
User avatar

Joined: Sun Jun 30, 2013 10:26 pm
Posts: 1950
Location: Sacramento, CA, USA
GARTHWILSON wrote:
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.


Top
 Profile  
Reply with quote  
PostPosted: Tue Mar 06, 2018 8:30 am 
Offline

Joined: Mon Jan 07, 2013 2:42 pm
Posts: 576
Location: Just outside Berlin, Germany
barrym95838 wrote:
GARTHWILSON wrote:
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:
: .twenty ( u -- ) 20 = if ." twenty " then ;
followed by
Code:
: 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 ...)


Top
 Profile  
Reply with quote  
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 266 posts ]  Go to page Previous  1 ... 3, 4, 5, 6, 7, 8, 9 ... 18  Next

All times are UTC


Who is online

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