6502.org Forum  Projects  Code  Documents  Tools  Forum
It is currently Tue May 07, 2024 9:51 pm

All times are UTC




Post new topic Reply to topic  [ 110 posts ]  Go to page Previous  1 ... 4, 5, 6, 7, 8
Author Message
PostPosted: Tue Sep 03, 2019 3:23 pm 
Offline

Joined: Wed Aug 21, 2019 6:10 pm
Posts: 217
chitselb wrote:
my exit was "POP RS->IP; JMP NEXT"
now it is "POP RS->IP; JMP NEXTO"
Code:
next    inc ip
        inc ip
nexto   jmp (ip)


Either are perfectly standard EXITs. There are processors that do one faster and processors that do the other faster, and on those processors, the model will follow suit. IIRC, the 68K has a very fast four byte NEXT based on an available JMP ++(...) operation.

Many 6502 models are symmetric, and the approach is often based on parts of a model being ported from another processor's implementation.

Quote:
Several other words also have inline parameters, and I'd like to resolve any problems without just tossing `PAGE` in there, optimally wasting only 1 byte to realign things.


If it only trips up when bumped up to $xx00, and not when bumped to $xx01, I'd revise what I said and say that I'd probably toss in a NOP. But that's not advice, it's just the way I'd probably tackle it.

If shifting to "PUSH ++IP->RS; ..." / "POP RS->IP" cleans it up, that has the appeal that in case there is some other application-specific word that may run into the same or similar issue, the issue has already been cleaned up.


Top
 Profile  
Reply with quote  
PostPosted: Fri Sep 13, 2019 2:52 am 
Offline

Joined: Sat Aug 21, 2010 7:52 am
Posts: 231
Location: Arlington VA
BruceRMcF wrote:
chitselb wrote:
my exit was "POP RS->IP; JMP NEXT"
now it is "POP RS->IP; JMP NEXTO"
Code:
next    inc ip
        inc ip
nexto   jmp (ip)


Either are perfectly standard EXITs. There are processors that do one faster and processors that do the other faster, and on those processors, the model will follow suit. IIRC, the 68K has a very fast four byte NEXT based on an available JMP ++(...) operation.


Thank you for the validation. I had only dissected a few other Forths and they used a post-increment EXIT. My inner interpreter (ENTER, EXIT, (+LOOP), (LOOP), etc...) is rewritten now and works well with the pre-incrementing!

For my next trick, I'm revisiting SAVE-BUFFERS and LOAD-BUFFERS (also VERIFY-BUFFERS which is a minor variant). PETTIL stashes blocks of virtual memory in (what I am calling) "packets" in a structure that builds downward in upper RAM. A packet is either "data" or "screen" and is either "compressed" or "uncompressed". Those two bit flags and a "size" form the 16-bit packet header. For compression, I use run-length encoding, which works well for typical Forth source. A screen packet will have 24 bits of "linewrap" stored adjacent and below the packet header. Each bit indicates whether that physical line is the start of a logical line, or not. Only 24 bits per screen are required, because physical line 0 is always the start of a logical line.

When I started writing this, the scope was intended to be a nifty Forth for my hardware PET. Project scope has expanded to the rest of the Commodore 8-bit line, which means adding disk support. The virtual memory buffer (all those packets) will load to a different place every time. Since all navigation is relative (only sizes, no absolute addresses) this doesn't require any changes to the data after loading it in. However, loading a file to a different load address than the one stored in the first two bytes is problematic. Here's the layout.
Code:
immediately after LOAD:

0000-03FF |zeropage|stack|systemstuff|
0400-46B7 |core|startup|studio|symtab| all mooshed together
Code:
after running PETTIL initialization:

0000-008C |PETTIL zeropage|
008D-03FF |zeropage|stack|system|
0400-040C |10 sys1039
040D-040F |JMP(startup)|
0410-049C |the bottom half of zeropage that BASIC was using|
049F-066B |Sweet16|
066C-1A55 |PETTIL `core` dictionary, (just code)|
1A56-52FD |free, unused memory, filled with DE AD BE EF pattern|
52FE-52FF |an empty virtual memory buffer (VMBUF)| grows downward, ends at BLKBUF
5300-56FF |1K block buffer (BLKBUF)| 1K block, ends at SYMTAB
5700-66FF |symbol table (SYMTAB)| this grows upward.  FORGET sorts and moves it
6700-7FFF |PETTIL `studio` dictionary (just code)|

