Jump to content
IGNORED

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


Lee Stewart

Recommended Posts

Making headway! Attached is an excerpt from the fbForth 1.0 manual, which is an explanation of the CRU words implemented in fbForth along with the fbForth TMS9900 Assembler code for them. I wonder whether the explanations are clear enough, over the top or need more information? Let me know.

 

CRU Words.pdf

 

...lee

Link to comment
Share on other sites

In the process of insuring that the copy of FBLOCKS in the manual is the same as the file, I wrote a routine, BLKOUT , to output to a file a range of blocks from the current blocks file formatted as presented in the manual. I may include it in FBLOCKS. Here it is in case you're interested:

*

 

 

BASE->R HEX   
0 VARIABLE OUTBUF 4E ALLOT              ( line output buffer)
PABS @ OUTBUF 1400 FILE OUTFIL          ( output file definition)
OUTFIL  SET-PAB  50 REC-LEN  OUTPT VRBL ( file type DV80)            
( header string for each block)
424C VARIABLE BLK# 4F43 , 4B20 , 2320 , 2020 , ( "BLOCK #   ")  
: ASCII     ( Change all non-ASCII chars to '#')
    OUTBUF 43 + OUTBUF DO       ( set up to scan buffer)
        I C@ 20 < I C@ 7E > OR  ( char not ASCII?)
        IF                      ( yes)
            23 I C!             ( change char to '#')
        THEN 
    LOOP ;    
