Jump to content
IGNORED

Camel99 Forth Information goes here


TheBF

Recommended Posts

Well I am really enjoying having a working file system on Camel99 Forth. :-D

\ print string left justified
: $.LEFT  ( $ width -- ) 
          OVER C@ - >R COUNT TYPE   R> SPACES ;

DECIMAL
: ?CR     OUT @ 10 + C/L@ > IF CR THEN ;

HEX
: DIR  ( <DSK?.> )   \  needs the '.' ONLY shows file name
          BL PARSE-NAME DUP ?FILE
          RELATIVE 100 FIXED R/O BIN OPEN-FILE ?FILERR
          >R                            \ push handle onto Return stack

          PAD 50 R@ READ-LINE ?FILERR
          CR PAD COUNT TYPE CR

          LINES OFF
          BEGIN
             PAD 50 R@ READ-LINE ?FILERR
          WHILE
             DROP                       \ don't need the byte count
             PAD 0A $.LEFT 2 SPACES ?CR
             ?TERMINAL                  \ check for *BREAK* key
             IF R> CLOSE-FILE           \ if detected we're done here
                2DROP
                CR CR ." *BREAK*" ABORT
             THEN 1 LINES +!
          REPEAT

          R> CLOSE-FILE
          2DROP 2DROP
          DECIMAL
          CR CR LINES @ . ." files"
          HEX ;

post-50750-0-44663800-1522614182.jpg

  • Like 1
Link to comment
Share on other sites

Version 2.0.5 is On GitHub

 

https://github.com/bfox9900/CAMEL99-V2

 

  • Found some ways to simplify the kernel and remove some names from the dictionary in FILESYSD
  • Fixed a bug in ANSFILES.F that broke "INCLUDE".
  • Uploaded the DIR.F and MORE.F
  • The new STRINGS.F package is pretty fast and let's you do most of what you can do in BASIC.

Todo:

  • Add LOAD and SAVE function
  • Create an editor
  • Make the editor a binary overlay for rapid loading inside the system.

 

Soon I will have to wake up my real iron, repair it and see if this all works in the real world.

 

BF

Link to comment
Share on other sites

Preliminary CAMEL99 Forth Document Available

 

https://github.com/bfox9900/CAMEL99-V2/tree/master/DOCS

 

I have created a document to help BASIC programmers understand the things added to Forth for TI BASIC users.

It has a few example programs in the text to let people see how these additions work. I feel like these are the best way to explain things.

 

Let me know if anything doesn't make sense or is broken and I can keep working on it.

 

The system feels pretty stable to me for what it does. I am sure some real users will find the killer bugs pretty quickly.

 

B

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

 

Very well-written document! I have not had a chance at low-level scrutiny (will get there later), but I like what I see. :)

 

...lee

 

Thanks

 

I have found some errors myself already. :-)

Appreciate your eagle eyes when you have the time.

Link to comment
Share on other sites

I am writing and writing... to make something of an instruction manual for CAMEL99. I started on the Assembler and wrote this for the opening. I think it is worth sharing.

 

 

Learning Assembly Language the Easy Way

One of the big secrets about Forth is the Forth Assembler. It gives you a way to learn Assembly language in a way that is so much less painful than the traditional Assembler process. You can learn by writing tiny routines that do simple things but very quickly. You must still understand how the TMS9900 CPU operates and any other system details that your program uses but it follows the “How do you eat an elephant principle?” Answer: Piece by piece.

Consider this traditional Assembly language work flow:

1. Write your program in the editor, save as SOURCE file

2. Assembler the program with the Assembler, giving OBJECT file.

3. *Link the OBJECT file with the LINKER giving BINARY file

4. Load the BINARY file into RAM and watch it CRASH

5. Goto 1

*TI-99 joins step 3 and 4 with a special “LINKING LOADER” program so they were aware of this issue.

Now consider how you make and Assembler program in Forth”

1. Start CAMEL99 Forth

2. Load the Assembler (becomes part of Forth)

3. Write a short CODE word in Assembly language

4. Test the CODE word by typing its name

A CODE Word Example

Let’s imagine we wanted a way to increment a Forth variable by two at maximum speed. It turns out that the 9900 CPU can do that in one instruction. Very fast. Let’s test this idea in the Forth console.

INCLUDE DSK1.TOOLS.F \ give us the programmer tools

INCLUDE DSK1.ASM9900.F \ give us the Assembler words

\ “two-plus-store” adds 2 to the contents in addr

\ TOS is the CPU register where CAMEL99 caches the “top of stack” value

CODE 2+! ( addr -- ) *TOS INCT, NEXT, ENDCODE

\ test it at the Forth console

VARIABLE X

X ? 0 ok

X 2+!

X ? 2 ok

X 2+!

X ? 4

Seems to work. We are done!

“2+!” is now just another word in the Forth dictionary but it runs really fast.

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

