Jump to content
Sign in to follow this  
GDMike

TurboForth

Recommended Posts

1 hour ago, GDMike said:

I'm so glad you asked for that Char file..and saw that typo...

and there she is...while were here, Lee do you see anything weird on my sound byte code..i think its called "CDATA" 

from what i remember it was playing correctly on its first hit, but on its second round it bacame off frequency.

ok kids, what did Lee teach us? quite a bit, its never a loss when He gets ahold of something!! 

 

Ha!  😁

 

Re sound processing, there are a few things wrong:

  1. You are moving 12 bytes to VRAM when there are 13 to move.
  2. You should be checking >83CE in its own loop. As it is, you are resetting the sound table each time through the loop before the first instance of the sound has had a chance to finish.
  3. Also, unless you want to repeat the sound indefinitely, you do not want to include the first part of your LOOP code in the loop.

Here is code that should work:

BP     LI   R0,BUFFER         You do not need to CLR R0,R1,R2
       LI   R1,CDATA          ...before loading them.
       LI   R2,13
       LIMI 0                 Disable interrupts while we mess with VRAM and sound setup.
       BLWP @VMBW
       LI   R10,BUFFER
       MOV  R10,@>83CC
       SOCB @H01,@>83FD
       MOVB @H01,@>83CE
       LIMI 2                 Enable interrupts so sound table will be processed.
LOOP   MOVB @>83CE,@>83CE     Wait until sound table 
       JNE  LOOP              ...has finished.
       LIMI 0
       MOVB R0,@STATUS
       RT

 

...lee

  • Like 1

Share this post


Link to post
Share on other sites

thanks Lee very much. im def not good in sound in assy, TF and FB Forth make this easy. As for my count of 12 bytes, i think i was actually in the middle of a "What If" scenario in my troubleshooting. I Don't mind assembly, but last year I got about this much code completed then my PC seemed to get lost, as i used a lot of BL subs versus a straight down approach to my writing style. I always ended with a RT but found R11 was losing its mind sometimes and for someone always in a rush, i spent more time truoubleshooting rather than getting something done. TF was simple as basic and quickly took care of me, but im not seeing to many examples of things in TF covering RS232 serial tx/rx. Ill take this assy prgm to its max as long as I can reach my result the way I like it to be. So far im getting there.

Share this post


Link to post
Share on other sites

Though your CLR routine certainly gets the job done for clearing the screen:

CLR    CLR  R0
       LI   R1,>2000
CLRR   BLWP @VSBW
       INC  R0
       CI   R0,960
       JLT  CLRR
       RT

Here is a VRAM FILL routine adapted from fbForth via TI Forth that does it faster because it does not set the VRAM address for every byte:

       REF  VDPWA,VDPWD

*== VDP fill routine. =================================================
*
*     R0: VRAM address
*     R1: character to fill VRAM
*     R2: character count
*
VFILL  CLR  R0             Address to start VRAM fill
       LI   R1,>2000       Fill character in left byte
       LI   R2,960         Fill count
       ORI  R0,>4000       Set bit for VDP write
       SWPB R0
       MOVB R0,@VDPWA      LS byte first
       SWPB R0
       MOVB R0,@VDPWA      Then MS byte
       NOP                 Kill time
VFLOOP MOVB R1,@VDPWD      Write a byte & auto-increment VRAM address
       DEC  R2
       JNE  VFLOOP         Not done, fill another
       RT
*======================================================================

 

...lee

Edited by Lee Stewart
Cleaned up ALC

Share this post


Link to post
Share on other sites

And just for the sake of discussion, after reviewing some of the high speed game code I found here on Atariage here is VFILL with VDPWD loaded into R3.

When I timed it versus the normal version Lee showed it seems to go about 12.9% faster. Not bad for a small code change.

Just a thought.

 

Here is the code in my Forth Cross-Assembler dialect but it's not too different from TI Forth Assembler.

 

Weird stuff:

  • TOS is just an alias for R4 which is a "cache" for top of stack item.
  • I use a sub-routine called WMODE to setup the VDPWA, to save space
  • POP, is a Forth macro for:
: POP,          ( dst -- )  *SP+      SWAP  MOV, ;    \ 22 cycles

 