so, here's how we get to VMBUF

: blkbuf    symtab @ b/buf - ;
: vmbuf    blkbuf 2- ;

PETTIL studio is the programmer environment, with every definition that touches the symbol table. When the compiling is done, all memory above 1A55 may be reclaimed and used for other purposes! Of course, you lose the editor, assembler, interpreter, compiler, find, the symbols, etc... but that's okay because your application code is built now and no longer needs those things. Storing the top word (e.g. STARTREK) into STARTUP will bring it up at launch, and SAVE-FORTH can store such an image on tape or disk like a turnkey application. BLKBUF will now be 7C00-7FFF and VMBUF still goes adjacent and just below that.

In no particular order, these are the design questions that I ponder today.

A VIC-20 is more useful for graphics when more of the $1000-1FFF region is available to the VIC chip. It'd be nice to move things around so `core` does not live there. What memory layouts might work better?

On the 80-column PET and the 128, a screen has 2000 characters (and no linewrap). It's workable if I make BLKBUF a 2K region and have screen packets be this size. The ewww factor is high.

Moving VMBUF at load is a pain. PETTIL has to look at the load address, subtract it from the end address, and subtract that number (packet file size) from BLKBUF. Then get the data. To make things more annoying, whenever the machine does tape or disk I/O, and the user hits the STOP key, or an I/O error occurs, the ROM drops to the BASIC `READY.`prompt. That code is chiseled into concrete, so all disk I/O for load, save and verify needs to be sandwiched between a pair of `aloha` calls to ensure that zero page is okay for running BASIC. Typing RUN resumes PETTIL with a warm start if this happens.

This (relocating loader that looks at the file load addres before calculating the effective load address) seems like it could be the sort of problem that someone else has already solved. All ideas are welcome.


Top
 Profile  
Reply with quote  
PostPosted: Fri Sep 13, 2019 8:02 pm 
Offline

Joined: Sat Aug 21, 2010 7:52 am
Posts: 231
Location: Arlington VA
chitselb wrote:
This (relocating loader that looks at the file load addres before calculating the effective load address) seems like it could be the sort of problem that someone else has already solved. All ideas are welcome.

Mia Magnusson came up with this in Facebook group "FORTH PROGRAMMING / RETRO COMPUTING" (https://www.facebook.com/groups/273924826349346/)

"p.s. do you really need to use standard format instead of inserting the length at the start of the file?"

INSERTING THE LENGTH AT THE START OF THE FILE! Of course! And after loading into memory, replacing the value with 00 00 to mark the tail of VMBUF again.

SAVE-BUFFERS replaces double null with the (negated) buffer size, also the PRG file size. At LOAD-BUFFERS or VERIFY-BUFFERS the first two bytes of the file are subtracted from `blkbuf` on the running system. So that takes care of the disk load.

For tape, the code is a little different, calling ROM routine READHEAD which populates the 192-byte cassette buffer at 027A with filetype, startaddr, endaddr, "filename string" (and blanks to the end of the buffer). After calculating the effective load address, a call to READDATA brings it in.

VERIFY-BUFFERS has to first store the filesize over the '00 00' at VMBUF, then call READDATA, otherwise those two bytes will not match, guaranteeing 100% "verify error". VERIFY-BUFFERS should also fail early after READHEAD, if there was not already '00 00' at this address.

Following READDATA,
( loadstartaddr ) off \ mark the tail -- both VERIFY-BUFFERS and LOAD-BUFFERS
( loadstartaddr ) vmbuf ! \ uservar, the place where new packets are added -- LOAD-BUFFERS only


Top
 Profile  
Reply with quote  
PostPosted: Wed Oct 09, 2019 9:38 am 
Offline

Joined: Sat Aug 21, 2010 7:52 am
Posts: 231
Location: Arlington VA
I finally got the outer interpreter behaving correctly and could not be more thrilled! It does nested loading of screens and has so far withstood all the torture tests I've thrown at it. Here's the source, feedback appreciated
Code:
lazy-loading outer interpreter

code skip   ( -- offset )
    $f0 #       lda,
    $2c c,  \ bit abs opcode
    \ fall through
end-code

code scan   ( -- offset )
    $d0 #           lda,
    \ entry from skip
    'modifyskipscan sta,
    in              ldy,
                    dey,
    begin,
                    iny,
    span            cpy,
    cc while,
    n6 )y           lda,
    n7              eor,