Latest Edition of CAMEL99 Doc is up on GitHub

 

Revision .5 contains a lot more material that lets you get started playing with Forth.

Introduction	8
About CAMEL Forth	8
What you have	9
Library Files	9
File Format	9
Only Needs the E/A Package.	9
File Naming Convention (Optional)	9
Forth Terminology	10
Standard Forth vs CAMEL99 Forth	12
Library files Available with CAMEL99 Forth	12
The Forth Programming Pyramid	13
*Incremental Compiling	13
Loading CAMEL99	14
DSK1.START	14
Lesson 1: Jump Right in	15
Hello World	15
The Colon Compiler	16
Final Thoughts on Hello World	19
Error messages	19
Lesson 2: Transition from BASIC to Forth	20
Structured Programming	21
Moving Closer to Forth Style	21
Trim the Fat	21
Minimal	22
Factoring is the key to good Forth	22
Lesson 3: The DATA Stack	23
What is a computer stack?	23
A Few More Math Examples	25
A Fundamental Difference between BASIC and Forth	25
Why do we use a Stack?	25
EMIT	26
Stack Diagrams	27
Lesson 4: The DO LOOP	28
And one more thing…	30
If you are very curious	30
Strings in Forth	31
CAMEL99 String Word Set	31
Using CAMEL99 String Words	32
Technical Details about STRINGS.F	33
Other Facts	33
Graphics Words	34
A New Word for Convenience	36
COLOR in CAMEL99	37
Memory Tips and Tricks	38
High CPU RAM	38
Low CPU RAM	38
VDP Memory	38
SAMS Memory	38
Fetch and Store for each Space	38
Memory Operators	39
CPU RAM Memory Words	39
VDP Memory Words	39
SAMS Card Memory	39
Stealing Memory Temporarily	41
Temporary Memory Example Program	43
Multi-Tasking	44
Why Multi-Task?	44
Multi-Tasking Commands	44
TASK SWITCHER TECHNICAL EXPLANATION	46
Techie Stuff for the TMS9900 Nerd	47
WARNING for Assembly Language Users	47
CAMEL99 MULTI-TASKING USER AREA	48
Example Multi-tasking Code	49
Assembly Language the Easy Way	50
A CODE Word Example	50
Understanding Our Code Word	51
CAMEL99 Assembler vs TI Assembler	52
Forth Assembler Differences	52
Code Comparison	52
Special Registers in the Forth Machine	53
Proper Use of the TOS Register	53
Structured Branching and Looping	55
Example Programs	56
Random Color Dots	56
Guess the Number in Forth	57
GRAPHICS Example: “Denile”	58
Forth Style Version of Denile	61
Important Idea	61

Many little repairs to demonstration programs.

It never ends but I have other work for today.

 

Happy Friday the 13th :skull:

 

 

 

 

 

  • Like 2
Link to comment
Share on other sites

Between power outages due to the ice storm I have been working to improve the speed of the CAMEL99 V2 kernel but stay within the 8K limit of the cross-compiler.

 

It is fascinating that many times Assembler code takes more bytes to implement a simple routine that Forth.

So the game is truly finding the places that make a difference.

 

One routine that seems to perk up the system is the Forth word HERE which returns the address of the next available memory in the dictionary.

It does nothing but fetch the contents of the dictionary pointer variable called DP.

Since HERE is used in a lot of places in the kernel, using the extra 2 bytes it takes to code it in Assembler makes a nice improvement.

\ it turns out that by making HERE faster, the system goes faster because HERE is used a lot.
\ : HERE   DP @ ; (Forth version)

CODE: HERE   ( -- addr) 
             TOS PUSH,  
             DP @@ TOS MOV,  
             NEXT, 
             END-CODE

The other routine that I have benchmarked with Turbo Forth is scrolling. TF uses Assembler and also provides a lot more functionality but in normal scrolling it was much faster.

 

I have finally got a Forth based scroll that uses a 2 line buffer that seems to scroll up at about the same speed as TF.

The routine takes advantage of the Forth DATA stack to hold values for reading VDP and writing VDP.

This makes it a little cryptic but it works.

 

By changing the constant C/S you can make the line buffer bigger.

 

In 80 col mode however I find taking 4 lines (360 bytes) a little extreme and performance does not improve much.

So this is now my final scroll.

[CC] C/L @ 2* [TC] CONSTANT: C/S              \ chars per scroll

: SCROLL      ( -- )
              C/S DUP                         \ get char per scroll and duplicate
              MALLOC ( -- c/s heap)           \ allocate chars per scroll in heap
              C/SCR @  C/L@ VTOP @ +          \ loops from 2nd line, to end of screen
              DO
                 I  ( -- c/s heap scr-addr)
                 OVER 2DUP    C/S VREAD      \ read chars/scroll to heap
                 PAUSE
                 SWAP C/L@ -  C/S VWRITE      \ write HEAP to line above
              C/S +LOOP                       \ advance loop by chars per scroll

              0 17 CLRLN                      \ clear last line
              DROP                            \ drop heap pointer
              MFREE ;                         \ de-allocate heap memory