CODE: VFILL   ( VDP-addr count char-- )
              TOS SWPB,            \ fix the TMS9900 byte order
              R2 POP,              \ R2=count
              R0 POP,              \ VDP-addr popped into R0
              WMODE @@ BL,         \ setup VDP write address IN R0
              R3 VDPWD LI,         \ vdp addr. in a reg. makes this 12.9% faster
              BEGIN,
                TOS *R3 MOVB,      \ write byte to vdp ram
                R2 DEC,            \ dec the byte counter
              EQ UNTIL,            \ jump back if not done
              TOS POP,
              NEXT,
              END-CODE

 

  • Like 1

Share this post


Link to post
Share on other sites
9 hours ago, GDMike said:

im not seeing to many examples of things in TF covering RS232 serial tx/rx. Ill take this assy prgm to its max as long as I can reach my result the way I like it to be. So far im getting there.

I know Willsy got kind of excited when he saw that I was working on a driver for RS232 for my Forth system.

 

I know it's a pain to translate Forth Assembler to TI Assembler. ( I have done my share the other way) :)

But this code actually works to provide an OPEN, SEND and RCV routine. So here it is. Happy to answer any questions.

(It shows the signs of my trial and error in the comments.) 🙂

 

This code is in my home-made cross-compiled Forth dialect but it could be adapted to Turbo Forth or FB Forth pretty simply I think.

Here are some preliminary docs to explain it:

  • CONSTANT:  is just a CONSTANT
  • VARIABLE:   is just a VARIABLE
  • T! is just !  (means "target" store" ie: for the TI progam image)
  • EQU is like EQU but backwards syntax to TI ASM
  • l:  means create a "label" . It's like CREATE in Turbo Forth and kind of like  "0 VARIABLE" in FB Forth (I think)

    Stuff you won't need:
  • [CC] (CROSS-COMPILING) lets me use the interpreter to do simple calculations or change the RADIX interpretatively
  • [TC] switches back to the [TARGET-COMPILING] mode to make TI programs
  • RPUSH is macro. Below are the macros for both stacks.
     
    \ PUSH & POP on both stacks
    : PUSH,         ( src -- )  SP DECT,  *SP   MOV, ;    \ 10+18 = 28  cycles
    : POP,          ( dst -- )  *SP+      SWAP  MOV, ;    \ 22 cycles
    
    : RPUSH,        ( src -- ) RP DECT,  *RP   MOV,  ;
    : RPOP,         ( dst -- ) *RP+      SWAP  MOV,  ;
    

    There is some code below "housekeeping on USER VARIABLES..."   It just increments your variables to keep track of the video column and OUT which counts characters since the last carriage return.

    /explanations

  • Spoiler
    \ xfcc99 cross-compiler tms9902 rs232/1 DIRECT cru DRIVER 9Feb2019 bjf
    \ CODE words are used to save kernel space by not needing the CRU library
    
    \ These routines push the value in R12 onto the return stack
    \ then restore it when returning to Forth.
    \ This supports accessing other I/O devices while using the serial port.
    
    [CC] HEX [TC]
                       1300 CONSTANT: RS232/1     \ card address
    [CC] RS232/1 40 +  [TC] CONSTANT: /TTY1       \ 40= uart#1,
    \ [CC] RS232/1 80 + [TC] CONSTANT: /TTY2      \ 80= uart#2
    
    \ 9902 control bits
    [CC] DECIMAL
           13 EQU LDIR           \ "load interval register"
    \ for reference...
    \      16 CONSTANT: RTSON    \ request to send
    \      18 CONSTANT: RIENB    \ rcv interrupt enable
    \      21 CONSTANT: RXRL     \ receive register loaded bit
    \      22 CONSTANT: TXRE     \ transmit register empty bit
    \      27 CONSTANT: -DSR     \ NOT data set ready
    \      28 CONSTANT: -CTS     \ NOT clear to send
           31 EQU RESET          \ 9902 reset bit
    
    [CC] HEX
    
    TARGET-COMPILING
    
    VARIABLE: BPS    \ 0034 BPS T!   \ 9600 baud
    VARIABLE: PROTO  \ 9300 PROTO T! \ 8 bits, no parity, 1 stops
    VARIABLE: PORT
    \ VARIABLE: CARD
    
    \ 9900 sub-routines. *NOT* Forth words.
    l: LEDON
             R12 RS232/1 LI,    \ select the card
             7 SBO,             \ turn LED on
             RT,
    l: LEDOFF
             R12 RS232/1 LI,    \ select the card
             7 SBZ,             \ turn LED off
             RT,
    
    \ * variables BPS and PROTO MUST BE SET CORRECTLY BEFORE USING OPEN-TTY *
    CODE: OPEN-TTY  ( port -- ) \ Usage: /TTY1 OPEN-TTY
             R12 RPUSH,
             LEDON @@ BL,
             TOS R12 MOV,       \ load 9902 port address
             RESET SBO,         \ reset card
             TOS PORT @@ MOV,   \ set the port variable to use
             PROTO @@ 8 LDCR,   \ set protocol
             LDIR SBZ,          \ disable 9902 timer
             BPS @@ 0C LDCR,    \ set baud rate
             TOS POP,           \ refill TOS
             LEDOFF @@ BL,
             R12 RPOP,          \ restore R12
             NEXT,
             END-CODE
    
    [CC] DECIMAL [TC]
    \ this word turns on the LED when sending
    CODE: CEMIT ( c -- )  \ 'com-emit"
             R12 RPUSH,
             LEDON @@ BL,
             PORT @@ R12 MOV,
             BEGIN,
               27 TB, EQ    \ test -DSR bit =0
             UNTIL,
             16 SBO,        \ set RTS
             BEGIN,
               22 TB, EQ    \ wait XBRE empty
             UNTIL,
             TOS SWPB,      \ put byte on the other side
             TOS 8 LDCR,    \ send 8 bits
             16 SBZ,        \ reset RTS
    \ housekeeping on USER VARIABLES...
             R1      STWP,  \ get current user area address
             30 (R1) INC,   \ inc  OUT
             34 (R1) INC,   \ inc  VCOL
             LEDOFF @@ BL,
             R12 RPOP,
             TOS POP,
             NEXT,
             END-CODE
    
    \ VARIABLE: KBUFF           \ holds the last char rcv'd
    
     [CC] DECIMAL [TC]
    CODE: CKEY? ( -- n )         \  "com-key"
             0 LIMI,
             R12 RPUSH,
             PORT @@ R12 MOV,    \ select >1340 CRU address
             TOS PUSH,
             TOS CLR,
             21 TB,               \ test if char ready
             EQ IF,
                 TOS 8 STCR,      \ read the char
                 18 SBZ,          \ reset 9902 rcv buffer
                 TOS 8 SRL,       \ shift to other byte
      \            TOS KBUFF @@ MOV,
              ENDIF,
              R12 RPOP,
              2 LIMI,
              NEXT,
              END-CODE
    
    [CC] HEX [TC]
    

     

     

 

 

 

Share this post


Link to post
Share on other sites
On 6/24/2019 at 8:05 PM, Lee Stewart said:
BP     LI   R0,BUFFER         You do not need to CLR R0,R1,R2
       LI   R1,CDATA          ...before loading them.
       LI   R2,13
       LIMI 0                 Disable interrupts while we mess with VRAM and sound setup.
       BLWP @VMBW
       LI   R10,BUFFER
       MOV  R10,@>83CC
       SOCB @H01,@>83FD
       MOVB @H01,@>83CE
       LIMI 2                 Enable interrupts so sound table will be processed.
LOOP   MOVB @>83CE,@>83CE     Wait until sound table 
       JNE  LOOP              ...has finished.
       LIMI 0
       MOVB R0,@STATUS
       RT

 

...lee

I am gonna steal this little gem Lee. 

I think much of it could be done in Forth with the addition of an LIMI word.

 

Merci!

  • Like 1

Share this post


Link to post
Share on other sites

And—Here is “my” VFILL routine incorporating @TheBF’s suggestion for putting VDPWD (VDP Write Data address) into R3:

 

       REF  VDPWA,VDPWD

*== VDP fill routine. =================================================
*
*     R0: VRAM address
*     R1: character to fill VRAM
*     R2: character count
*     R3: VDPWD (VDP Write Data address)
*
VFILL  CLR  R0             Address to start VRAM fill
       LI   R1,>2000       Fill character in left byte
       LI   R2,960         Fill count
       LI   R3,VDPWD       VDP Write Data address
       ORI  R0,>4000       Set bit for VDP write
       SWPB R0
       MOVB R0,@VDPWA      LS byte first
       SWPB R0
       MOVB R0,@VDPWA      Then MS byte
       NOP                 Kill time
VFLOOP MOVB R1,*R3         Write a byte & auto-increment VRAM address
       DEC  R2
       JNE  VFLOOP         Not done, fill another
       RT
*======================================================================

 

...lee

  • Like 1

Share this post


Link to post
Share on other sites

yes, ive been seeing this ORI >4000 Statement for quite awhile.  i have to dig deepeer into it's depth to figure what's going on, but its tremendously a faster approach..i have experimented a little, but because i didnt understand it, and ive seen various illustrations with it buried in loops 6 and 8 times deep..i dunno yet because i havent had that need for speed yet i guess. but when i do, i know its an option.  thx for that reminder...

Share this post


Link to post
Share on other sites
7 hours ago, GDMike said:

yes, ive been seeing this ORI >4000 Statement for quite awhile.  i have to dig deepeer into it's depth to figure what's going on, but its tremendously a faster approach..i have experimented a little, but because i didnt understand it, and ive seen various illustrations with it buried in loops 6 and 8 times deep..i dunno yet because i havent had that need for speed yet i guess. but when i do, i know its an option.  thx for that reminder...

 

Because I am not sure whether you do not understand “ORI  Rn,>4000” or why it is used to write to the VDP Write Address Register, I will try to explain both.

 

“ORI  R0,>4000” performs a bitwise OR of >4000 with the contents of R0. That is, it sets the bits in R0 (makes them each 1) that correspond to the 1 bits in ‘>4000’ (binary 0100000000000000). If R0 contains >7FFF (binary 0111111111111111) before “ORI  R0,>4000” executes, it will still contain >7FFF afterwards because all (only one in this case) bits set in >4000 are already set in R0. If R0 contains >2006 (binary 0010000000000110) before “ORI  R0,>4000” executes, it contains >6006 (binary 0110000000000110) afterwards.

 

As to why you would perform “ORI  R0,>4000” to write to the VDP Write Address Register, you use bit 1 (from the left) of the VRAM address to tell the VDP whether you are going to read from or write to that VRAM address. At first blush, this may make no sense since it would appear you are changing the VRAM address when you set bit 1. However, the VDP (TMS9918A in this case) addresses a maximum of 16 KiB, which means that the available address range for the VDP is  0 – >3FFF, which means that bits 0 and 1 do not affect the address value. This makes bits 0 and 1 available as flags that can be passed to the VDP at the same time as setting a VRAM address. The designers of the TMS9918A did just that to tell the VDP whether the passed address is the read address (bit 1 off) or the write address (bit 1 on). Once you have set the VRAM address, you can read from or write to it repeatedly for a VRAM block of data because the VDP read/write registers are auto-incrementing. By the way, bit 0 is used as a flag to signal writing to VDP registers VR00 – VR07

 

To go a step further, the VSBR, VMBR, VSBW, VMBW and VWTR utilities all use the memory-mapped, VDP access addresses (referred to above as “registers”), VDPWA (RAM = >8C02 [VDP Write Address]), VDPRD (RAM = >8800 [VDP Read Data]) and VDPWD (RAM = >8C00 [VDP Write Data]) to do their work. You may not save much time writing your own routines for VMBR, VMBW and VWTR, except for the BLWP/RTWP overhead, or even for VSBR and VSBW when you are truly only interested in a single VRAM byte. However, when you use VSBW to fill blocks of VRAM with the same byte, you waste a significant amount of time setting the VRAM address for each and every byte when you could write your own routine to take advantage of the VRAM-auto-incrementing feature of the VDP.

 

OK....That is probably TMI so I will stop now. 😴

 

...lee

  • Like 1
  • Thanks 1

Share this post


Link to post
Share on other sites

Thanks Lee.  Naa, actually I studied up on that when Matt was explaining it, BUT I didn't know about bits 0,1 or I forgot and I didn't know which Refs SHOULDN'T be rewritten generally. Good to know. And I always need a refresher anyway..memory issues on a personal scale...good stuff

Edited by GDMike

Share this post


Link to post
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.

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...
Sign in to follow this  

  • Recently Browsing   0 members

    No registered users viewing this page.

×
×
  • Create New...