Jump to content
IGNORED

fbForth—TI Forth with File-based Block I/O [Post #1 UPDATED: 06/09/2023]


Lee Stewart

Recommended Posts

Here is my fbForth Assembler version of doScroll , which is now called by SCROLL defined below it:

 

 

 

HEX
ASM: doScroll  ( -- )  ( 0=left 2=right 4=up 6=down)
   sINC @() R4 MOV,
   WRAP @() R7 MOV,
   sNXTRC @() 834A @() MOV,   ( move to FAC for speed)
   sSRCCH @() 834C @() MOV,   ( source address to FAC+2 for speed)
   sDSTCH @() 834E @() MOV,   ( dest address to FAC+4 for speed)
   sOUTCTR @()  R6 MOV,      ( sOUTCTR @ 0 DO )
   0 LIMI,    ( necessary because fbForth's VSBR and VSBW do not disable interrupts)
   BEGIN,
      834C @() R2 MOV,     ( source address to R2 for inner loop)
      834E @() R3 MOV,     ( dest address to R3 for inner loop)
      R7 R7 MOV,           ( wrapping? )
      NE IF,
         R3 R0 MOV,
         36F6 @() BLWP,    ( VSBR--read wrap char from sDSTCH)
         R1 sWRCH @() MOV,  ( save wrap char to MSB)
      THEN,
      sINCTR @() R5 MOV,       ( sINCTR @ 0 DO )
      BEGIN,
         R2 R0 MOV,        ( get ready to read sSRCCH)
         36F6 @() BLWP,    ( VSBR--read char from sSRCCH)
         R3 R0 MOV,        ( get ready to write sDSTCH)
         36EE @() BLWP,    ( VSBW--write char to sDSTCH)
         R4 R2 A,          ( inc/dec sSRCCH)
         R4 R3 A,          ( inc/dec sDSTCH)
      R5 DEC,
      EQ UNTIL,            ( LOOP )
      R3 R0 MOV,           ( wrap char dest)
      sWRCH @() R1 MOV,
      36EE @() BLWP,    ( VSBW--write wrap/blank char to sDSTCH)
      834A @() 834C @() A,         ( next-round src address)
      834A @() 834E @() A,         ( next-round dst address)
   R6 DEC,
   EQ UNTIL,               ( LOOP )
   2 LIMI,         ( allow interrupts again)
;ASM

: SCROLL ( dir -- ) ( 0=left 2=right 4=up 6=down) 
   SCRDIR doScroll 
;
DECIMAL

 

 

 

It is a good bit faster than the high-level version. I cheated a little bit, however. You will notice that the calls to VSBR and VSBW are calling 36F6h and 36EEh directly. That is because I happen to know where they are since I wrote it. |:) It could change in future releases of the cartridge, so it can't be relied on. But for now, it works. It is still slower than TurboForth's SCROLL because it is not making as much use of scratchpad RAM as TurboForth and a couple of words that doScroll depends on are not written in ALC. I may include it in a future release of fbForth; but, I might need to go to a 64Kib cartridge to do it because the current 32KiB ROM is almost too tight.

 

Here is the fbForth-assembled version of doScroll :

ASM: doScroll  ( -- )  
  C120 , sINC , C1E0 , WRAP , C820 , sNXTRC , 834A , C820 ,
  sSRCCH , 834C , C820 , sDSTCH , 834E , C1A0 , sOUTCTR ,
  0300 , 0000 , C0A0 , 834C , C0E0 , 834E , C1C7 , 1305 ,
  C003 , 0420 , 36F6 , C801 , sWRCH , C160 , sINCTR , C002 ,
  0420 , 36F6 , C003 , 0420 , 36EE , A084 , A0C4 , 0605 ,
  16F6 , C003 , C060 , sWRCH , 0420 , 36EE , A820 , 834A ,
  834C , A820 , 834A , 834E , 0606 , 16DC , 0300 , 0002 , 
;ASM

...lee

Link to comment
Share on other sites

Here is my port to fbForth 2.0 of @Willsy's DarkStar that led to the last several posts in this thread::

 

DarkStar_fbForth2.zip

 

Both files need to be in DSK1—DARKSTAR is the game and DKSTRCHR is the font file loaded by it. Be careful :-o if you are using the same DSK1 for TurboForth because the TurboForth DarkStar blocks file has the same name (DARKSTAR)!! :-o

 

To start the game, make DSK1.DARKSTAR the current blocks file and load block #1:

USEBFL DSK1.DARKSTAR
1 LOAD

To get back to the default font after the game, type the following:

0 SCRFNT !
FNT

...lee

Edited by Lee Stewart
  • Like 2
Link to comment
Share on other sites

Sorry—I got sidetracked! Here is an updated DARKSTAR with a compiled version in blocks #31 – #38:

 

DarkStar_fbForth2_x2.zip

 

To load the compiled version type

30 LOAD

If your DKSTRCHR font file is not on DSK1, you can change the “DSK1” on line #1 of block #30 to load it from DSK2, DSK3, or ....

 

...lee

  • Like 2
Link to comment
Share on other sites

  • 1 month later...

The code below is my port to fbForth of @Willsy’s TurboForth DATA[ and ]DATA . I will be including this code in the next release of FBLOCKS instead of the code in post #963 because a programmer can simply use DATA[ ... ]DATA for both integers and bytes by doubling up for bytes. Note, too, that it can be used in word definitions as well as on the command line. Anyway, here it is:

 

( The words below do NOT require a count of the cells that follow it. )
( They are much faster than INTERPRET with a list of numbers because they )
( don't waste a dictionary search getting to the number conversion routine )
( for each and every number! )
( These words may be executed or compiled into definitions. )
: DATA[] ( -- addr #cells )
R 2+ R @ DUP 2 * 2+ R> + >R ;
: DATA[ ( -- addr count ) ( Input Stream: n1 ... nn)
STATE @ IF
COMPILE DATA[] 0 ,
THEN
HERE ( start address of list)
0 ( start counter)
BEGIN
IN @ ( get IN before reading next word)
BL WORD ( get next token to HERE)
HERE 1+ C@ ( get address of first character)
93 = ( is it ‘]’?)
IF ( yes; we are at the end of the list)
IN ! ( restore IN so INTERPRET reads last word we just read)
1 ( last time through loop [flag for UNTIL] )
ELSE
DROP ( DROP IN value; we don't need it)
HERE NUMBER ( convert to a double [32-bit] number)
DROP ( make it a single [16-bit] number)
, ( compile number into dictionary)
1+ ( increment counter)
0 ( once more through loop [flag for UNTIL] )
THEN
UNTIL ( get next number in input stream)
; IMMEDIATE
: ]DATA ( Interpreting: -- )
( Compiling: addr count -- ) ( Executing: -- addr count )
STATE @ ( compiling?)
IF ( yes)
SWAP 2- ! ( store count in location before addr)
THEN
; IMMEDIATE

 

...lee

  • Like 1
Link to comment
Share on other sites

Here are the fbForth Assembler and code versions of DATA[] for fbForth:

 

( fbForth Assembler version of DATA[]--- )
ASM: DATA[] ( -- addr #cells )
IP *+ R1 MOV, ( get #cells in r1)
SP DECT, ( make space on the stack)
IP SP ** MOV, ( push the address of the data)
SP DECT, ( make space on the stack )
R1 SP ** MOV, ( move #cells to stack )
R1 1 SLA, ( convert to bytes)
R1 IP A, ( adjust Forth PC to jump over the data)
;ASM
( Code version of DATA[]--- )
HEX
CODE DATA[] ( -- addr #cells )
C07D , 0649 , C64D , 0649 , C641 , 0A11 , A341 ,
NEXT,
DECIMAL

...lee

Link to comment
Share on other sites

As it stands, there cannot be any code, including comments, between DATA[ and ]DATA . This means that you cannot easily set up a larger array of data than will fit in one Forth block. It is quite simple to do it for a VARIABLE array with the cell count in the first location (see below); but, to define an array-containing word, which pushes its cell-count and address of its first datum to the stack, is well nigh impossible. It will not be easy; but, I will try to work out a better definition of DATA[ to allow for comments and other words that may be needed for multi-block arrays, notably --> for loading successive blocks into the array. I might add that @Willsy’s DATA[ for TurboForth does not suffer this problem.

 

Here is how to set up a multi-block VARIABLE array:

 

( First block)

0 VARIABLE MYARRAY

DATA[ num(1) num(2) ... num(x) ]DATA

SWAP DROP ( drop address; keep count)

--> ( load next block)

( Middle blocks)

DATA[ num(x+1) num(x+2) ... num(x+x) ]DATA

SWAP DROP + ( drop address; add count to previous count)

--> ( load next block)

...

( Last block)

DATA[ num(x+1) num(x+2) ... num(x+x) ]DATA

SWAP DROP + ( drop address; add count to previous count)

MYARRAY ! ( store total cell-count in first cell of MYARRAY)

...lee

Link to comment
Share on other sites

Easiest way is to add an extra mode to the interpreter. Use state=2 as special data compiling mode.

 

Well, there are two problems for me with that, viz., (1) I would need to release another build of the cartridge binary (not quite ready to do that); (2) I am trying to avoid the interpreter for large arrays of numbers because the interpreter searches the dictionary (466 words in the resident dictionary) for each and every number before it attempts number conversion. Small arrays are fine; but, I would like to make it convenient for very large arrays.

 

...lee

Link to comment
Share on other sites

Ah! But in your interpreter, you would say:

 

 

state @ 2 = if
    bl word number abort" Not a legal number" ,
else
    \ states 0 and 1
    ....
    ....
    ....
then

 

So, you wouldn't do a dictionary search at all if state==2. You'd use the same feature for CODE definitions, too. That's how TF works, which is why TF doesn't need to 'comma in' the op-codes in a CODE def.

 

You'd still need to update the cart though :sad:

 

Still, the cool thing about Forth is, you can write a new interpreter in fbForth itself - at least for testing. I've done this in TF many times. ABORT breaks out of it though. Would be good enough for getting the concept right though. :thumbsup:

Link to comment
Share on other sites

Ah! But in your interpreter, you would say:

state @ 2 = if
    bl word number abort" Not a legal number" ,
else
    \ states 0 and 1
    ....
then

So, you wouldn't do a dictionary search at all if state==2. You'd use the same feature for CODE definitions, too. That's how TF works, which is why TF doesn't need to 'comma in' the op-codes in a CODE def.

 

You'd still need to update the cart though :sad:

 

Still, the cool thing about Forth is, you can write a new interpreter in fbForth itself - at least for testing. I've done this in TF many times. ABORT breaks out of it though. Would be good enough for getting the concept right though. :thumbsup:

 

It is not that simple in fbForth. I could certainly do something like that, I suppose; but, currently, the only words that set STATE are [ and ] . [ sets it to 0 for execute mode and ] sets it to C0h for compile mode. C0h is the sum of the value of the precedence bit (40h) and the terminator bit (80h) present in the length byte of immediate words in fbForth and TI Forth.

 

...lee

Edited by Lee Stewart
Link to comment
Share on other sites

Yeah, I'll bet you are using the “Deflection” theme. I will change a few of the last posts to teal. Though a bit of a hassle, you can read that objectionable blue color (with “Deflection”) by selecting the text with your mouse. That temporarily turns it to white. “Deflection” appears to be the only skin with that problem. It would be nice if the skin software were smarter to avoid those kinds of clashes! 'Tis a pitty, really, because blue is such a pleasant color to the eyes on a white or light gray background.

 

...lee

Link to comment
Share on other sites

Ah! But in your interpreter, you would say:

state @ 2 = if
    bl word number abort" Not a legal number" ,
else
    \ states 0 and 1
    ....
    ....
    ....
then

So, you wouldn't do a dictionary search at all if state==2. You'd use the same feature for CODE definitions, too. That's how TF works, which is why TF doesn't need to 'comma in' the op-codes in a CODE def.

 

You'd still need to update the cart though :sad:

 

Still, the cool thing about Forth is, you can write a new interpreter in fbForth itself - at least for testing. I've done this in TF many times. ABORT breaks out of it though. Would be good enough for getting the concept right though. :thumbsup:

 

Actually, it looks like your code only has 2 states, executing (0) and compiling (1). You control compiling numbers with the variable, coding, at >A068. And—the dictionary is searched before number strings are converted to numbers.

 

Anyway, I finally have a definition for DATA[ that will allow comments and --> between DATA[ and ]DATA . Any other words will throw an error. This will allow large arrays that span several blocks. I will post it later today.

 

...lee

Link to comment
Share on other sites

Here is the updated code for DATA[ and ]DATA : [Edit: See post #1212 for an updated DATA[ .]

 

( The words below do NOT require a count of the cells that follow it. )
( They are much faster than INTERPRET with a list of numbers because they )
( don't waste a dictionary search getting to the number conversion routine )
( for each and every number! Also, multi-block arrays may now be )
( implemented because DATA[ now allows comments and --> [load next block] )
( before ]DATA )
( These words may be executed or compiled into definitions. )
( Load only one of the following versions of DATA[] )
( High-level Forth definition of DATA[]--- )
: DATA[] ( -- addr #cells )
R 2+ R @ DUP 2 * 2+ R> + >R ;
( fbForth Assembler version of DATA[]--- )
ASM: DATA[] ( -- addr #cells )
IP *+ R1 MOV, ( get #cells in r1)
SP DECT, ( make space on the stack)
IP SP ** MOV, ( push the address of the data)
SP DECT, ( make space on the stack )
R1 SP ** MOV, ( move #cells to stack )
R1 1 SLA, ( convert to bytes)
R1 IP A, ( adjust Forth PC to jump over the data)
;ASM
( Code version of DATA[]--- )
HEX
CODE DATA[] ( -- addr #cells )
C07D , 0649 , C64D , 0649 , C641 , 0A11 , A341 ,
NEXT,
DECIMAL
( The following version of DATA[ allows comments and --> between DATA[ and ]DATA )
0 VARIABLE IN_TMP
( [NUMBER] expects packed string of number to convert at HERE)
: [NUMBER] ( cnt -- cnt+1 )
HERE NUMBER ( convert to a double [32-bit] number)
DROP ( make it a single [16-bit] number)
, ( compile number into dictionary)
1+ ( increment counter)
;
: DATA[ ( -- addr count ) ( Input Stream: n1 ... nn)
STATE @ IF
COMPILE DATA[] 0 ,
THEN
HERE ( start address of list)
0 ( start counter)
BEGIN
IN @ IN_TMP ! ( get IN before reading next word)
BL WORD ( get next token to HERE)
HERE 1+ C@ ( get first character)
CASE ( check first character)
93 ( ‘]’) OF IN_TMP @ IN ! ( restore IN to INTERPRET last word)
1 ( last time through loop [flag for UNTIL] )
ENDOF
40 ( ‘(’) OF HERE C@ 1 = ( comment)
IF
[COMPILE] (
0 ( once more through loop [flag for UNTIL] )
ELSE
1 0 ?ERROR
THEN
ENDOF
45 ( ‘-’) OF HERE 3 + C@ 62 ( ‘>’) = ( ‘-->’)
IF ( load next block)
[COMPILE] -->
ELSE ( convert and compile negative number)
[NUMBER] ( convert and compile number at HERE; inc count)
THEN
0 ( once more through loop [flag for UNTIL] )
ENDOF
DROP ( drop unmatched code)
[NUMBER] ( convert and compile number at HERE; inc count)
0 ( once more through loop [flag for UNTIL] )
1 ( give ENDCASE something to consume)
ENDCASE
UNTIL ( get next number in input stream)
; IMMEDIATE
: ]DATA ( Interpreting: -- )
( Compiling: addr count -- ) ( Executing: -- addr count )
STATE @ ( compiling?)
IF ( yes)
SWAP 2- ! ( store count in location before addr)
THEN
; IMMEDIATE

I am sure DATA[ can be coded more efficiently; but, the above, at least, works pretty well, if I do say so myself!

 

...lee

 

EDIT: I removed the inadvertent inclusion of the previous version of DATA[ .

Edited by Lee Stewart
  • Like 1
Link to comment
Share on other sites

Here is fbForth code for DCHAR and SPDCHAR to use DATA[ ... ]DATA as DCHAR does in TurboForth:

 

( Helper routine for DCHAR and SPDCHAR )
: [DCHAR] ( addr cnt chr# ptbase-- )
SWAP 8 * + ( VRAM destination address)
SWAP -DUP ( get cnt to top of stack)
IF ( continue only if cnt non-zero)
2 * ( adjust cnt to bytes)
VMBW ( copy from addr to VRAM)
THEN ;
( Equivalent to CALL CHAR in BASIC. Similar to CHAR , but uses)
( array of numbers instead of stack for pattern definition. )
( Used to define one or more characters starting at chr# )
( pattern address. Moves cnt cells from addr to chr# pattern )
( address in VDP memory. )
: DCHAR ( addr cnt chr# -- )
PDT ( VRAM base address of pattern table)
[DCHAR] ; ( copy cnt pattern cells from addr to VRAM)
( Same as DCHAR, but for sprite pattern definitions because )
( SPDTAB does not always start at same VRAM address as PDT. )
: SPDCHAR ( addr cnt chr# -- )
SPDTAB ( VRAM base address of sprite pattern table)
[DCHAR] ; ( copy cnt pattern cells from addr to VRAM)

As indicated above, it was necessary to write two words ( DCHAR and SPDCHAR ) because the text and sprite pattern tables are not necessarily the same.

 

...lee

  • Like 1
Link to comment
Share on other sites

I just ran into a snag with my definition of DATA[ (see post #1020). It crashes with multi-line input from the terminal, i.e., when the terminating ]DATA is not on the same line with DATA[ . It works just fine loading from a blocks file. The problem appears to be the terminating null, which terminates input from the terminal. DATA[ attempts to convert the null to a number and fails, of course—aborting with an error message.

 

If I tell DATA[ to ignore the null, the system hangs because (I think) the interpreter tries to read past the terminating null in the TIB (Terminal Input Buffer)—not a good thing.

 

I haven't yet figured out how to keep DATA[ in control after the end of the input line. The key may be to define a word that mimics the functionality of --> , except for the block-loading part, because that works for multi-block DATA[ ... ]DATA arrays. If anyone has any suggestions, I am all ears!

 

...lee

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...