Version 2.0.8 will go up on GitHub .... if the power stays up . ;-)

Edited by TheBF
Link to comment
Share on other sites

I found another couple of words that make a significant difference without taking more space.

 

>DIGIT converts a small number to an ASCII digit.

HOLD puts a digit into memory in a little buffer and maintains a pointer into the buffer going right to left as a number is converted digit by digit.

 

Both of these are part of the hi level command called '#' which puts both >DIGIT and HOLD inside a loop.

Because they are inside a primary loop making them faster improves performance with every iteration.

 

Here is their Forth code

: >DIGIT ( n -- c) DUP 9 > 7 AND + 30 + ; \ convert n to ascii digit c

\ decr. HOLD pointer HP, Store char at the address contained in HP
: HOLD   ( char -- )  -1 HP +!  HP @  C! ;

And here are their ALC replacements

CODE: HOLD  ( char -- )  \ 2 BYTES bigger, 4X faster
            HP @@   DEC,
            HP @@ W MOV,
            TOS     SWPB,
            TOS  *W MOVB,
            TOS     POP,
            NEXT,
            END-CODE

\ : >DIGIT ( n -- c) DUP 9 > 7 AND + 30 + ; \ convert n to ascii digit c
 CODE: >DIGIT  ( n -- c)   \ ASM is 8 bytes smaller 4X faster
            TOS 9 CMPI,
            @@1 JLE,       \ if n<=9 jump to convert it
            TOS  7 ADDI,   \ else number is not base 10, add 7
 @@1:        TOS 30 ADDI,  \ add 30 to create ASCII value
            NEXT,
            END-CODE

So I save space on these two and number printing measure about 50% faster.

 

The is new code is up on GITHUB now.

  • Like 1
Link to comment
Share on other sites

Between power outages due to the ice storm I have been working to improve the speed of the CAMEL99 V2 kernel but stay within the 8K limit of the cross-compiler.

 

It is fascinating that many times Assembler code takes more bytes to implement a simple routine that Forth.

So the game is truly finding the places that make a difference.

 

One routine that seems to perk up the system is the Forth word HERE which returns the address of the next available memory in the dictionary.

It does nothing but fetch the contents of the dictionary pointer variable called DP.

Since HERE is used in a lot of places in the kernel, using the extra 2 bytes it takes to code it in Assembler makes a nice improvement.

\ it turns out that by making HERE faster, the system goes faster because HERE is used a lot.
\ : HERE   DP @ ; (Forth version)

CODE: HERE   ( -- addr) 
             TOS PUSH,  
             DP @@ TOS MOV,  
             NEXT, 
             END-CODE

The other routine that I have benchmarked with Turbo Forth is scrolling. TF uses Assembler and also provides a lot more functionality but in normal scrolling it was much faster.

 

I have finally got a Forth based scroll that uses a 2 line buffer that seems to scroll up at about the same speed as TF.

The routine takes advantage of the Forth DATA stack to hold values for reading VDP and writing VDP.

This makes it a little cryptic but it works.

 

By changing the constant C/S you can make the line buffer bigger.

 

In 80 col mode however I find taking 4 lines (360 bytes) a little extreme and performance does not improve much.

So this is now my final scroll.

[CC] C/L @ 2* [TC] CONSTANT: C/S              \ chars per scroll

: SCROLL      ( -- )
              C/S DUP                         \ get char per scroll and duplicate
              MALLOC ( -- c/s heap)           \ allocate chars per scroll in heap
              C/SCR @  C/L@ VTOP @ +          \ loops from 2nd line, to end of screen
              DO
                 I  ( -- c/s heap scr-addr)
                 OVER 2DUP    C/S VREAD      \ read chars/scroll to heap
                 PAUSE
                 SWAP C/L@ -  C/S VWRITE      \ write HEAP to line above
              C/S +LOOP                       \ advance loop by chars per scroll

              0 17 CLRLN                      \ clear last line
              DROP                            \ drop heap pointer
              MFREE ;                         \ de-allocate heap memory

Version 2.0.8 will go up on GitHub .... if the power stays up . ;-)

 

 

2 STEPS FORWARD,

1 STEP BACK

DOIN' THE SOFTWARE 2 STEP...

 

I will be publishing version 2.0.9 later today because this little gem had a bug where it killed the top 2 records of my sprite table when it scrolled in GRAPHICS mode. I tested with my PONG demo program but of course PONG does not scroll.

 

I can't use a constant that is pre-calculated for all modes. DUH!

 

B

Link to comment
Share on other sites