here &modifyskipscan
    vc until,    \ changed to BEQ (skip) or BNE (scan)
    in              sty,
                    tya,
    push0a          jmp,
end-code

: parse   ( -- length )
     skip dup 1- <n6 +
     scan rot - in 1+! >n8 tuck
     ?: tuck under c! ;

create firmwarecursor
    $AF c,   $C6 c,  $D5 c,    $C4 ,  $D8 c,
\ C4 PNT   current (logical) screen line address
\ C6 PNTR  current cursor column on current line
\ D8 LNMX  width of the screen (39 or 79)
\   DFLTN    PNTR    TBLX      PNT    LNMX
\    3        in      lin    lin*40   span
\                            +blkbuf

code =cursor   ( addr|0 -- )
    z stx,    -6  # ldx,
    0 # ldy,
    begin,     tos 1+ lda,
    if,  firmwarecursor 250 - ,x ldy,
    then,
    tos )y lda,     pha,
    cursor 250 - ,x lda,
    tos )y sta,     iny,    pla,
    cursor 250 - ,x sta,   inx,
    0>= until,
    z ldx,  drop jmp,

: query
    tib 80 expect ;

: refill   ( -- )
    sib blk@ block cursor 3 c!+ 0 !+
    lin 40* rot + !+ >r
    lin buf.wrap >bit cbit@
    ?: forty eighty  dup r> c!
    0 =cursor  expect  0 =cursor ;

code lin+   ( -- flag )
    lin lda, 
    0>= if,
        cursor 5 + bit,
        vc if,
            iny,
        then,
    then,
    iny,  lin sty,  next jmp,
end-code

code eoi?   ( -- flag )         \ end of input
    blk lda,
    ' eol? beq,
    lin lda,  l/scr # cmp,   xpushc jmp,
end-code

code eol?   ( -- flag )
    in lda,   span cmp,  xpushc jmp,
end-code

code empty?   ( -- flag )
    n ldy,   iny,    xpushz jmp,
end-code

: nomloading? ( -- flag )
    lin+ eoi? ;

: nomsession? ( -- flag )
    span c@ empty? or ;

: hungry?   ( -- flag )
    blk@ ?: nomloading? nomsession? ;

: ?nomnom   ( flag -- )
    ?exit blk@ ?: refill query ;

: name   ( char -- nfa|false )
    blk@ ?: sib tib  n6 2!
    begin   eol?
    while   hungry?   ?nomnom 
            eoi?
    until
    eoi? ?: false parse  n0 coff ;

: grok   ( cfa flag -- )
    compiling? <>
    ?: execute xt, ;

code \  ( -- )
    0 # lda,  span sta,   next jmp,

: interpret   ( -- )
    begin   ?stack  bl name ?dup
    while   found? ?dup
            ?: grok number
    repeat ;

: .ok
    ." ok" cr ;

: quit   ( -- )
    rp! blk 2off
    begin         
        [compile] \
        interpret
        compiling? ?: cr .ok
    again  ; -2 allot

: abort   ( -- )
    sp! forth definitions quit  ; -2 allot

code chkblk   ( u -- u flag )
    tos lda,  sec,   0<> if, #blk cmp, then,  xpushc jmp,

: load   ( u -- )
    chkblk  8 ?error  \ "BLOCK OUT OF RANGE"
    6 blk m>r
        blk ! in on  prev on  [compile] \
        interpret
    6 blk r>m
    in c@ refill in c! ;

: -->   ( -- )
    scr @ blk@ ?dup
    if, nip 1+ then,
    blk ! in off [compile] \
    interpret ;


Top
 Profile  
Reply with quote  
PostPosted: Tue Dec 08, 2020 12:12 am 
Offline

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

It looks like your interpreter is working with SPAN directly and I was wondering how you would handle a situation like this:
Code:
: GREET
   CR ." WHO ARE YOU? "
   PAD 80 EXPECT
   CR ." HELLO "
   PAD SPAN C@ TYPE
   CR ." WELCOME TO FORTH." ;

A trivial example, I know, but you get the idea.


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

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: