Jump to content

Photo

Camel99 Forth Information goes here

Camel99 Forth Concatentive Programming ANS Forth

291 replies to this topic

#276 TheBF OFFLINE  

TheBF

    Dragonstomper

  • Topic Starter
  • 987 posts
  • Location:The Great White North

Posted Fri Feb 22, 2019 11:03 AM

About that ISR driven RS232

 

I have got something pretty stable working for ISR on RS232/1 thanks again to all the help one gets here on Atariage.

The spoiler shows the current code and test routine and the little movie shows it in action at 9600 bps.

 

It is worth noting that at 9600 bps, sending a  7K file with a 256 byte buffer, the file was captured and echoed back to the terminal no problem.

The same test done a 19.2Kbps dropped characters near the end of the file.  So with a bigger buffer I can capture faster, but if I need the memory I need to slow down the sending a bit.

Or I could stop the echo and just put the bytes in storage buffer somewhere. However 9600 is fast enough for what I am doing.

 

Also note I am using expansion RAM (variables) for QHEAD and QTAIL not scratchpad RAM.  Seems to be ok for my needs.

 

For the assembly language coders out there, you can compare how I took insanemultitasker's code but gave the various routines names in the Forth "dictionary".

This means I can run the ALC routines from the Forth command line and see how the work.

Spoiler

Attached Files


Edited by TheBF, Fri Feb 22, 2019 11:09 AM.


#277 TheBF OFFLINE  

TheBF

    Dragonstomper

  • Topic Starter
  • 987 posts
  • Location:The Great White North

Posted Tue Feb 26, 2019 6:25 PM

Here a bug, there a bug, everywhere a bug bug. Old theBF had some RAM, ee I ee I oh!

 

I thought I was so clever using scratchpad memory after the >8300 workspace to hold Forth's USER VARIABLEs.  LOL 

The old machine got me again.  I can use the addresses up to 8344 for various system variables.

I tried placing I/O  vectors in the space after that and the !$@#%^ file sys DSR uses some of those locations.  :mad:

 

I have found that >8352 and >836E are un-touched (so far)  so I use those for vectors.

      20 USER: TFLAG             \ TASK flag awake/asleep status
      22 USER: JOB               \ Forth word that runs in a task
      24 USER: DP                \ dictionary pointer
      26 USER: HP                \ hold pointer, for text->number conversion
      28 USER: CSP
      2A USER: BASE
      2C USER: >IN
      2E USER: C/L               \ Chars per line (32 or 40 depending on VDP mode)
      30 USER: OUT               \ counts chars since last CR (newline)
      32 USER: VROW              \ current VDP column (in fast RAM)
      34 USER: VCOL              \ current VDP row (in fast RAM)
\     36 USER: CURRENT
\     38 USER: CONTEXT
      3A USER: LP                \ LEAVE stack pointer.
      3C USER: SOURCE-ID         \ 0 for console,  -1 for EVALUATE, 1 for include
      3E USER: 'SOURCE           \ WATCH OUT! This is 2variable, occupies 3E and 40
\      40 USER: -------          \ used by 'SOURCE
      42 USER: TPAD
\ *********************************************************************
       44 USER: 'KEY?           \ vector to test for key press
\       46 USER: ???     might be ok
\      48 USER: ---             \ DSR use *PROTECTED IN ROOT TASK
\      4A USER: ---             \ DSR use *PROTECTED IN ROOT TASK
\      4C USER: ---             \ DSR use *PROTECTED IN ROOT TASK
\      4E USER: ---             \ DSR use *PROTECTED IN ROOT TASK
\      50 USER: ---             \ DSR use *PROTECTED IN ROOT TASK
       52 USER: 'EMIT           \ vector for char. output routine
\      54 USER: ---  1+ DSRSIZ  \ DSR use *PROTECTED IN ROOT TASK
\      56 USER: ---  DSRNAM     \ DSR use *PROTECTED IN ROOT TASK
\      58 USER: ---             \ DSR use *PROTECTED IN ROOT TASK
       6E USER: 'PAGE           \ vector for screen clear routine



#278 TheBF OFFLINE  

TheBF

    Dragonstomper

  • Topic Starter
  • 987 posts
  • Location:The Great White North

Posted Tue Feb 26, 2019 6:37 PM

STRAIGHT     An old PolyForth word

After fighting with the ISR routine and getting it to work, I found I was not happy with how the rest of the system worked using the work around.

Polled I/O works great for keyboard entry so I wondered if there was a way to blast code at the machine when I needed to without fooling around with the GPL and ISR workspaces.

 

Someone here reminded me to disable interrupts for full attention of my polled code and sure enough that worked.

So I create STRAIGHT, a word from PolyForth and now I can blast source code into a big buffer in low RAM whenever I need to at full speed.

 

I had trouble getting the ALC code to wait for the first character so I just gave up and put that in Forth as well as the user notification stuff cuz that's way simpler in Forth.

 

Now I just need to write a little routine to write the buffer to a DV80 file and one to from memory and I have what I wanted. 

PC -> Ti-99 saving and/or compilation without leaving the terminal emulator.

\ STRAIGHT a word from PolyForth
\ Accept chars into a buffer with no echo
\ capable of reading continuous data at 9600 bps

NEEDS MOV, FROM DSK1.ASM9900

CREATE ALLDONE     \ branch here to exit readcom
         R12 RPOP,
         2 LIMI,
         R1 TOS MOV,  \ get the char count to Forth TOS
         NEXT,
DECIMAL
CODE READCOM ( addr n -- n' )
         R12 RPUSH,
         PORT @@ R12 MOV,       \ select the 9902
        *SP+ W MOV,             \ addr ->W   (ie: R8)
         W TOS ADD,             \ calc last address ->TOS
         R0 SETO,               \ set timeout register >FFFF
         R1 CLR,                \ reset char counter
         0 LIMI,                \ we need the entire machine
         BEGIN,
            21 TB,
            EQ IF,
               *W+ 8 STCR,    \ put char in buf & inc
                18 SBO,       \ clr rcv buffer
                R0 SETO,      \ reset timeout
                R1 INC,       \ count char
            ELSE,
                 R0 DEC,      \ no char, dec TIMEDOUT
                 EQ IF,
                    ALLDONE @@ B,
                 ENDIF,
            ENDIF,
            W TOS CMP,        \ W =   end of buffer ?
        EQ UNTIL,
        ALLDONE @@ B,
        ENDCODE

: STRAIGHT   ( addr len -- n)
       SWAP 1+ TUCK 1-   ( addr+1 n addr)
       CR ." Send file now..."
       KEY SWAP C!     \ store first Char
       READCOM
       CR ." Complete"  CKEY? DROP 
       CR ;

HEX


#279 TheBF OFFLINE  

TheBF

    Dragonstomper

  • Topic Starter
  • 987 posts
  • Location:The Great White North

Posted Wed Feb 27, 2019 9:26 PM

Xon/Xoff in Forth

 

I thought it would be handy to include a way to control the TI-99 sending data to the terminal. I remember using control S and control Q on the DEC 10 Terminal in the old days.

It means that any utility you write that is gushing data to the terminal can be stopped and started with the same key strokes. Handy.

 

By changing the routine that is plugged into the output vector 'EMIT, we get Xon/Off in Camel Forth.

 

In the process I discovered that making a  simple one byte buffer for a serial port receive routine has a benefit.

I only update the buffer if a new key was pressed.  It means the (XEMIT) routine does not have to run any CRU code to read the flow control key. 

 

Edit:  The reason this can work is because I read the keyboard in the utilities for a "break" by the user, therefore KBUFF gets filled with key while DUMP, or DIR etc. are running.

\ this is cross-compiler Forth

VARIABLE: KBUFF           \ holds the last char rcv'd

[CC] DECIMAL
CROSS-ASSEMBLING
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,  \ record the key press
         ENDIF,
         R12 RPOP,
         2 LIMI,
         NEXT,
         END-CODE

Xon Xoff in Forth

I recant: reading the byte buffer did not really give much advantage. Code changed.

\ XONXOFF.FTH
HEX
11 CONSTANT ^Q
13 CONSTANT ^S

: (XEMIT)  ( c -- )   \ * XON/XOFF version*
         KEY? ^S =
         IF
           BEGIN
              PAUSE    \ let another task have a turn while we wait
              KEY? DUP 3 = ABORT" ^C"
              ^Q =
           UNTIL
         THEN
         CEMIT ;   \ send c to comm TTY1

: XON/XOFF   ( -- ) ['] (XEMIT)  'EMIT ! ;
: NOHANDSHK  ( -- ) ['] (EMIT)   'EMIT ! ;

Edited by TheBF, Thu Feb 28, 2019 10:44 AM.


#280 TheBF OFFLINE  

TheBF

    Dragonstomper

  • Topic Starter
  • 987 posts
  • Location:The Great White North

Posted Sun Mar 3, 2019 8:33 PM

Making a Sound Lexicon for the TMS9919

 

Many years ago I remember wondering how I might tackle the challenge of programming the TMS9919 with a set of Forth words.

I spent some time today working on how it might be done and I modified my preliminary work.

 

This version lets you do the minus number duration trick that we have in TI- BASIC by running a very small ISR that just keeps trying to turn off the sound channels if the volume number is not zero.

 

The other thing I always wanted was  a  way to play BASS notes by frequency in Herz, so this word set has the word ( dur freq vol ) BASS which makes it easy.

Using the same math we can also play white noise notes that track frequency.  No kidding!

 

Here's the code.  I will have to make some demo recordings.  At the moment I have been using Vorticon's Stratego game sounds for inspiration.

 

EDIT: Created the word PLAY to save memory and improve code clarity

 

Spoiler

Edited by TheBF, Mon Mar 4, 2019 6:22 PM.


#281 TheBF OFFLINE  

TheBF

    Dragonstomper

  • Topic Starter
  • 987 posts
  • Location:The Great White North

Posted Tue Mar 19, 2019 6:30 AM

Semantic Power of the 9900 Instruction Set (Fantastic!)

 

While doing some analysis of how improve compiling times I zoomed in on a word in Camel Forth called DIGIT?.  This word takes an ascii character and converts it to a numeric value. It returns two arguments.

If the conversion is good the number and a true flag is left on the data stack. If the conversion is bad, the input character and a false flag are left on the data stack.

Camel Forth defines this function in Forth using some clever binary logic. 

 

However this word is called in a loop to convert multi-digit numbers so it was a good target to improve the speed of number interpretation and compilation.

 

Camel Forth's DIGIT? (original comments by Dr. Brad Rodriguez)

: DIGIT?     ( char -- n -1)             \ if char is a valid digit
\            (      -- x  0 )            \ if char is not valid
              DUP 39 > 100 AND +         \ silly looking
              DUP 140 > 107 AND -
              [CHAR] 0 -                 \ but it works!
              DUP BASE @ U< ;       

I used the GForth decompiler to see how it was done in GForth, one of the reference implementations of ANS/ISO Forth and I saw this:

: DIGIT?
      30 - 
      DUP 9 U>
      IF 7 - DUP 9 U<=
        IF
          DROP FALSE EXIT
        THEN
      THEN
      DUP BASE @ U>=
      IF
        DROP FALSE EXIT
      THEN
      TRUE ;

Looking at this example I wrote the equivalent in Forth assembler and it's almost a direct translation.  It actually worked the first time I coded it. ;-)

The 9900 instruction set is almost the same level as Forth, when structured branching and looping are added to the assembler.

 

*Notes:

  1. The combination of a jump token and IF,  ( GT IF,)  in this assembler simply create a JMP instruction around the following code to the nearest ENDIF, location.
  2. TOS is an alias for R4, used a cache register for the top value on the Forth data stack
  3. PUSH is a 2 instruction macro that decrements R6 and then moves R4 to the data stack  ( DECT R6    MOV R4,*R6 )

          

The code below puts the equivalent Forth code in the comments

CODE DIGIT? ( char -- n f )           \ : digit?
               TOS PUSH,              \ 2 extra instructions
               TOS -30 AI,            \ 30 -
               TOS 9 CI, GT           \ DUP 9 U>
               IF,                    \ IF
                  TOS -7 AI, LTE      \    7 - DUP 9 U<=
                  IF,                 \    IF
                      TOS CLR,        \       DROP FALSE
                      NEXT,           \       EXIT
                  ENDIF,              \    THEN
               ENDIF,                 \ THEN
               TOS BASE @@ CMP, GTE   \ DUP BASE @ U>=
               IF,                    \ IF
                  TOS CLR,            \     DROP FALSE
                  NEXT,               \     EXIT
               ENDIF,                 \ THEN
               TOS *SP MOV,           \ extra instruction
               TOS SETO,              \ TRUE
               NEXT,                  \ ;
               ENDCODE

Amazing design by TI Engineers all those years ago.

 

 



#282 Lee Stewart OFFLINE  

Lee Stewart

    River Patroller

  • 3,966 posts
  • Location:Silver Run, Maryland

Posted Tue Mar 19, 2019 9:12 AM

FYI, here is the ALC from TI Forth’s DIGIT (from fig-Forth) and the equivalent (I think!) fbForth Assembler code, which only leaves FALSE if the ASCII character cannot be converted to a digit:

Spoiler

 

...lee



#283 TheBF OFFLINE  

TheBF

    Dragonstomper

  • Topic Starter
  • 987 posts
  • Location:The Great White North

Posted Tue Mar 19, 2019 10:11 AM

FYI, here is the ALC from TI Forth’s DIGIT (from fig-Forth) and the equivalent (I think!) fbForth Assembler code, which only leaves FALSE if the ASCII character cannot be converted to a digit:

Spoiler

 

...lee

 

Ah... so the TI guys built this into TI-Forth in the '80s.   Makes sense.

 

The hi-level Forth version Brad did was 48 bytes, the code version based in GForth is 24 bytes and it is approximately 7X faster.  :)

 

All this points to the fact that modern commercial Forth systems have abandoned threaded code for native code. However it is a much harder compiler to build.



#284 Lee Stewart OFFLINE  

Lee Stewart

    River Patroller

  • 3,966 posts
  • Location:Silver Run, Maryland

Posted Tue Mar 19, 2019 10:56 AM

...

Camel Forth's DIGIT? (original comments by Dr. Brad Rodriguez)

: DIGIT?     ( char -- n -1)             \ if char is a valid digit
\            (      -- x  0 )            \ if char is not valid
              DUP 39 > 100 AND +         \ silly looking
              DUP 140 > 107 AND -
              [CHAR] 0 -                 \ but it works!
              DUP BASE @ U< ;       

 

Clever code, indeed—but it confused me at first because of a missing HEX ahead of the definition.  I especially like how the ASCII gap is handled.  It insures that any character in the gap is treated as a number higher than any likely radix (314 – 320), which should fail the comparison at the end of the definition.

 

[Edit:  I should add that the two AND operations will not work in TI Forth or fbForth because operations that yield TRUE or FALSE, unfortunately, render TRUE as 1 rather than -1 (FFFFh) as in the above case.]

 

...lee



#285 TheBF OFFLINE  

TheBF

    Dragonstomper

  • Topic Starter
  • 987 posts
  • Location:The Great White North

Posted Sat Mar 23, 2019 9:56 AM

CAMEL99 Forth Version G Release

 

I forgot how many things I had been working on since last November.  It's good to look back and see how far we've come sometimes.

I just posted version G. It fixes a bug in the interpreter error detection and adds a bunch of new library files.

 

https://github.com/bfox9900/CAMEL99-V2(forgot the link)

 

### Nov 30, 2018 V2.1.G

  • Version G corrects a long-time bug in the interpreter that reported
    "empty stack" under some conditions erroneously (CAMELG2.HSF)
  • Compiler switch name has been changed to USEFORTH (previously SMALLER) because
    sometimes Forth is smaller and sometimes Assembler code is smaller.
  • Version G has a code word for DIGIT? to improved compile times
  • The word ?SIGN is now PRIVATE, not visible in the dictionary to save space
  • The word >NUMBER has been changed slighly from the original CAMEL FORTH that speeds it for the 9900 cpu.
  • The ELAPSE.FTH program has been significantly improved for accuracy and the code size has been reduced.
  • A file based BLOCK system is available as a library: /LIB.ITC/BLOCKS.FTH
  • These blocks are compatible with FBFORTH and Turbo Forth allowing the developer read programs from these other Forth systems. 
    Compiling this code will not be possible without writing a "translation harness" however for simple programs this is not too difficult.
  • A simple demo of BLOCK usage is file LINEDIT80.FTH for use with 80col displays or the TTY based kernel CAMEL99T
  • Data structures per Forth 2012 are now supported in file STRUC12.FTH.
    A simple example is part of the file. (remove or comment out if you use the file)
  • ACCEPT has been changed passing backspace cursor control to EMIT. (see below)
  • EMIT has been changed to handle newline and backspace characters
  • (EMIT) and (CR) i/o primitives can be compiled as Forth or CODE (controlled by USEFORTH )
### CAMEL99T (tty)
  • Version CAMEL99T is built to use RS232/1 as the primary console.
    It has been tested with Tera Term, Hyper-terminal and PUTTY under windows 10.
    Terminal configuration is 9600,8,n,1, hardware handshake.
  • A word VTYPE ( $addr len VDPaddr -- ) is part of the CAMEL99T to allow simple printing to the VDP screen at a screen address. (no protection!)
  • Library file call XONXOFF.FTH vectors EMIT to provide XON/XOFF protocol.
  • File VT100.FTH can be included to provide cursor control for a VT100 terminal.

Edited by TheBF, Sat Mar 23, 2019 11:54 AM.


#286 TheBF OFFLINE  

TheBF

    Dragonstomper

  • Topic Starter
  • 987 posts
  • Location:The Great White North

Posted Wed Apr 3, 2019 9:56 AM

The DSRLINK...
 
I am forever grateful for insanemulti-tasker and the TI tech pages for giving me the foundation for DSRLINK. I could not resist trying to understand it better.
 
In going through what I was using, I found a number of lines that did not make sense and a couple of variables that I thought could be eliminated by using immediate operations rather than indirect addressing.
 
I improved some of my comments and when I was done the kernel was 44 bytes smaller using this version for DSRLINK.
 
One of the savings was removing the static string buffer NAMEBUF.  Instead I used the un-allocated memory in the CAMEL99 HEAP (low RAM).
The system variable 'H' always contains the address of free memory in the heap. It's probably got some corner cases where I could clobber it, like if I allowed a preemptive task to change the value of 'H' with MALLOC, but I don't use preemptive multi-tasking so I am not too worried. I think I can manage it the next time I have to use CAMEL99 Forth for a space mission with NASA. :grin:
 
The spoiler has the new version. 
Edit: Updated to latest code

 

Spoiler

\ DSRLNK  Ver 9 for XFC99 cross-compiler/Assembler

\ PASSES error code back to Forth workspace, TOS register

\ Source:
\ http://atariage.com/forums/topic/283914-specialized-file-access-from-xb/page-2
\ Post by InsaneMultitasker  Original: Thierry Nouspikel (?)

\ - Re-write to used CAMEL Forth Heap via the variable 'H' for NAMBUF
\ - Changed some jumps to structured loops & IF/THEN
\ - removed some unused code ( at least it looks unused)
\ - saved 44 bytes!!                                        B. Fox

CROSS-ASSEMBLING  XASSEMBLER DEFINITIONS

\ we need more labels than I normally use for Forth style CODE Words
 A DUP refer: @@A    binder: @@A:
 B DUP refer: @@B    binder: @@B:

\ === MACROS ===

\ set the VDP address from a register argument
: VDPWA, ( reg -- )
       DUP           SWPB,   \ setup VDP address
       DUP VDPWA @@  MOVB,   \ write 1st byte of address to VDP chip
       DUP           SWPB,
           VDPWA @@  MOVB,   \ write 2nd byte of address to VDP chip
                     NOP,  ; \ need this tiny delay for VDP chip

\ gives access to Forth R4. (top of stack cache)
: [TOS]    8 (R13)  ;

\ === DSR WORKSPACE ======
[CC] HEX
 RP0 80 -     EQU DREGS    \ use memory below Forth RETURN stack for workspace
 5 2* DREGS + EQU DREG(5)  \ compute address of DREGS register 5

TARGET-COMPILING
\ === DATA BYTES ===
l: HEX20   20 BYTE,
l: HEXAA   AA BYTE,
l: DOT     2E BYTE,    \ ascii period
          .EVEN

CLR-JMPTABLE
\ === DSR ENTRY POINT ===
l: DSR1                      \ label creates headless code
      *R14+     R5   MOV,    \ get '8'->R5, auto inc R14, for return
       HEX20 @@ R15  SZCB,   \ >20 eq flag=0
       8356 @@  R0   MOV,    \ [PAB FNAME] to R0
       R0       R9   MOV,    \ dup R0 in R9
       R9       -8   ADDI,   \ R9-8 = [PAB FLG]
       R0           VDPWA,   \ set VDP address to address in R0
       VDPRD @@ R1   MOVB,   \ R1= length of FNAME

\ setup to copy VDP FNAME ->namebuf to '.' character
       R1       R3   MOVB,   \ DUP length byte to R3
       R3       08   SRL,    \ swap the byte to other side
       R4            SETO,   \ R4 = -1
       H @@      R2 MOV,     \ unused heap becomes temp. namebuf
       BEGIN,                \ search for length match and/or period in name
         R0            INC,    \ point to next fname VDP address
         R4            INC,    \ counter starts at 0
         R4       R3   CMP,    \ is counter = fnamelength
         @@1           JEQ,    \ if true goto @@1:
         R0          VDPWA,    \ set VDP address
         VDPRD @@ R1  MOVB,    \ read next VDP char from fname
         R1      *R2+ MOVB,    \ copy to namebuf & inc pointer
         R1    DOT @@ CMPB,    \ is it a '.'
       EQ UNTIL,               \ until '.' found  34 bytes!!!

\ ==== error checks ====
@@1:   R4        R4  MOV,    \ test R4 (device name length)=0
       @@6           JEQ,    \ if so, goto ERROR 6
       R4        07  CMPI,   \ is dev name length>7
       @@8           JGT,    \ if so, goto @@8 (ERROR6)
       83D0 @@       CLR,    \ erase magic CRU addr. holder
       R4   8354 @@  MOV,    \ put length in magic address
       R4            INC,    \ +1 points to '.' character
       R4   8356 @@  ADD,    \ add offset to PAB address (makes "real PAB")

\ ==== GPL WORKSPACE ====
       83E0         LWPI,    \ SROM (search ROM device list)
       R1           CLR,     \ MAGIC GPL REGISTER=0
       R12     1000 LI,      \ init CRU base to 1000
@@A:   BEGIN,                \ scan for I/O cards
         R12   R12   MOV,
         NE IF,              \ if card address<>0
              00 SBZ,        \ turn off card
         ENDIF,
         R12    0100  ADDI,  \ advance CRU to next card
         R12    2000 CMPI,   \ test for last card address
         @@5          JEQ,   \ no more cards. goto ERROR5
\ card activation...
         R12  83D0 @@ MOV,   \ save card CRU in magic address
         00           SBO,   \ turn on the card
         R2   4000    LI,    \ ROM start addr -> R2
        *R2  HEXAA @@ CMPB,  \ test for card present
       EQ UNTIL,             \ loop until card is found

       DREG(5) @@ R2 ADD,    \ add '8'+4000= >4008 = "DSR ROM List"
       @@B          JMP,

@@3: \ scan ROM linked list for code address
      BEGIN,
          BEGIN,
            83D2 @@   R2 MOV,   \ start of ROM device list -> R2
            00           SBO,   \ turn card on
 @@B:      *R2       R2  MOV,   \ Fetch next link
            @@A          JEQ,   \ if link=0 goto @@A (NEXT CARD)
            R2  83D2 @@  MOV,   \ save link address in magic address
            R2           INCT,  \ R2 = code pointer
           *R2+      R9  MOV,   \ fetch code address ->R9
            8355 @@  R5  MOVB,  \ dev length->R5
            @@4          JEQ,   \ if 0 we have a string match
            R5      *R2+ CMPB,
         EQ UNTIL,

\ find dev string match
         R5         08  SRL,    \ shift length byte
         H @@       R6  MOV,    \ heap ->R6 is NAMEBUF
         BEGIN,
            *R6+   *R2+ CMPB,   \ compare namebuf to ROM string
             @@3        JNE,    \ if mismatch goto @@3
             R5         DEC,    \ dec the counter register
         EQ UNTIL,

\ === run DSR code ===
@@4:     R1            INC,    \ count entries into the DSR ?
        *R9            BL,     \ call the DSR code
      AGAIN,                   \ try next card

\   -- DSR returns here if we are done --
       00            SBZ,  \ Turn off the card
       DREGS         LWPI, \ ==== DSR Workspace ====
       R9           VDPWA, \ set vdp address
       VDPRD @@  R1  MOVB, \ read error value to DREGS R1
       R1 0D         SRL,  \ shift error to correct range
       @@7           JNE,  \ if error<>0 goto @@7
                     RTWP, \ else return to Forth workspace

\ error condition handlers
@@5:   DREGS         LWPI, \ we came from GPL workspace, restore DREGS
@@6:                       \ device name length=0
@@8:   R1            SETO, \ device name length>7
@@7:
       GPLSTAT @@ R0 MOVB, \ get gpl status byte
                  R0 SWPB,
       R0       0020 ANDI, \ mask to get GPL error bit
       R0         R1 OR,   \ combine GPL & DSR error codes
       R1     [TOS]  MOV,  \ put error code in Forth TOS
                     RTWP, \ return to Forth

\          ******* DSRLINK ENDS *******
\ /\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/

\ create the vector for BLWP
l: DLNK
        DREGS DATA,        \ the workspace
        DSR1  DATA,        \ entry address of the code

CODE: DSRLNK  ( [pab_fname] -- ior)
          TOS 8356 @@ MOV,
          TOS CLR,
          TOS GPLSTAT @@ MOVB,   \ clear GPL status register
          0 LIMI,                \ critical that we disable interrupts here.
        DLNK @@ BLWP,
          8 DATA,
          2 LIMI,
        NEXT,
        END-CODE

Edited by TheBF, Thu Apr 11, 2019 6:18 PM.


#287 TheBF OFFLINE  

TheBF

    Dragonstomper

  • Topic Starter
  • 987 posts
  • Location:The Great White North

Posted Thu Apr 4, 2019 7:31 AM

The old saying goes "Any program that can be written in 1000 bytes can be written in 999 bytes".

 

Integrating DSRLINK into Forth means I have other ways to pass parameters than just using registers.

I realized that DSRLINK could take a parameter from the stack. The parameter it needed was the PAB file-name address moved to >8356.

 

Previously I had been moving the PAB file-name  to >8356 in the FILEOP command with FORTH like this:

: FILEOP  ( opcode -- err)                   \ TI99 O/S call
          [PAB VC!                           \ write opcode byte to VDP PAB
          [PAB FLG] DUP VC@ 1F AND SWAP VC!  \ clear err code bits
          0 GPLSTAT C!                       \ clear GPL status register
          [PAB FNAME] DSRNAM !               \ ** THIS LINE ***
          DSRLNK ( -- err)                   \ DSRLINK with parameter 8
          GPLSTAT C@ 20 AND  OR              \ get GPL status, or with err
;

By changing 1 line in DSRLNK to take a parameter from the stack and stuff it into >8356, I save 4 bytes and speed up my FILEOP command a little.

: FILEOP  ( opcode -- err)                   \ TI99 O/S call
          [PAB VC!                           \ write opcode byte to VDP PAB
          [PAB FLG] DUP VC@ 1F AND SWAP VC!  \ clear err code bits
\          0 GPLSTAT C!                      \ *** MOVE INTO DSR routine
          [PAB FNAME] DSRLNK ( -- err)       \ *** PASS filename to DSRLNK **
\          GPLSTAT C@ 20 AND  OR             \ *** MOVE INTO DSR routine
;

New DSRLNK call looks like this:

HEX
CODE: DSRLNK  ( [pab_fname]-- ior)
        TOS 8356 @@ MOV,    \ ** this line ** replaces TOS PUSH, (2 instructions)
        TOS CLR,
        0 LIMI,          
        DLNK @@ BLWP,
        8 DATA,
        2 LIMI,
        NEXT,
        END-CODE

And this saves another 2 bytes, because I had to PUSH the TOS register to make room for the error code anyway. 

 

EDIT: And while I am here I just removed the last line and put it into the DSR routine. This makes FILEOP faster, but added 2 bytes versus the FORTH version. (Yes it's true, Forth and be smaller than ALC, but not always)

 

EDIT2:   And why not move the line that clears the GPL status byte into DSRLNK too?  That saves my 2 bytes I just lost.  :)

 

EDIT3:  These changes improved compile times from floppy disk by 2.6%  on real iron versus Version "F"  Nice!

CODE: DSRLNK  ( [pab_fname]-- ior)
          TOS 8356 @@ MOV,
          TOS CLR,
          TOS GPLSTAT @@ MOVB,   \ clear GPL status register
          0 LIMI,                \ critical that we disable interrupts here.
        DLNK @@ BLWP,
          8 DATA,
          2 LIMI,
        NEXT,
        END-CODE


Edited by TheBF, Thu Apr 4, 2019 8:41 AM.


#288 TheBF OFFLINE  

TheBF

    Dragonstomper

  • Topic Starter
  • 987 posts
  • Location:The Great White North

Posted Mon Apr 8, 2019 9:11 PM

They Don't Really Use Forth Anymore Do They?

 

I thought the gang here might like to see this video while they need a break from debugging.

 

(or while waiting for C to compile)  :_(  (It's a joke)  ;-)

 

https://wiki.forth-e...8:forth-in-that



#289 InsaneMultitasker OFFLINE  

InsaneMultitasker

    River Patroller

  • 2,427 posts

Posted Mon Apr 8, 2019 11:31 PM

The DSRLINK...

 

I am forever grateful for insanemulti-tasker and the TI tech pages for giving me the foundation for DSRLINK. I could not resist trying to understand it better.


\ Source:
\ http://atariage.com/forums/topic/283914-specialized-file-access-from-xb/page-2
\ by InsaneMultitasker via Thierry Nouspikel

 

Nice job working through that DSRLNK code.  I might have mentioned it before (and if not, I will say it here) that I did not write the DSRLNK and never intended to give you that impression. That version has been in my 'toolbox' for ages; I just passed it along.  :)



#290 TheBF OFFLINE  

TheBF

    Dragonstomper

  • Topic Starter
  • 987 posts
  • Location:The Great White North

Posted Tue Apr 9, 2019 2:03 PM

 

Nice job working through that DSRLNK code.  I might have mentioned it before (and if not, I will say it here) that I did not write the DSRLNK and never intended to give you that impression. That version has been in my 'toolbox' for ages; I just passed it along.  :)

 

Understood.  Somehow that version made a little more sense to me than others I had looked at.

That made it easier to integrate into my Forth system.



#291 TheBF OFFLINE  

TheBF

    Dragonstomper

  • Topic Starter
  • 987 posts
  • Location:The Great White North

Posted Thu Apr 11, 2019 10:42 AM

In case you ever wondered...

 

After playing for over a year a various optimizations I thought I should create a "mostly" Forth version for educational purposes. My entire reason for this project was to learn about cross-compiling Forth and that hopefully others could get jumpstart should they ever want to try it themselves.

 

So this version of the code has been cleaned of wordy comments and most of the code is Forth. 

The VDP driver is written in Forth here as well using a few VDP routines so that's interesting. It seems to perform quite well too.

 

There is another file of Assembly language primitives that are the un-pinnings of Forth, but the spoiler is just the hi-level language to make a Forth compiler and interpreter written in Forth.

 

Spoiler

 

Edit: comment fix


Edited by TheBF, Thu Apr 11, 2019 2:01 PM.


#292 TheBF OFFLINE  

TheBF

    Dragonstomper

  • Topic Starter
  • 987 posts
  • Location:The Great White North

Posted Yesterday, 11:51 AM

Re-visiting Direct Threaded Code (DTC)
 
I was working on the DTC version of CAMEL99 Forth because I had not figured out how to make DOES> work.  
For the non-forther CREATE DOES>  gives forth a very simple form of object oriented programming that pre-dates OOP by about 15 years.
 
I took to reading the bible on the matter Brad Rodriguez's papers called "Moving Forth" 
 
In Part 3 http://http://www.br...ers/moving3.htm  we can read about how DOES> works with indirect threading, direct threading and sub-routine threading.

While reading this over I realized that I had missed something about DTC.
 
DTC works by  creating ALC routines just like you would in assembler but you end them with a branch to a 2 instruction routine call "next" that works like "return" but uses the Forth return Stack.
(typically this routine's address is kept in a register so it is  B *R10 for example which is only 2 bytes for each Forth routine.



\ Forth DTC NEXT routine in Forth Assembler 
\ IP is the instruction pointer register for the Forth virtual machine (R9 in CAMEL99 forth)

l: _next                     
       *IP+ R5 MOV,    \ read contents at IP into R5, auto inct IP
           *R5 B,      \ branch to the address in R5       

This is great for code words. Very simple and you get nestable sub-routine calls with only 2 instructions.  Not bad!

But Forth words are lists of addresses so they need a routine to "interpret" those lists.  To enter a Forth word we use DOCOL
( called "do colon" because ":" is how we create a new Forth word)
 
In a DTC system we need to start every Forth word with a branch to that DOCOL Routine like below: 

<wordname>  <B @DOCOL >  <forth> <forth> <forth> etc...

 
But the list of Forth addresses starts 4 bytes after the branch instruction so when we run DOCOL, I used a temp register to keep track of this and advance it by 4 bytes to get to the correct place with Forth "instructions".
My old docol is shown below.

l: _docol     IP RPUSH,
              R8 4 ADDI,      \ jump past the code fragment in the Forth word
              R8 IP MOV,      \ move new IP address into Forth IP register              
              NEXT,           \ goto next routine

  
Brad mentions using a JSR instruction (jump to subroutine) to make this easier but I always thought we needed a stacked sub-routine address to make this work like in the 6809 CPU example.
 
BUT NO!
 
The reason to use JSR is because it automatically computes the address where we need to return to,  which is ...  4 bytes ahead!
 
So the BL instruction takes care of that perfectly by putting that special address in R11 AUTOMATICALLY!   So all I needed to do was this:

\ Using Branch and Link

<wordname>  <BL @DOCOL >  <forth> <forth> <forth> etc...
                         ^ 
                         |  
\ R11 points to here: ---^  YEAH!

So my new DOCOL looks like this:

l: _docol     IP RPUSH,      
              R11 IP MOV,    
              NEXT,        \ EDITed

And this benefit extends to the "Executor" routines for variables and constants too:

\ Executor that executes a "CONSTANT"
l: _docon    TOS PUSH,      \ make room in TOS
             *R11 TOS MOV,  \ move PFA into Forth IP register    14
              NEXT,

 \ Executor that executes a "VARIABLE"
l: _dovar     TOS    PUSH,   \ make room in TOS                   28
              R11  TOS MOV,  \ move PFA into Forth IP register    14
              NEXT,

I still haven't got DOES> working but the new DTC Forth system runs between 10% and 21% faster than the ITC system. 

Forth word headers still consume 4 bytes extra however. But CODE words are 2 bytes smaller.

 

DTC also means that I can begin "inlining" small CODE routines seamlessly into Forth definitions so I need to explore making a peep hole optimizer on the Forth compiler.

Many Forth primitives are only one 9900 instruction so this will work really well.

 

So much code, so little time

 

Happy Easter and a Blessed Passover 


Edited by TheBF, Yesterday, 1:49 PM.






Also tagged with one or more of these keywords: Camel99, Forth, Concatentive Programming, ANS Forth

0 user(s) are browsing this forum

0 members, 0 guests, 0 anonymous users