ANS/ISO Forth Files

 

I am in the process of documenting the handle based file system in CAMEL99 Forth.

It seems to work pretty well. The ANS Forth file words may be a little more primitive than BASIC programmers are used to so I may add a layer on top to make closer to BASIC.

However it is really fun to have a handle based file system on the TI-99.

 

The Spoiler contains the code to implement this subset of forth Files wordset.

More information is here: http://forth-standard.org/standard/file

 

 

 

CR .( ANSFILES  for CAMEL99 V2 BJF 02APR2018)

\ Requires CAMEL99 V2 with DISKDSR4 and FILESYSD

\ A subset of ANS Forth files wordset with TI-99 specific file control words

\ Dependancy:
\ TI-99 file system is record oriented not byte oriented
\ therefore READ-FILE and WRITE-FILE are part of this lexicon.

\ ANS/ISO Forth Definitions used in this code:
\         fid -  file identifier (a file handle)
\         ior -  input/output response (the error number)
\         fam -  file access mode. see code for details

\ primitive file sys. commands for reference
\ : OPEN    ( -- ior)  0 FILEOP ;
\ : CLOSE   ( -- ior)  1 FILEOP ;
\ : READ    ( -- ior)  2 FILEOP ;
\ : WRITE   ( -- ior)  3 FILEOP ;
\ : REWIND  ( -- ior)  4 FILEOP ;
\ : LOAD    ( -- ior)  5 FILEOP ;
\ : SAVE    ( -- ior)  6 FILEOP ;
\ : DELETE  ( -- ior)  7 FILEOP ;
\ : SCRATCH ( -- ior)  8 FILEOP ;

CR .( ..)
\ File handle server
HEX
VARIABLE #FILES

CREATE PABS ( -- addr)   \ table for 8 potential PABs
             0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ,

\ ]PTAB exposes PABS as an array
: ]PTAB   ( n -- addr )  2* PABS + ;

\ compute the VDP address for any PAB(n)
: PAB[N]  ( n -- VDPadr) 120 * 3FFF SWAP - ;

: ?FILES  ( n -- )  #FILES @ > ABORT" No more files" ;

: NEWHNDL ( -- hndl) \ returns first free handle
         0           \ start at handle=0
         BEGIN
           1+
           DUP ?FILES    \ have we exceeded #files allowed
           DUP ]PTAB @   \ fetch pab table contents
         0= UNTIL ;      \ loop until we find an empty location

\ the file handle selects the active PAB
: SELECT  ( hndl -- )
           DUP ?FILES
           ]PTAB @ DUP 0= ABORT" Null handle"
           ^PAB ! ;

: ASSIGN  ( hndl -- ) \ assign a new handle and SELECT it.
          DUP  
          DUP PAB[N] SWAP ]PTAB !
          SELECT ;

: RELEASE ( hndl -- ) 
          ]PTAB OFF  
          3FFF ^PAB ! ; \ INCLUDE assumes ^PAB starts at 3FFF.

\ user level command.
: FILES   ( n -- )
          DUP 8 > ABORT" too many files"
          #FILES ! ;
.( ..)
\ ===================================
\ file access mode configuration

VARIABLE FAM  \ we build the file access mode in a variable

\ and/or the contents of a variable with mask
 : AND!   ( mask addr -- ) TUCK @ AND SWAP ! ;
 : OR!    ( mask addr -- ) TUCK @  OR SWAP ! ;

\ TI-99 file access mode modifiers
 2 BASE !  \        *ctrl bits*
 : DISPLAY    ( -- ) 11110111 FAM AND! ;
 : SEQUENTIAL ( -- ) 11111110 FAM AND! ;
 : RELATIVE   ( -- ) 00000001 FAM OR! ;

 : UPDATE     ( -- ) 11111001 FAM AND! ;
 : INPUT      ( -- ) 00000100 FAM OR! ;
 : OUTPUT     ( -- ) 00000010 FAM OR! ;
 : APPEND     ( -- ) 00000110 FAM OR! ;

VARIABLE B/REC    \ bytes per record
 : VARI  ( size -- fam) B/REC ! 00010000 FAM  OR! ;
 : FIXED ( size -- fam) B/REC ! 11101111 FAM AND! ;

\ set fam on stack to default file format 
\ (in case the op forgets to set it up)
.( ..)
 HEX
\ These ANS word adjust and return the FAM variable
 : R/W   ( -- fam)  UPDATE  FAM @ ;
 : R/O   ( -- fam)  INPUT   FAM @ ;
 : W/O   ( -- fam)  OUTPUT  FAM @ ;