: HDR ( n --- )             ( output header with block # on stack)
    BASE->R DECIMAL         ( force decimal base)
    BLK# OUTBUF 0A CMOVE    ( initialize header)
    0 <# #S #>              ( make block # a double number & convert to text)
    OUTBUF 7 + SWAP CMOVE   ( copy converted # to header)
    0A WRT                  ( write 10 bytes to file)
    R->BASE ;               ( restore number base)
: FTR OUTBUF 1 BLANKS 1 WRT ;   ( output footer line of 1 blank)
: BLKOUT  ( n1 n2 --- )     ( block output routine)
    BASE->R DECIMAL         ( force decimal base)
    1+ SWAP OUTFIL OPN DO   ( open output file; set up block output loop)
        I . I BLOCK I HDR   ( log current block to display; load block; do header)
        10 0 DO             ( set up line output loop)
            OUTBUF 4 BLANKS ( initialize line number output)
            I 0 <# #S #>    ( convert line # to text)
            3 OVER - OUTBUF + SWAP CMOVE    ( copy line #)
            DUP OUTBUF 4 + 40 CMOVE         ( copy 64 chars to line buffer)
            ASCII           ( convert non-ASCII chars to '#')
            44 WRT          ( write line to file)
            40 +            ( point to next line in block buffer)
        LOOP 
        DROP FTR            ( drop extra line pointer; write footer)
    LOOP 
    CLSE R->BASE ;          ( close file; restore number base)
( Output instructions to console)
CR CR 
." *Send line-numbered blocks from current blocks file to a text file." CR CR 
." Usage:  F-D" 22 EMIT ."  DSK<n>.<outfilename>" 22 EMIT CR 
."         <start block> <end block> BLKOUT" CR CR 
." --WARNING--Do NOT change to/from TEXT80 mode while using BLKOUT !!!" CR CR
    R->BASE  

 

 

*

...lee

Link to comment
Share on other sites

Making headway! Attached is an excerpt from the fbForth 1.0 manual, which is an explanation of the CRU words implemented in fbForth along with the fbForth TMS9900 Assembler code for them. I wonder whether the explanations are clear enough, over the top or need more information? Let me know.

 

attachicon.gifCRU Words.pdf

 

...lee

 

This is great :thumbsup: Any objection if I copy this concept for TF?

 

Mark

Link to comment
Share on other sites

I know we've talked about the details of joystick/keyboard capture in the Assembly on the 99/4A thread (in particular, here: http://atariage.com/forums/topic/162941-assembly-on-the-994a/page-11?do=findComment&comment=2848971); but, I'm still undecided about how I should handle restoring the keyboard to normal scan mode after joystick scanning. TI Forth's word JOYST ( keybdno --- char xstat ystat ) "restores" the keyboard scan mode with HEX 4 8374 C! , which I never understood because 4 selects the "Pascal Keyboard", whereas the system originally initializes to mode 5 (Standard or Basic Keyboard). For fbForth, I am inclined to use HEX 0 8374 C! , which restores the keyboard mode before the left (1) or right (2) joystick was selected. My reasoning is that the user might actually have changed the keyboard mode to other than "Standard" and want that back. If I were to force the "Standard" keyboard with HEX 5 8374 C! , that would, then, be a surprise. Of course, the user may have selected other than the "Standard" keyboard mode by accident, in which case HEX 0 8374 C! would "restore" that wrong mode. What do you think? 0 or 5?

 

...lee

Edited by Lee Stewart
Link to comment
Share on other sites

Neither. Use the CRU and read the joysticks at the hardware level, and bypass TI's KSCAN routine. It's tens of times faster:

 

 

; JOYST ( joystick# -- value )
; Scans the joystick returning the direction value
_joyst  mov *stack,r1               ; get unit number
        ai r1,6                     ; use keyboard select 6 for #0, 7 for #1
        swpb r1
        li r12,36
        ldcr r1,3
        li r12,6
        stcr r1,5
        swpb r1
        inv r1
        andi r1,>001f
        mov r1,*stack
        li r12,_next
        mov r12,@>83d6              ; defeat auto screen blanking
        mov @bank1_,@retbnk         ; return to bank 1 if interuupts should fire
        limi 2                      ; briefly enable interrupts
        limi 0                      ; and turn 'em off again
        b @retb0                    ; return to caller in bank 0
Link to comment
Share on other sites

Neither. Use the CRU and read the joysticks at the hardware level, and bypass TI's KSCAN routine. It's tens of times faster: ...

 

That presents a compatibility problem with old TI Forth code—not using the CRU, but the stack effects. JOYST would need to accept 1 or 2 rather than 0 or 1 for input (easy enough to effect) and leave the character code, x status and y status that TI Forth programmers are wont to getting. I suppose I could work up something to see whether I can keep down the code bloat. Perhaps I should actually code two versions, say, JOYKSC and JOYCRU , and then let the user map JOYST to whichever one they want to use. Of course, I then still need the answer to my question. :P

 

BTW, Mark, why did you choose 0 and 1 for joysticks 1 and 2?

 

...lee

Link to comment
Share on other sites

A-a-a-n-d...here is my solution:

*

HEX
26 USER JMODE ( 0=TI Forth; ~0=CRU)

( Scans the joystick returning the direction value)
( fbForth TMS9900 Assembler code)
ASM: JCRU         ( joystick# -- value )
    *SP R1 MOV,         ( get unit number)
    R1 5 AI,            ( use keyboard select 6 for #1, 7 for #2)
    R1 SWPB,
    R12 24 LI,      ( <-----This line FIXED!!! )
    R1 3 LDCR,
    R12 6 LI,
    R1 5 STCR,
    R1 SWPB,
    R1 INV,
    R1 001F ANDI,
    R1 *SP MOV,
    83D6 @() CLR,         ( defeat auto screen blanking)
;ASM

: JKBD ( kbd --- chr xstat ystat ) ... ;  ( This is the old TI Forth JOYST word that uses KSCAN)

: JOYST ( kbd|joyst --- [chr xst yst]|n )
    JMODE @ IF JCRU ELSE JKBD THEN ;      ( Now, JMODE decides which of the above words to execute) 

*

@Willsy? I stole most of your code! :grin: The differences are

  • Changed from joysticks 0 and 1 to 1 and 2 for consistency with TI Forth;
  • Don't need to restore R12 because it is only ever used for CRU stuff in fbForth, except in rare circumstances;
  • Just zeroed the screen-blanking timer because KSCAN always increments it prior to testing for 0 (don't know if it is tested elsewhere);
  • I don't think I need the LIMI 2/LIMI 0 combo in fbForth (How would I test that?)

Let me know if you see anything wrong with my code changes from your code.

 

...lee

Edited by Lee Stewart
Link to comment
Share on other sites

I corrected a mistake in line 10 of my last post. I forgot that the '36' was decimal—I needed to convert it to '24' because it's in hexadecimal mode! :dunce:

 

Unless I'm doing something wrong, JCRU only works with joysticks. It does not respond to the keyboard joystick keys. At least, that's how it's working in Classic99, i.e., the arrow keys and the Tab key (fire). Is there any way around this? Is that how it works in TF, @Willsy?

 

...lee

Link to comment
Share on other sites

Well it's reading the joysticks at the hardware level so it will sound how you configure classic 99 wrt joystick emulation. On my installation the joystick is mapped to the cursor keys and the fire button is the tab button. This is confirmed to work in TF in classic 99.

 

Mark

Link to comment
Share on other sites

Wow! I had a serious misconception about what the left and right keyboard keys returned compared to joystick returns. I thought the values were the same, i.e., that 8375h would show a key value for a joystick direction and that 8376h and 8377h would show those directions when the appropriate key was pressed. What was I thinking?! :dunce: I now think I understand what's going on. fbForth's JKBD (TI Forth's JOYST ) first checks for a keypress. If it finds one, it invents values that a joystick would have left in 8376h and 8377h and reports those along with the character code. If no keypress, it reports the actual values left in 8376h and 8377h from KSCAN's sampling of the joystick and also reports FFh for the "keypress". fbForth's JCRU , on the other hand, only gets actual joystick positions, so only works with actual joysticks. I guess I was hoping to make JCRU work with the keyboard, as well. That would mean, of course, that I would need to write my own keyboard scan routine without the serious delay loop that's in KSCAN. I'm not sure I want to do that. I think I'll leave it to the user to change JMODE to a non-zero value to run joystick-only mode (without KSCAN) with JOYST and leave it at 0 to run JOYST with KSCAN. Anybody care?

 

...lee

Link to comment
Share on other sites

I think the keyboard scan is both slow and cumbersome. Further more, how does it represent multiple simultaneous states that are possible with a joystick? Is possible to have three simultaneous states on the joystick. E g. Up, right and fire. How is this reported in JKBD? In the TF version, the joystick state is a bit-field.

 

 

 

Here is the description for JOYST:

 

http://turboforth.net/lang_ref/view_word.asp?ID=132

Link to comment
Share on other sites

I think the keyboard scan is both slow and cumbersome. Further more, how does it represent multiple simultaneous states that are possible with a joystick? Is possible to have three simultaneous states on the joystick. E g. Up, right and fire. How is this reported in JKBD? ...

 

JKBD first checks 8375h. If it finds 18 (12h), it abandons further checking, reporting 12h and two 0s. If it finds 255 (FFh), it assumes joystick use and checks 8377h (x-status) and 8376h (y-status), reporting FFh and both direction values. If it finds any other nonzero value, it checks for key values that represent the 8 possible directions, reporting the key value and the corresponding directions.

 

That's pretty much everything the hardware-level JCRU (same as TF's JOYST) reports except the simultaneous 'fire' and joystick position. I will check to see whether KSCAN is capable of that and change JKBD if it is.

 

...lee

Link to comment
Share on other sites

@Willsy et al.—

 

KSCAN reports simultaneous 'fire' and joystick positions, so I modified the original JKBD code to do so, as well. Obviously, if a user is using the keyboard as the joystick, simultaneous 'fire' and direction determination are impossible because 'fire' is a keystroke, even the joystick button, and KSCAN has only one location to store the keystroke, viz., 8375h. Furthermore, KSCAN does not translate the keycode to directions to store at 8376h and 8377h—it reserves that operation for its CRU sampling of the joystick position:

*

: JKBD  ( kbd --- chr xstat ystat )
   8374 C! ?KEY DROP 8375 C@ DUP 12 =
   OVER 0FF = OR
   IF
     8377 C@ 8376 C@
   ELSE
     DUP
     CASE
       4 OF 0FC 4  ENDOF
       5 OF 0 4 ENDOF
       6 OF 4   4 ENDOF
       2 OF 0FC 0  ENDOF
       3 OF 4 0 ENDOF
       0 OF 0 0FC ENDOF
       0F OF 0FC 0FC ENDOF
       0E OF 4 0FC ENDOF
       DROP DROP 0 0 0 0
     ENDCASE
   ENDIF
   0 8374 C! ; 

*

For comparison, here is the original code:

 

 

 

: JKBD ( kbd --- chr xstat ystat )
   8374 C! ?KEY DROP 8375 C@ DUP DUP 12 =
   IF
     DROP 0 0
   ELSE
     0FF =
     IF
       8377 C@ 8376 C@
     ELSE
       8375 C@                             
       CASE
         4 OF 0FC 4  ENDOF
         5 OF 0 4 ENDOF
         6 OF 4   4 ENDOF
         2 OF 0FC 0  ENDOF
         3 OF 4 0 ENDOF
         0 OF 0 0FC ENDOF
         0F OF 0FC 0FC ENDOF
         0E OF 4 0FC ENDOF
         DROP DROP 0 0 0 0 
       ENDCASE
     ENDIF
   ENDIF
   0 8374 C! ; 

 

 

 

What this means is that JKBD will handle the joystick just as does JCRU . JKBD has the advantage of giving the same information for both the joystick and its keyboard emulation, i.e., character code, x-status (0, FCh or 4) and y-status (0, FCh or 4). Its disadvantage, of course, is the long timing loop in KSCAN. JCRU will only report the hardware bitstring (1=Fire, 2=W, 4=E, 8=S and 16=N) for the joystick and 'fire' button—the keyboard is not sampled.

 

As I indicated in an earlier post, JOYST will execute JKBD by default or the user can set JMODE to 1 to have JOYST execute JCRU .

 

...lee

Edited by Lee Stewart
Link to comment
Share on other sites

@Willsy? @Vorticon? @JonnyBritish? @jacquesg? Anyone?

 

I'm trying to resist further changes to fbForth until after I finish the manual (probably by month's end!); but, I keep running into stuff that seems to need fixing. One problem I have puzzled over for a long time is cleaning up a failed colon ( : ) definition. VLIST will list it because it is pointed to by LATEST ; but, ' , -FIND and (FIND) will not find it, so FORGET will not work! It's easy enough to execute SMUDGE to make it visible to FORGET , but that seems cumbersome. It may be best to simply make it clear to the user that the word can be removed by resetting the smudge bit before defining any other words and, then FORGETting it. I suppose it could just be ignored; but, it does clutter up the dictionary. Thoughts?

 

...lee

 

 

Link to comment
Share on other sites

It's actually non-trivial. I spent a while looking at this in TF. TF can spot 'structural' errors during the compilation of a colon-definition - things like missing LOOP after a DO - that kind of thing. In those cases, it can rewind LATEST and HERE (HERE also needs to be reset, otherwise you'll leak memory). It can do this, because ; does the checking at the end of a definition. However, when things come to an abrupt end, such as the case of a miss-spelled word (thus the word wasn't found) then ; never gets a chance to run, because ABORT runs. Thus you end up with an orphaned definition.

 

I thought about this for TF, and determined that a new word was required: KILL. KILL will remove the word, regardless of smudge, restore LATEST, and set (not necessarily restore) HERE to the first free address.

 

I never got around to implementing it though - ran out of ROM space!

Link to comment
Share on other sites

It's actually non-trivial. I spent a while looking at this in TF. TF can spot 'structural' errors during the compilation of a colon-definition - things like missing LOOP after a DO - that kind of thing. In those cases, it can rewind LATEST and HERE (HERE also needs to be reset, otherwise you'll leak memory). It can do this, because ; does the checking at the end of a definition. However, when things come to an abrupt end, such as the case of a miss-spelled word (thus the word wasn't found) then ; never gets a chance to run, because ABORT runs. Thus you end up with an orphaned definition.

 

I thought about this for TF, and determined that a new word was required: KILL. KILL will remove the word, regardless of smudge, restore LATEST, and set (not necessarily restore) HERE to the first free address.

 

I never got around to implementing it though - ran out of ROM space!

 

That's pretty much what happens in fbForth and TI Forth. If the user reacts to a malformed colon-defined word, say XXX , immediately with SMUDGE XXX FORGET , everything is restored. HERE , LATEST and CONTEXT are all properly restored. If a word definition is started with CODE or ASM: , the smudge bit is not set, so something like ASM: XXX ... ;ASM can immediately be FORGOTten with no toggling of the smudge bit. I'm still thinking I should just give users the information and leave it up to them. After all, the dictionary functions perfectly well whether or not the offending word is removed—it's just aesthetically offensive in addition to taking up space.

 

...lee

Link to comment
Share on other sites

 

I'm still thinking I should just give users the information and leave it up to them. After all, the dictionary functions perfectly well whether or not the offending word is removed—it's just aesthetically offensive in addition to taking up space.

 

I'm inclined to agree. Hand-holding is an anathema in the Forth world (though, in this particular case, I see no problem with it - I mean, why would you *want* to leave a half-finished definition in memory?). Anyway, as you say, as long as things are documented, people can work around it, and even invent their own words to fix the problem. That is the Forth way afterall - DIY ;-)

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...