\ ANS Forth word replaces INTERNAL
 : BIN   ( fam -- fam') 8 OR ;  \ modify FAM on stack

\ needed to test for file args on stack
: DEPTH   ( -- n ) SP0 SP@ 2+ - 2/ ;

\ : ?EXISTS  ( -- )
\             FSTAT 8 AND
\             IF DISKOFF TRUE ABORT" No such file"
\             THEN ;

.( ..)
HEX
\ build the PAB from all the pieces, error checking
: OPEN-FILE ( $addr len fam -- fid ior)
             DEPTH 3 < ABORT" file args"
             NEWHNDL DUP >R ASSIGN    \ copy handle & assign PAB
             [PAB PSIZE 0 VFILL        \ erase the VDP PAB to be safe.

             ?DUP 0=                  \ is FAM 0
             IF    14
             THEN  [PAB FLG] VC!       \ write file access mode

             B/REC @ ?DUP 0=          \ test for new record length
             IF  50                   \ if not default to 80 bytes (>50)
             THEN [PAB RECLEN] VC!     \ store reclen in PAB
                  B/REC OFF           \ reset the B/REC variable

             2DUP MAKEPAB             \
             NEWFILE                  \ setup new file
             0 FILEOP ( -- err#)      \ call O/S OPEN
             DUP                      \ test for error
             IF   R> RELEASE 0 SWAP   \ release hndl. return 0
             ELSE R> SWAP
             THEN ;

: CLOSE-FILE  ( fid -- ?)
               DUP SELECT
               1 FILEOP
               SWAP RELEASE ;

: READ-LINE ( c-addr u1 fid -- u2 flag ior )
            SELECT
            2 FILEOP DUP >R               \ read operation, rpush error#
            IF                            \ if err#<>0
               0 FSTAT R>                 \ fatal error, don't read data
            ELSE
               ( -- adr u1)
               [PAB CHARS] VC@             \ get no. chars read
               MIN  >R                    \ MIN(u1,chars)= u2, rpush
               [PAB FBUFF] V@ SWAP R@  VREAD   \ move VDP fbuff to c-addr
               R>                         \ get u2 (chars actually read)
               EOF 0=                     \ test  EOF = 0
               R>                         \ bring back error#
            THEN ;

: WRITE-LINE ( c-addr u fileid -- ior )
             SELECT
             DUP [PAB CHARS] VC!         \ # chars to write ->PAB
             [PAB FBUFF] V@ SWAP VWRITE  \ write CPU RAM to VDP file buffer
             3 FILEOP                   \ call write operation
             FSTAT 2 AND FUSE           \ fuse EOF and general file errors
;
.( ..)
: CREATE-FILE ( caddr len fam -- fid ior )
\ OUTPUT mode forces new file creation in TI-99 O/S
               2 OR                     \ modify 'fam' bits to OUTPUT mode
               OPEN-FILE ;

: FILE-POSITION   ( fid -- n ior) SELECT  [PAB REC#] V@ ERR@ ;
: REPOSITION-FILE ( fid -- ior)   SELECT  [PAB REC#] V! 4 FILEOP ;

: DELETE-FILE     ( caddr len -- ior ) R/W OPEN-FILE ?FILERR 7 FILEOP  ;

\ ===================================
8 FILES             \ set the #FILES now

DECIMAL

CR .( Max files set to ) #FILES @ .
( About 1080 bytes)
HEX

 

 

Link to comment
Share on other sites

You may have already addressed this and maybe I am missing or forgetting something, but two things puzzle me about PAB and VRAM buffer placement in your handle-based file system for CAMEL99 Forth:

  1. The odd-address starting points referenced to >3FFF and
  2. The overwriting of the reserved disk buffer space of high VRAM tracked by DSRs at >8370 (highest available VRAM address).

Disk DSRs, based on the TI DSR specs for the TI-99/4A, reserve buffer space for the DSR at the top of VRAM, placing the address of the byte just below this space into >8370. This buffer space changes for each invocation of the DSR’s FILES subprogram, changing the address in >8370 up or down by 518 bytes for each file (at least, that is so for TI, CorComp, MYARC(?), CF7 and nanoPEB DSRs). It seems to me that your upper reference point for PABs should be the value in >8370 after “ 8 FILES ” (or equivalent) is executed.

 

If you have only tested your file-handle system on Classic99 with its default FIAD file handler, you can probably get away with it, but it will crash and burn on the real iron and emulators that use the actual TI-based DSRs. This will even happen on Classic99 if you use the TI controller option, which can only be invoked by using a disk image and manually editing the section of the INI file for that particular disk to set Type=3.

 

...lee

Link to comment
Share on other sites

in order to shoehorn file loading into the 8k kernel I used a simple decrement the PAB pointer by >120 each time a new file is opened.

This means the PAB pointer defaults to the top of VDP RAM at 3FFF before the first file is opened.

 

So I think what your new information means for me if that I should replace my Forth variable with the address 8370 to properly tell the system that I have taken the VDP memory for myself.

 

Did I get that right?

Link to comment
Share on other sites

in order to shoehorn file loading into the 8k kernel I used a simple decrement the PAB pointer by >120 each time a new file is opened.

This means the PAB pointer defaults to the top of VDP RAM at 3FFF before the first file is opened.

 

So I think what your new information means for me if that I should replace my Forth variable with the address 8370 to properly tell the system that I have taken the VDP memory for myself.

 

Did I get that right?

 

Not unless you are writing your own DSR for peripheral I/O.

 

Upon power-up, the top of VRAM is reserved by the DSR of the first disk device encountered by the 4A and its DSR handles calls for reserving more or less space by the FILES routine. The DSR uses that reserved space for passing file/sector contents to and from the programmer’s PABs and their associated buffers pointed to by bytes 2 and 3 of each PAB, which are distinct from the DSR’s upper-VRAM buffers.

 

And, I still do not understand starting each PAB area on an odd address. Do you use a single byte at each starting address for linking or something else? Oh, wait!—VRAM is only ever byte-addressed, i.e, not directly address by the TMS9900!—never mind! :dunce:

 

...lee

Link to comment
Share on other sites

So that is how the machine wakes up but if we load a program with the E/A cartridge, can we not take over the machine and do what we want with the VDP RAM?

 

I am slowly working on getting my real iron running so I guess I get to find out in a while.

 

B

Link to comment
Share on other sites

So that is how the machine wakes up but if we load a program with the E/A cartridge, can we not take over the machine and do what we want with the VDP RAM?

 

I am slowly working on getting my real iron running so I guess I get to find out in a while.

 

B

 

Oh, you can, indeed, do whatever you want, just as long as you never attempt to open a file on disk. But—if you access a disk, the controller to which it is attached will use its reserved VRAM space and tromp all over whatever you may have put there. There is nothing you can do to tell the disk controller’s DSR to do otherwise short of disconnecting the controller, but, then, of course, you would have no disk access. In fact, if you trash the validation byte (>AA) just above the address in >8370, disk access may actually not work, at all. However, I do not know whether the DSR checks that byte before every I/O operation or only at startup to validate that it actually got written.

 

...lee

Link to comment
Share on other sites

I thought the ROM DSR code used the PAB for its clues as to where the file buffer is located and which device to connect to and all the other details.

 

I used to be confused, but now I am not so sure. :?

 

That is mostly true, but the DSR has its own buffer in high VRAM for each open file, which must be different from the buffer to which the PAB points. The DSR does not check your PAB or the VRAM buffer to which it points to see whether the file is open. It checks its own buffer(s). I would need to review the details to be sure, but I believe the DSR always reads and writes whole sectors regardless of the read or write mode requested by the PAB. Whereas, the PAB’s buffer only needs to be big enough to hold one record, which can be much smaller than a sector. In fact, it even can make sense for two PABs to point to the same VRAM buffer for copying information from one file to another. The DSR, however, will use separate buffers for each file. I guess you could think of the DSR buffers as kind of dumbwaiters that pass file sectors back and forth.

 

I think that, for writes, the DSR does not write a dirty sector buffer until a different sector is accessed or the file is closed. The fact that there is enough room in each DSR buffer for two sectors probably makes this process more efficient, but I digress...

 

...lee

Link to comment
Share on other sites

So the file system is double buffering in VDP Ram. Once at the sector level and then copying records into different VDP RAM.

Sounds pretty inefficient, however I guess we can never accuse the TI-99 designers of worrying too much about efficiency.

 

This could have been done using the (address, len) structure to manage the date, simply pointing to the data in the sector buffer rather than copying it anywhere. Maybe that's how I should write a new file system... hmmm

 

Ok so I have to move my buffers much farther up in memory. But I still don't know where the FILES function is located when I use the E/A cartridge, that allocates this VDP sector memory. I may spend some time studying the DISK DSR CODE further.

 

Thanks for the insights Lee.

  • Like 1
Link to comment
Share on other sites

So the file system is double buffering in VDP Ram. Once at the sector level and then copying records into different VDP RAM.

Sounds pretty inefficient, however I guess we can never accuse the TI-99 designers of worrying too much about efficiency.

 

This could have been done using the (address, len) structure to manage the date, simply pointing to the data in the sector buffer rather than copying it anywhere. Maybe that's how I should write a new file system... hmmm

 

Ok so I have to move my buffers much farther up in memory. But I still don't know where the FILES function is located when I use the E/A cartridge, that allocates this VDP sector memory. I may spend some time studying the DISK DSR CODE further.

 

Thanks for the insights Lee.

 

No prob.

 

I doubt that the E/A cartridge has a FILES routine. I think the power-up routine in the DSR sets the default to 3.

 

The FILES function is a level 2 DSR routine. Its “name” is >16. Here is the FILES word’s routine for fbForth 2.0 that calls it:

;[*** FILES ***      ( n --- )
*       expects on the stack the maximum number 
*       of simultaneously open files

*        DATA DPTH_N
* FIL__N DATA 5+TERMBT*LSHFT8+'F','IL','ES'+TERMBT

* FILES  DATA $+2
*        BL   @BLF2A
*        DATA _FILES->6000+BANK2  

_FILES MOV  @$PABS(U),R0        ; PAB address
       LI   R1,>0100            ; namelength (1 for DSR subroutines)
       LIMI 0                   ; disable interrupts because VSBW and DSRLNK don't
       BLWP @VSBW               ; write the byte to the PAB
       INC  R0                  ; next PAB address to write
       LI   R1,>1600            ; FILES subroutine number in DSR
       BLWP @VSBW               ; write to PAB
       MOVB @1(SP),@>834C       ; get number of files from stack
       INCT SP                  ; pop stack
       DEC  R0                  ; point to namelength byte in PAB
       MOV  R0,@SUBPTR          ; copy to where DSR expects it
       BLWP @DSRLNK             ; do the subroutine
       DATA >0A                 
       B    @RTNEXT             ; return to inner interpreter
;]* 

I am not checking for errors, but you can check the byte at >8350 for 0 (success) or failure (>FF).

 

...lee

Link to comment
Share on other sites

 

No prob.

 

I doubt that the E/A cartridge has a FILES routine. I think the power-up routine in the DSR sets the default to 3.

 

The FILES function is a level 2 DSR routine. Its “name” is >16. Here is the FILES word’s routine for fbForth 2.0 that calls it:

;[*** FILES ***      ( n --- )
*       expects on the stack the maximum number 
*       of simultaneously open files

*        DATA DPTH_N
* FIL__N DATA 5+TERMBT*LSHFT8+'F','IL','ES'+TERMBT

* FILES  DATA $+2
*        BL   @BLF2A
*        DATA _FILES->6000+BANK2  

_FILES MOV  @$PABS(U),R0        ; PAB address
       LI   R1,>0100            ; namelength (1 for DSR subroutines)
       LIMI 0                   ; disable interrupts because VSBW and DSRLNK don't
       BLWP @VSBW               ; write the byte to the PAB
       INC  R0                  ; next PAB address to write
       LI   R1,>1600            ; FILES subroutine number in DSR
       BLWP @VSBW               ; write to PAB
       MOVB @1(SP),@>834C       ; get number of files from stack
       INCT SP                  ; pop stack
       DEC  R0                  ; point to namelength byte in PAB
       MOV  R0,@SUBPTR          ; copy to where DSR expects it
       BLWP @DSRLNK             ; do the subroutine
       DATA >0A                 
       B    @RTNEXT             ; return to inner interpreter
;]* 

I am not checking for errors, but you can check the byte at >8350 for 0 (success) or failure (>FF).

 

...lee

 

Well this has forced me to read all the rest of the stuff on the TI Tech pages. Thanks again Lee.

So It should be pretty simple now for me to call these subprograms by using the language I created for File DSRs.

I believe I just need to search the sub-program list rather than the DSR list.

That's the theory anyway.

 

And we all know that theory and practice are the same ... in theory.

 

(but not in practice) :(

  • Like 1
Link to comment
Share on other sites

So It should be pretty simple now for me to call these subprograms by using the language I created for File DSRs.

I believe I just need to search the sub-program list rather than the DSR list.

 

Yup. That is what the

BLWP @DSRLNK
DATA >0A

does with the >0116 (string length=1 and name=16h) in the PAB.

 

...lee

Link to comment
Share on other sites

CAMEL99 Forth V2.0.11

 

I have addressed the new information (to me) that Lee provided regarding using >8370 as source of the end of VDP memory.

I have not yet implemented "FILES" so the default value is currently set to 3 by the TI system and there is not way to change it.

 

I am changing editors to ATOM to allow integration with GitHub, but I fear there will be some bad synchronization for a time while I get familiar with these new tools.

However I am enjoying this modern way of doing things. :-)

 

Version 2.0.11 binary is on GitHub in the DSK1 folder.

 

There is also a major upgrade to the manual V0.7 that gives more insight for using the system with more demo programs, Assembler explanations and info on some new faster direct control (not auto-motion) Sprites.

  • Like 1
Link to comment
Share on other sites

Monkey Fingers

 

You know what they say about monkeys and typewriters and an infinite amount of time?

I am not sure it's true, but this monkey program is entertaining to watch if you are a word nerd.

And if you write science fiction, it comes up with some pretty good character and planet names IMHO.

 

The program has simple rules to prevent multiple consonants and vowels, but no rule for a 1 letter word that is just a consonant.

 

This has been tested on CAMEL99 V2.0.11

 

 

 

\ monkeys.fth          Brian Fox May 3 2018
\

INCLUDE DSK1.RANDOM.F

DECIMAL
VARIABLE WORD_LEN   
VARIABLE CHARSOUT
VARIABLE WORDSOUT

HEX 7FFF CONSTANT 32K

: 1+!  ( addr -- ) 1 SWAP +! ;
: CLIP  ( n min max -- n') ROT MIN MAX ;
: VOWELS S" AEIOU" ;
: BETWEEN ( n min max -- ? ) 1+ WITHIN ;
: UALPHA? ( c -- ?)  [CHAR] A [CHAR] Z BETWEEN ;
: LOWER?  ( c -- ?) [CHAR] a [CHAR] z BETWEEN ;
: TOUPPER ( c -- c) DUP LOWER? IF 05F AND THEN ;

DECIMAL
: VOWEL?  ( char -- ? )    VOWELS ROT SCAN NIP 0> ;
: CONSONANT? ( char -- ? ) VOWEL? 0= ;

VARIABLE PREVIOUS-CHAR                         \ PREVIOUS VALUES: -1=VOWEL, 0=UNDEFINED,  1=CONSONANT

-1 CONSTANT AVOWEL
 1 CONSTANT ACONST

VARIABLE CONSONANTS
VARIABLE VOWELS

: NEW-WORD  ( -- ) CONSONANTS OFF   VOWELS OFF   PREVIOUS-CHAR OFF ;

: MONKEY-FINGER ( -- char) 
                BEGIN  
                  27 RND [CHAR] A +  
                  DUP UALPHA?
                UNTIL
                CHARSOUT 1+! ;

: REMEMBER ( char -- )
          DUP VOWEL?
          IF
             AVOWEL  PREVIOUS-CHAR !
             VOWELS 1+!
             CONSONANTS OFF
          ELSE
             ACONST  PREVIOUS-CHAR !
             CONSONANTS 1+!
             VOWELS OFF
          THEN ;

: KILL|KEEP ( char ? -- char | ?)  IF  DROP FALSE  ELSE TRUE THEN ;

: GETVOWEL ( -- vowel-char)
          BEGIN   
            MONKEY-FINGER DUP CONSONANT? 
            KILL|KEEP
          UNTIL ;

: GETCONST ( -- consonant-char)
          BEGIN   
            MONKEY-FINGER DUP VOWEL? 
            KILL|KEEP       
          UNTIL ;

: CONSONANTS? ( char n -- ?)
         CONSONANTS @ =    PREVIOUS-CHAR @ ACONST = AND ;

: VOWELS?     ( char n -- ?)
         VOWELS @     =    PREVIOUS-CHAR @ AVOWEL =  AND ;
\ Rules:
\ never more than 2 vowels in a row
\ never more than 1 consonants in a row
: RULES   ( CHAR -- CHAR )
           1 CONSONANTS?  IF  DROP    GETVOWEL  THEN
           2 VOWELS?      IF  DROP    GETCONST  THEN
           REMEMBER ;

\ 1 random key stroke, remember it and check rules , count char
: TYPE-WRITER ( -- char) MONKEY-FINGER  RULES ;

: MONKEY-WORD ( -- )
         NEW-WORD
         WORD_LEN @ RND 1+ 0
         ?DO
            TYPE-WRITER EMIT
         LOOP
         WORDSOUT 1+!
        SPACE ;

: TAB  ( n -- ) VCOL ! ;

: WAITKEYUP  ( -- ) BEGIN KEY? 0= UNTIL ;
: WAITKEY    ( -- ) KEY? IF KEY DROP THEN ; 

DECIMAL
: MONKEY-LINE  ( -- )
          CR   MONKEY-WORD  13 TAB  MONKEY-WORD 26 TAB MONKEY-WORD ;

: TITLE
PAGE
CR 2 TAB ." IF..."
CR
CR 2 TAB ." an infinite number of monkeys, with"
CR 2 TAB ." an infinite number of typewriters,"
CR 2 TAB ." type for an infinite amount of time,"
CR 2 TAB ." they will type the complete works"
CR 2 TAB ." of Shakespeare."
CR
CR 29 TAB ." Anonymous"

10 23 AT-XY  ." Press a key to begin..." KEY DROP ;

: MONKEYS  ( -- )
         27 7 VWTR
         TITLE PAGE
         CHARSOUT OFF
         WORDSOUT OFF
         10 WORD_LEN !
         CR ." Max word length = " WORD_LEN @ .
         BEGIN
           WAITKEY
           MONKEY-LINE
           CHARSOUT @ 32K =
           ?TERMINAL OR
         UNTIL
         WAITKEYUP
         CR
         CR ." The monkeys typed " CHARSOUT @ U.  ." characters
         CR ." in " WORDSOUT @ . ." words." ;

 

 

 

 

 

 

 

post-50750-0-09999200-1525379898.jpg

MONKEYFINGER.mp4

  • Like 2
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...