Jump to content
TheBF

Camel99 Forth Information goes here

Recommended Posts

VI99 Updates

 

I am slowly getting used to using VI99.  I am modifying some of the vi key codes to be more TI99ish. Cursor control uses E,X,S,D for example but with the control key.  Also when you type the ':' to go to command mode it pops you into Forth below the editor screen.

 

Part of the issue with using escape sequences to control TI-99 over high speed serial is that without interrupt driven receive you miss characters during editor operations. It works perfectly if you are not auto repeating quickly.  But hold the key down and the old gal can't keep up to that stream of characters. I will leave it as is for now. The "insert" mode where you do the editing works fine.

 

In the mean time I wrote this little addition. Something you can't do with vi in UNIX. :)

 

I can compile code out of the editor's SAMS memory buffer!  I am re-purposing the Forth word LOAD which is used for blocks in traditional Forth.  In this case LOAD accepts a numeric parameter but rather than a block no. VI99 LOAD selects which 64K SAMS buffer to compile so it can compile an entire file.  This quite a bit faster than compiling from floppy disk. The 231 line Assembler compiles in 23 seconds from memory vs 43 seconds from floppy disk. 

 

With all the editor routines compiled into the system this is all it took.  I made LOAD a "plugin" because it compiles in a couple of seconds.

I will also make the search and replace utility a "plugin".   

These utilities will compile into the system quickly but of course can "forgotten" if you don't need them.

\ Compile code from the vi99 editor buffer

: LOAD  ( file# -- )
         SEGMENT       \ select the segment (1..10)
         LASTLINE @ 0
         DO
             I ]RECORD LEN EVALUATE
             SPINNER
         LOOP ;

 

The video shows the editor and the new LOAD routine in operation.

Although it's hard to get used floppy disks again it is beginning to become a reasonable IDE.

Gotta learn more about a hard drive or TIPI maybe... :)

 

 

  • Like 2

Share this post


Link to post
Share on other sites
Posted (edited)

By the way...

The VI99 running in the previous video is using SAMS memory card written in Forth and it is still reasonably fast.

(It is about 1/2 speed to the same algorithm written in the Forth Assembler and ~20% bigger.)

 

I use machine code for the CRU control because I don't want to take the extra space required to load the entire CRU command set in Forth.

 

The magic words to control the SAMS card here are called SEGMENT and PAGED. 

You first set the SEGMENT to any value from 1 to 15.

 

Then to get at any byte in the  64K  segment.  pass the 16bit address to PAGED. You will get a "paged" address that you can read or write like normal memory.

 

It works very well but if you are transferring from one 4K page to another you need keep an intermediate buffer to temporarily hold the data you are moving.  You can of course also do things at full machine speed within any 4K block of the segment so filling and erasing can move along quite fast.

 

PAGED tests if the bank is already mapped before hitting the SAMS card to save a little time. 

 

The code computes the SAMS register to use at compile time based on the value you choose to give to the constant PMEM. (see line 10)

This version limits you to one SAMS page. For my purposes that is enough at the moment and given the small CPU ram space I don't want to give away more that 4K for this purpose.

 

One other cute trick is that R12 in Camel99 Forth is a USER variable, meaning it is different for every task. So that is how this code computes the address of 'R12 for Forth to use. These means that this routine can be used with the multi-tasker because 'R12 is local to each tasks' workspace. :)  

Hmm... maybe a Garbage collector could run in the background for LISP type language. :) 

 

Here is the current stable version of the DSK1.SAMSFTH

Spoiler
\ SAMS CARD support for CAMEL99 Forth Multi-tasking friendly  May 2020  B Fox
\ 64K segmented memory fetch and store
\
HERE

DECIMAL
  24 USER 'R12  \ address of R12 in any Forth workspace
HEX
: SAMSCARD  ( -- ) 1E00 'R12 ! ;   \ select sams card

  3000 CONSTANT PMEM  \ paged memory block location
\ compute SAMS register based on PMEM address
PMEM 0B RSHIFT 4000 + CONSTANT SREG

     VARIABLE SEG        \ holds current 64K segment
     VARIABLE BANK#      \ current mapped bank
\ using machine code so we don't need the CRU library
HEX
\ *set the CRU address in 'R12 before using these words*
 CODE 0SBO  ( -- ) 1D00 ,  NEXT, ENDCODE
 CODE 0SBZ  ( -- ) 1E00 ,  NEXT, ENDCODE

 CODE 1SBO  ( -- ) 1D01 ,  NEXT, ENDCODE
 CODE 1SBZ  ( -- ) 1E01 ,  NEXT, ENDCODE

: SAMS-OFF  ( --) SAMSCARD 1SBZ ;  \ disable mapper
: SAMS-ON   ( --) SAMSCARD 1SBO ;  \ enable mapper

\ safely set the 64K segment that you want to use
: SEGMENT ( 1..F -- )
         DUP 01 10 WITHIN 0= ABORT" SAMS segment err"
         SEG ! ;  \ don't allow segment 0
 1 SEGMENT

\ * SAMSINI sets card to "power-up" condition
: SAMSINI
       SAMSCARD          \ select SAMS card CRU address
       0SBO              \ turn card on
       0                 \ 1st value
       4000 20           \ register address, # SAMS regs
       BOUNDS ( -- 4020 4000 )
       DO
           DUP I !       \ I is reg. address
           0101 +        \ next value
       2 +LOOP
       0SBZ              \ turn off card
       DROP
;
HEX
: PAGED  ( addr -- addr')
         SEG @ 1000 UM/MOD  ( -- offset bank#)
         DUP BANK# @ =      \ are we using the same PAGE
         IF
             DROP           \ Yes! Drop bank# and get out
         ELSE
             DUP BANK# !    \ update bank# variable
             ><             \ swap bytes, bank# must be in left byte
            SAMSCARD 0SBO   \ turn on the card
          ( bank#) SREG !   \ store bank in SAMS register
            0SBZ            \ turn off card
         THEN  PMEM +       \ then add offset to paged mem block
;

\ paged memory fetch and store
: [email protected]    ( addr -- n)    PAGED [email protected] ;   \ fetch a byte
: C!P    ( n 32addr -- ) PAGED C! ;   \ store a byte

: @P     ( 32addr -- n)  PAGED @ ;    \ fetch an int
: !P     ( n 32addr -- ) PAGED ! ;    \ store an int

SAMSINI SAMS-ON   ( un-comment for real iron)
CR .( SAMS card activated)
CR HERE SWAP - DECIMAL . .( bytes)

 

 

Edited by TheBF
updated code
  • Like 1

Share this post


Link to post
Share on other sites

So it turns out that an "ok" fix to the VI99 escapes sequence interpreter was 2-fold:

  1.  Use the faster assembler coded version of the SAMS mapper so screen writes move along quicker.
  2.  If the interpreter can't figure out what the sequence is then wait until their are no more keys coming in.

Here is the simple solution to the interpreter. CLRKEYS just reads keys with the timed key routine TKEY  until TKEY returns 0.

Make CLRKEYS the default alternative in the case statement and everything gets stable. Still can't autorepeat these keys but at least it is reliable.

: CLRKEYS  ( -- )  BEGIN D0 TKEY 0= UNTIL ;

: CURSCTRLS  ( $ -- )
         CASE
            " [1~"  $OF  TOSTART    ( Home)        ENDOF
            " [A"   $OF  MOVEUP     ( up arrow)    ENDOF
            " [B"   $OF  MOVEDN     ( dn arrow)    ENDOF
            " [D"   $OF  LEFT       ( Left arrow)  ENDOF
            " [C"   $OF  RIGHT      ( right arrow) ENDOF
            " [4~"  $OF  TOEND      ( End)         ENDOF
            " [5~"  $OF  PGUP                      ENDOF
            " [6~"  $OF  PGDN                      ENDOF
            " [23~" $OF -1 +FILE    ( F11)         ENDOF
            " [24~" $OF  1 +FILE    ( F12)         ENDOF
                         CLRKEYS
         ENDCASE

 

  • Like 1

Share this post


Link to post
Share on other sites

Three Cheers for Formal Testing

(which I didn't do)

 

I was working today on a faster way to delete/insert a line in a file in SAMS memory. It's an interesting challenge due to the block nature of the memory.

In the course of playing with some methods I wanted to calculate the value of some constants and compile them as a literal value.

In other words do something that those fancy compilers like GCC do for you. :)  

 

In Forth it would look like this.

HEX 99 CONSTANT X
    4A CONSTANT Y

: MYROUTINE  ( -- n)  [  X Y + ] LITERAL ;

MYROUTINE switches the compiler off with '[' and so the interpreter is active.  X  & Y are added together and the sum is left on the DATA stack.

']'  turns the compiler back on and LITERAL compiles the number on the stack as a "literal" number, pre-calculated.

 

I was doing a bunch of this and so I wanted a more expressive way to do this so I wrote:

: ]EVAL  ]  POSTPONE LITERAL ; IMMEDIATE 

( Now it looks better)
: MYROUTINE  ( -- n)  [ X Y + ]EVAL ;

It didn't work!

I tried it in FbForth. (using the older word [COMPILE] instead of POSTPONE)   It worked.

I checked my source code and OOPS!  I made ']' IMMEDIATE.  It's been that way probably since I began this journey. I don't use it much so it never was noticed.

 

My apologies. I only partially tested the system with the HAYES Test Suite for standard Forth because it had a lot of extras that Camel99 doesn't have. Modifying the big test suite was a pain.

Lesson learned.

 

I will publish a new version shortly with the correction that also has a couple of small additions to the library as well.

 

 

  • Like 1

Share this post


Link to post
Share on other sites

CAMEL99 Forth V2.61

 

Here what's new:

  •  ']' is now not an immediate word in compliance with standard Forth
  •  DSK1.CAML99SC  is Forth compiled to load at >6000 and so works with a SUPER cart and Classic99. This gives 8K more CPU RAM for your programs
  •  DSK1.SAMSDUMP  adds the word SDUMP to the system so you can dump SAMS memory. This works with the SAMS SEGMENT system, dividing SAMS memory into 15 by 64K segments.
  •  DSK1.INPUT changes the #INPUT word to use the new NUMBER? conversion word. #INPUT works like TI-BASIC's input command looping with an error until a valid number is entered.
  •  CROSS99 builds a simple cross compiler using DSK1.XASM99 to make standalone binary programs. Forth is not part of the finished program.
  •  DSK1.XASM99 is a cross assembler that assembles programs into a target memory location.
  •  Demo program DSK3.HELLOSRC is the source code for a cross-assembled Hello World program. DSK3.HELLO is the binary program file that loads with E/A 5
  •   DSK1.SAMSFAST has been removed and replaced with DSK1.SAMS, the fastest access to SAMS memory in CAMEL99
  •  DSK1.SAMSFTH does the same as DSK1.SAMS but is written mostly in Forth. It's slower but would worker better for MULTI-tasking because it defines R12 as a user variable making R12 unique in each task.

    For all those users out there please report any bugs. :) 
     

 

  • Like 2
  • Thanks 1

Share this post


Link to post
Share on other sites
Posted (edited)

I can't wait to play! Thank you!!

.... I've gotta finish my current program then I'll jump on.

Great job.

Interesting games can be made using supercart 32K with the 4 switches for bank selection available to the user, the game can detect the position of each switch thus giving Cool reactive conditions by the user, I'm thinking landing gear down, warp speed selected...on and on.

I know about"watching" for bank selection, as I use it in my SNE program to distinguish wether the user is in bank 0 or not, which is not allowed, so a warning is presented with"HONK"..hehe

 

 

Edited by GDMike
  • Like 1

Share this post


Link to post
Share on other sites

Well I am just happy that somebody else boots the darn thing. :)

Don't hesitate to ask a question or 2.

 

Have fun

B

  • Thanks 1

Share this post


Link to post
Share on other sites

I don't know why it wouldn't have attraction. It's super.. but I'm only using real hw so I'm not going to see good stuff like 80 col. But oh well. (My choice).

I'm not giving up just because of that, well, unless I can't get it to text mode on real hw. I doubt that.

Share this post


Link to post
Share on other sites
1 hour ago, GDMike said:

I don't know why it wouldn't have attraction. It's super.. but I'm only using real hw so I'm not going to see good stuff like 80 col. But oh well. (My choice).

I'm not giving up just because of that, well, unless I can't get it to text mode on real hw. I doubt that.

I booted this version on real hardware today.  It boots in Text mode. 

If you want 32 column like BASIC, do INCLUDE DSK1.GRAFIX

To see /study a simple graphics mode program INCLUDE DSK3.SMPTE ( color bars from the society of motion picture and television engineers)

If you don't want to use the editor INCLUDE DSK1.MORE .

Then use  MORE DSK1.anyfile  to see it. Spacebar will pause the display.  BREAK will stop it.

 

  • Like 1

Share this post


Link to post
Share on other sites

SAMS Variables in Forth

 

In VI99 I needed a way to keep the context of each of the 10 files that could be in memory. That meant space for 10 file names and 5 variables. Altogether that consumed 250 bytes of valuable dictionary memory.  It made me wonder if I could save some memory and make the string variable and the integer variables in SAMS memory? 

I decided I could use the first record of SAMS memory as local memory for the file. I will change the editor to put text starting at record 1.

That gives me 128 bytes at the top of the SAMS segment. Lots of space but would the speed penalty be too much to use SAMS for variables in the editor? 

 

The SAMSVAR records an offset value. The offset is relative to the beginning of the 64K segment that is selected in the Camel99 SAMS management system.

The difference between a SAMSVAR and other variables is that when you invoke a SAMS variable it automagically pages in the memory page required from SAMS.

This means we can use our normal fetch and store words in Forth to work with SAMSVARs. :) 

 

We make SAMSVARs with Forth's CREATE DOES> structure. In OOP vernacular, CREATE DOES> lets us make an object constructor that has only one method .

(Note: TI-FORTH and FbForth use the <BUILDS DOES> combination to do this)

 

This way of working can flummox newbies to Forth so I will take a run at explaining it. (This is going step by step so it's kind of long)

-------------------------------------------

 

To start let's understand the word CREATE in Forth. CREATE makes an entry in the Forth dictionary. It literally puts the text following CREATE into memory with a little extra stuff to connect it to the list of other words.

CREATE FOO  ( puts the word FOO in the dictionary)

After "creating" FOO, if you type FOO into Forth all you get back is a memory address sitting on the top of the data stack. That's all.

 

The Forth comma ','  takes a number from the data stack and compiles it into the next available. So if we say:

CREATE FOO   7 , 

… we can reference the address of that the number seven using the name FOO.  Typing FOO will return the address where '7' is stored and put that address onto the data stack. 

 

---------------

If it helps imagine it's a  little this in Assembly Language:

FOO     DATA  7

--------------

 

Now we can type FOO  "fetch" "print-number"  as below and '7' will appear with ok from Forth. Wonderful. We're just getting started.

FOO @ . 7 ok

 

Now consider this code:

99 CREATE FOO   ,  

It works the same but we put 99 onto the data stack first.  Comma doesn't care. It picked up 99 and stored in memory the same as it did with 7.

 

So let's define a new Forth word that does all of this for us:

:  VAR:   CREATE   ,   ;

Now we can make variables that are initialized to anything we want.  They will return the address where the numbers are stored so we can "fetch" them with @ or change them with !.  (store)

 0 VAR: NULL
99 VAR: FOO  
 7 VAR: BAR 

This is the first part of making a SAMSVAR.  We don't need the CPU RAM address of a variable, we need the SAMS card address.  So a SAMSVAR needs to be different in what it "does" compared to a regular variable. We can use the "Forth word DOES> to tell a SAMSVAR what to do. (See what I did there?) :) 

: SAMSVAR: CREATE  ,    ( like before )

           DOES> @      ( fetch the number we gave it) 
                 PAGED  ( convert to SAMS address, pull in the bank)
;

 

So CREATE  and comma are what happens when we invoke the word SAMSVAR:   (this is when we compile a program)

 

DOES> changes what will happen, in other words what code will run,  when we invoke the name of a word created with SAMSVAR:

Clear as mud?

 

So to use SAMSVARs we must give each one their memory address in a virtual memory space called a SEGMENT.  Each SEGMENT is 64k.

PAGED is an assembler routine that computes where any address will appear in the CPU RAM page that we selected  (>3000 is used in CAMEL99) and maps it into CPU RAM.

So my new code looks like this:

  0 SAMSVAR: TOPLINE
  2 SAMSVAR: LASTLINE
  4 SAMSVAR: ECOL
  6 SAMSVAR: EROW
  8 SAMSVAR: UPDT      \ true if file is changed in anyway
 10 SAMSVAR: FILENAME  \ ready for long file paths

All that to say the performance hit is about 38% slower than referencing variables in CPU ram. I think I can live with that. :)

 

To play with this code in Camel99  do:

INCLUDE DSK1.TOOLS   ( to get DUMP and .S )

INCLUDE DSK1.SAMS 

 

Then you can paste this code into Classic99 to explore.

 

  • Like 1
  • Thanks 1

Share this post


Link to post
Share on other sites

The bad news: My 2nd old 1/2 height floppy drive is not seeking reliably. I hope that a thorough cleaning will improve it.

 

The good news:  I have successfully compiled code into different pages of SAMS memory. It's just a beginning but it works.

 

This implementation creates something like "vocabularies" for each 4K PAGE. It's not ideal in that it is not a big contiguous code space. It's not a particularly elegant solution either but it was for exploration. 

 

It's good because the compiler and the code runs at full speed after the mapping operation.  The CMAP operation is Forth but it's still pretty fast. I can improve that later. 

 

So here is Concept 1 to compile code into Sams from Camel Forth.  Happy to answer any questions but this is just a means to an end. 

 

In Concept 2, I will have to organize a group of pages into a linked list that can searched sequentially.  This would allow a simulated 64K code segment to be used with the caveat that you won't be able to compile code across 4K pages, but the compiler will be able to search the entire list.

 

This then begs the question of lookup time which might require a re-write of the kernel to use 8-way hashing of the dictionary as was done in poly-Forth.  Even a linear Assembler search will bog down with a 2000 word dictionary.

 

Spoiler
\ SAMS Memory Forth compiler  CONCEPT 1:         Jun 8 2020  B Fox

\ Compile to a discrete, named 4K page and link back to Kernel dictionary
\ Each code page holds a 2 CELL header with DP and LATEST for that page the end of block
\ Each code page in this model is like a small vocabulary that links back to Forth

NEEDS DUMP  FROM DSK1.TOOLS  \ debug only

HEX       E000 CONSTANT CSEG    \ CODE SEG. The page in CPU for extended code
F000 2 CELLS - CONSTANT PLINKS  \ dictionary pointers at end of page block

\ compute CSEG SAMS register at compile time :)
CSEG 0B RSHIFT 4000 + CONSTANT CREG

DECIMAL
  24 USER 'R12  \ address of R12 in any Forth workspace

HEX
\ *set the CRU address in 'R12 before using these words*
 CODE 0SBO  ( -- ) 1D00 ,  NEXT, ENDCODE
 CODE 0SBZ  ( -- ) 1E00 ,  NEXT, ENDCODE

: SAMSCARD  ( -- ) 1E00 'R12 ! ;   \ select sams card

: CMAP  ( bank# -- )        \ CODE MAP
         ><                \ swap bytes, bank# must be in left byte
         SAMSCARD 0SBO     \ turn on the card
         ( bank#) CREG !   \ store bank# in SAMS register
         0SBZ ;            \ turn off card

CREATE HOME  0 , 0 ,         \ 2 cell variable

: DICTIONARY ( -- n n)  DP @ LATEST @ ;        \ get dictionary pointers
: RELINK     ( dp latest -- ) LATEST ! DP ! ;  \ set dictionary pointers
: REMEMBER   ( -- ) DICTIONARY HOME 2! ;

: INITPAGE ( bank# -- )
         CMAP                         \ map extended memory
         CSEG LATEST @  PLINKS 2! ;   \ CSEG as DP & current dictionary

: FORTH   ( -- ) HOME [email protected] RELINK ;  \ Restore the Forth dictionary to a HOME
: ENDDEFS ( -- ) DICTIONARY PLINKS 2! ;

: CODEPAGE: ( page# -- )  \ page# can be 0..$FF (0..255)
         CREATE  DUP ,                      \ compile page#
                 INITPAGE                   \ set the pointers at end of page

         DOES> @ CMAP                       \ map in the memory page
               PLINKS [email protected] RELINK ;           \ set new dictionary pointers

: PAGE-USE  ( -- n )  PLINKS [email protected] DROP  CSEG - ;

30 CODEPAGE: MISC
31 CODEPAGE: XASM99
32 CODEPAGE: ASM9900
33 CODEPAGE: BLOCKS

\ Remember the Forth dictionary to this point so we can get back from a SAMS dictionary
REMEMBER

\ TEST CODE
DECIMAL
FORTH MISC
: STAR    42 EMIT ;
: STARS   0 ?DO  STAR LOOP ;
: HI      CR ." Hello world from SAMS memory!" ;

INCLUDE DSK1.SOUND
INCLUDE DSK1.COLORS
INCLUDE DSK1.ELAPSE

ENDDEFS   PAGE-USE DECIMAL .

FORTH XASM99

  INCLUDE DSK1.XASM99

ENDDEFS  PAGE-USE DECIMAL .

FORTH ASM9900

  INCLUDE DSK1.ASM9900

ENDDEFS PAGE-USE DECIMAL .

FORTH BLOCKS

    INCLUDE DSK1.BLOCKS

ENDDEFS PAGE-USE DECIMAL .

 

 

  • Like 1

Share this post


Link to post
Share on other sites
36 minutes ago, TheBF said:

The bad news: My 2nd old 1/2 height floppy drive is not seeking reliably.

I just traded an ea cart for my spare half ht fd. And I'm using a gotek for fdsk1.

My only half ht FD I have left is my drive 2. And I'm temporarily using a borrowed ramdisk. I can't wait now for my tipi.

I think tipi will be the best thing for file management!

 

Share this post


Link to post
Share on other sites
2 minutes ago, GDMike said:

I just traded an ea cart for my spare half ht fd. And I'm using a gotek for fdsk1.

My only half ht FD I have left is my drive 2. And I'm temporarily using a borrowed ramdisk. I can't wait now for my tipi.

I think tipi will be the best thing for file management!

 

How do you do EA cart stuff without the cart. I have not looked at any of the options.

 

  • Like 1

Share this post


Link to post
Share on other sites
Posted (edited)

I'm using the cart.

I was looking for some and found one I could trade for, so it gave me an extra ea cart. But now I don't have extra fdisk drives lol

 

IMG_20200608_231441074.jpg

Edited by GDMike
  • Like 1

Share this post


Link to post
Share on other sites
2 hours ago, TheBF said:

question of lookup time which might require a re-write of the kernel to use 8-way hashing of the dictionary as was done in poly-Forth.  Even a linear Assembler search will bog down with a 2000 word dictionary.

 

With 510 words in its kernel, fbForth 2.0 is already a little slow when words at the beginning are needed. Unfortunately, the most-used words are at the head of the linked list. And, of course, compiling a number will always cause a search through all 510 of those words before checking whether it is a legal number. This latter situation is not too serious until one needs to compile a large block of numbers. That is why I included DATA[ (and its complementary ]DATA ), which turns the interpreter’s search order around to first see if the input token is a number.

 

I should probably look at other ways to manage the dictionary by looking closer at your SAMS dictionary code as well as how polyForth manages its dictionary. Where can I get information on the latter?

 

...lee

  • Like 1

Share this post


Link to post
Share on other sites

I didn't realize you did the search order switch with DATA[ .

That's pretty fancy.

 

Here is the only reference I know of to a PolyForth Manual.

http://www.greenarraychips.com/home/documents/greg/DB005-120825-PF-REF.pdf

 

I did a little homework on the concept before but never wrote any code. From what I can gather a hash value is calculated from the contents of the name and a 3 bit code is embedded in the header that determines which search list the word is attached to.  This way the longest search is word-count/8.  So a significant speed up. In the original PolyForth they also only recorded the first 3 characters of the name and hashed the remaining characters for even faster lookups.

 

Camel Forth is rather liberal in the header giving up an entire byte for the precedence bit so I have lots of space to hide the extra bits.  I suppose that you could use 2 bits for a 4 way hash and still get a good improvement if header space is an issue.

 

B

  • Like 2

Share this post


Link to post
Share on other sites

Old floppy drive head cables never die. They just get tangled on stuff.

 

My 35 year old floppy drive works again. :)  Took a while to figure out why the head assembly slid perfectly except in the middle of the travel.  

The head cables hidden at the back of the drive had slowly moved to a place where they were rubbing on a projection in the chassis and at the middle of travel the rubber insulation snagged on it.

A bit of "forming" and it's back in business. (clean it a little anyway)

My day has improved greatly.

  • Like 1

Share this post


Link to post
Share on other sites

Too many shortcuts

Awhile back I was struggling with making a reliable repeating KEY.  I used a known algorithm and even re-wrote it in Assembler to no avail.  I essentially gave up on it and moved on.

While perusing the Playground documentation I came across this piece of code.

LWPI >83E0
MOV R11,@>836E store the return address
BL @>000E (keyscan uses both intws and gplws)
MOV @>836E,R11 restore the return address
LWPI WKSP

I remembered reading about saving GPL workspace R11 and restoring it when using the KSCAN code but in my efforts to find superfluous bytes in the kernel I removed this and didn't see any difference.

In my efforts to make the repeating KEY routine reliable, I had made every effort to protect the KEY? routine (KSCAN) code with Interrupts disabled and correctly reading the GPL status byte. It all worked great... except when I used it in a repeating key routine.

 

So I thought what the h*ll.  Let's see if it makes a different.  It does. The new code is below in XFC99 cross-compiler Assembler.

Since the system runs in RAM I just use a memory location before the code to save GPL's R11.  I also discovered that it only is 100% reliable if I don't re-enable interrupts in this routine but rely on my VDP routines to do that job later. So there is more to this than I understand.  Not ideal, but I will take it for now.

l: GPLR11   0 DATA,
CODE: KEY? ( -- ?)  \ *WARNING* it takes 1,128uS for KEY? scan to run
            TOS PUSH,
            TOS CLR,            \ TOS will be our true/false flag
            0 LIMI,
            TOS 837C @@ MOVB,   \ clear GPL flags
            83E0 LWPI,          \ switch to GPL workspace
            R11 GPLR11 @@ MOV,
            000E @@ BL,         \ call ROM keyboard scanning routine
            GPLR11 @@ R11 MOV,
            WRKSP0 LWPI,        \ return to Forth's workspace
            837C @@ R1 MOVB,    \ read GPL status byte (=2000 if key pressed)
            R1  3 SLA,          \ check the key bit
            OC IF,              \ if carry flag set
               8374 @@ TOS MOV, \ read the key
            ENDIF,
            NEXT,               \ return
            END-CODE

With this working reliably I loaded up a version of ED99,  my VDP editor and it looks like I might have an editor that I can use on real iron. Testing on the TI-99 to follow.

What an ordeal this has been because I saved 8 bytes.  :)  

 

Classic99 QI399.025 2020-06-13 1_10_29 PM.png

Share this post


Link to post
Share on other sites

I know that editors are like underwear and quite personal but I started playing around with ATOM again after a long time away. I found a package that supports ANS Forth and it is quite nice to use.

It even is smart enough to memorize the names of variables, constants and word definitions in the file and serve up auto-completion suggestions.

It also supports GitHub so you can keep your repositories current, something I will be doing over the next week. (I hope)

 

Something to consider for development with Classic99 and Forth. (Looks like it is for 64 bit Windows only)

 

https://atom.io/

 

Interestingly it is not as cool in some ways as  FPC (DOS) and Win32Forth from the 1990s in which the editor hyper indexed all the code so you could explore right down to the real code "atoms". By double clicking on any word in the file(comments excluded) you would see the definition of that word in source code. Click on any word in that definition and another file would open and so on.

Tom Zimmer the author of both of those systems was brilliant

 

ED99SAMS6.FTH — C__Users_Public_Dev_Forth_HSF2000_cc9900_Editors_SAMSEDITOR — Atom 2020-06-13 11_13_16 PM.png

  • Like 1

Share this post


Link to post
Share on other sites

So it's not as fancy as ATOM but it runs on a TI-99.

So for anyone who wants to review/beat it up, here is what I will call V 0.9 of ED99. 

It requires a SAMS card or Classic99 with SAMS enabled.

It also requires Camel99 V2.62 which I have not published but I will shortly.

It will run on 2.61 but the repeating key will clobber the file contents randomly. Not cool.

 

Notes:

  • User commands can be seen at the bottom of the file.
  • On the PC the Esc key drops you out of the editor into the Forth interpreter at the bottom of the screen.
  • In lieu of documentation review the CASE statement on line 377 to learn the keyboard controls.
  • Many are the same as the TI Editor to minimize the learning curve.
  • 10 files can be loaded at the same time.
  •  CTRL Y  yanks lines from the file an puts them on a line-stack. This takes a couple of seconds for a file of 500 lines but it works.
  •  CTRL V will put the line-stack line back into the file.
  • In the Forth interpreter you can "INCLUDE DSK1.DIR" to have access to a "dir" command to see what's on your disks.
  •  There is only about 7K of memory left when the editor and TOOLS are loaded. I will be working some solutions to expand that memory.

 

 

Spoiler
\ ED99 SAMS memory file editor for CAMEL99 Forth Apr 2020 Brian Fox
NEEDS .S        FROM DSK1.TOOLS
NEEDS CASE      FROM DSK1.CASE
NEEDS READ-LINE FROM DSK1.ANSFILES
NEEDS PAGED     FROM DSK1.SAMSFTH
NEEDS -TRAILING FROM DSK1.TRAILING
NEEDS VTYPE     FROM DSK1.VTYPE
NEEDS .R        FROM DSK1.UDOTR
NEEDS RKEY      FROM DSK1.RKEY

.( .)
HERE
CR .( ED99 Multi-file Editor V0.9 BFox 2020) CR
  80 CONSTANT TOPBAR
  81 CONSTANT BOTBAR
1000 CONSTANT 4K
\ cursor characters
DECIMAL
95 CONSTANT ULINE
30 CONSTANT BAR
31 CONSTANT BOX
\ screen management & record constants
    C/[email protected] CONSTANT WIDTH   \ screen width. Detects 40/80 columns
      80 CONSTANT #80     \ length of file records
      16 CONSTANT EL/SCR  \ editor lines per screen
     128 CONSTANT RECSIZE
     500 CONSTANT MAXLINES
WIDTH 1- CONSTANT RMARGIN
         VARIABLE INSERTING

\ utility words
: GETXY   ( -- COL ROW)  VROW [email protected] ;
: BLANKS  ( adr len -- ) BL FILL ;
: BETWEEN ( n lo hi -- ? ) 1+ WITHIN ;
: CURSOR   ( char -- ) CURS ! ;
.( .)
\ graphics helpers
HEX
 0800 CONSTANT PDT   \ "pattern descriptor table"
: ]PDT     ( char# -- 'pdt[n])  8* PDT + ;
: CHARDEF  ( addr char# --)  ]PDT 8 VWRITE ;
: HLINE    ( col row char cnt --) 2>R >VPOS 2R> VFILL ;
: COLORS   ( fg bg -- ) SWAP 4 LSHIFT SWAP +  7 VWTR ;
: FORTHCOLOR     1 7 COLORS ;
: EDCOLOR        F 5 COLORS ;

HEX
CREATE DBLN  0000 , FF00 , FF00 , 0000 ,
CREATE SGLN  0000 , 0000 , FF00 , 0000 ,
CREATE VERT  A0A0 , A0A0 , A0A0 , A0A0 ,
CREATE ABOX  FC84 , 8484 , 8484 , 84FC ,
.( .)
HEX
: DEF-CHARS
     DBLN  TOPBAR CHARDEF
     SGLN  BOTBAR CHARDEF
     ABOX    BOX  CHARDEF ;

\ busy spinner ...
VARIABLE SPIN#
CREATE SCHARS   CHAR | C, CHAR / C, CHAR - C, CHAR \ C,
: SPINCHAR ( -- char ) SPIN# @ 1+ 3 AND DUP SPIN# ! SCHARS + [email protected]  ;
: SPINNER  ( -- )      SPINCHAR GETXY >VPOS VC! ;

\ SCREEN formatting ...
DECIMAL
.( .)
\ Multiple file manager indexed via the SEG variable in SAMS.
\ SAMS implementation uses only SEGMENTS 1..15
\ SEG variable indexes into FILENAMES and editor state variables
DECIMAL
CREATE FILENAMES  \ counted strings 15 bytes + COUNT BYTE
     S" deadbeefdeadbee" S, \ SEG=0 NOT USED
     S" DSK1.UNTITLED  " S, \ 1
     S" DSK1.UNTITLED  " S, \ 2
     S" DSK1.UNTITLED  " S, \ 3
     S" DSK1.UNTITLED  " S, \ 4
     S" DSK1.UNTITLED  " S, \ 5
     S" DSK1.UNTITLED  " S, \ 6
     S" DSK1.UNTITLED  " S, \ 7
     S" DSK1.UNTITLED  " S, \ 8
     S" DSK1.UNTITLED  " S, \ 9
     S" DSK1.UNTITLED  " S, \ 10

: FILENAME ( -- caddr) SEG @ 16 *  FILENAMES + ;
\ EVARS can hold 10 different values. One for each SAMS segment
: EVAR: ( -- addr ) \ nil   1   2   3   4   5   6   7   8   9  10
        CREATE          0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ,
        DOES>  SEG @ CELLS +  ( -- addr) ;

EVAR: LASTLINE
EVAR: TOPLINE
EVAR: SOL     \ start of line
EVAR: EROW
EVAR: ECOL
EVAR: UPDT

: UPDATED   UPDT ON ;
: ERASELN ( col row -- )AT-XY  VPOS WIDTH BL VFILL ;

\ EROW is screen row we are editing,TOPLINE the topline on the screen.
: REC#    ( -- n ) EROW @ TOPLINE @ + ; \ the record  we are editing

: .FILENAME  ( -- )
     0 0 AT-XY ." #"  SEG @ 2 .R ." | "
     VPOS 16 BL VFILL FILENAME COUNT VTYPE
     UPDT @ IF ." *"  THEN ;

: .LINE#     ( -- )
     RMARGIN 12 -  0 AT" Line "  REC# 3 .R  ." /" LASTLINE @ 3 .R ;

: RULER$  ( -- addr len)
S" 0----+----1----+----2----+----3----+----4----+----5----+----6----+----7-"
;

: .TOPBAR  ( -- ) RULER$ SOL @ /STRING C/[email protected] MIN 0 1 >VPOS SWAP VWRITE ;
: .BOTBAR  ( -- ) 0 18 C/[email protected]  BOTBAR HLINE ;
: .HEADER  ( -- ) .FILENAME  .LINE# .TOPBAR ;
: DRAW.SCR ( scr# -- )  PAGE  .HEADER  .BOTBAR ;

\ compute address of 128 byte record in any SAMS segment
: ]RECORD       ( n -- addr) RECSIZE *  PAGED  ;
: [REC#]RECORD  ( -- ) REC# ]RECORD ;
: WRITELN  ( VDPaddr CPUaddr -- ) SOL @ + OVER WIDTH  VWRITE  ;
: LIST ( -- )
     0 2 >VPOS ( -- VDPaddr )
     TOPLINE @ DUP EL/SCR +  SWAP
     DO
       ( VDPaddr ) I ]RECORD WRITELN
       WIDTH +  ( -- VDPaddr' )
     LOOP
     DROP ;
.( .)
DECIMAL
: PROMPT: ( -- ) 0 19 ERASELN ;
: STATUS: ( -- ) 0  1 ERASELN ;

: CLIP    ( n n1 n2 -- n1..n2) ROT MIN MAX ;
: ?ERR    ( ERR# $addr len -- )
          ROT ?DUP IF  PROMPT: TYPE .  KEY DROP ABORT THEN ;

: ?OPENERR ( n -- ) ?DUP IF . TRUE ABORT" Open error" THEN ;
: ?R/WERR  ( n -- ) ?DUP IF . TRUE ABORT" R/W error" THEN ;
: ?CLOSERR ( N -- ) ?DUP IF . TRUE ABORT" Close error" THEN ;
.( .)
DECIMAL
: LOADDV80 ( addr len -- )
     2DUP FILENAME PLACE
     DV80 R/O OPEN-FILE ?OPENERR >R
     TOPLINE OFF
     LASTLINE OFF
     BEGIN
       PAD DUP 80 [email protected] READ-LINE ?R/WERR ( -- pad len ?)
     WHILE
       LASTLINE @ ]RECORD ( pad len record) SWAP CMOVE
       SPINNER
       LASTLINE 1+!
     REPEAT
     R> CLOSE-FILE ?CLOSERR ;
.( .)
\ save SAMS memory, remove trailing zeros
VARIABLE SH   \ save handle var is simpler inside DO/LOOP
: SAVEDV80  ( addr len -- )
     DV80 W/O OPEN-FILE ?OPENERR SH !
     LASTLINE @ 1+  0
     ?DO
        I ]RECORD #80 -TRAILING 1 MAX  SH @ WRITE-LINE ?R/WERR
       SPINNER
     LOOP
     SH @ CLOSE-FILE ?CLOSERR ;
.( .)
\ cursor movement
DECIMAL
: HOMECURS  ( -- )   EROW OFF ECOL OFF ;
: COL&ROW   ( -- ecol erow) ECOL @ EROW @ 2+ ; \ Editor's X,Y on vdp
: PUTCURS   ( -- ) COL&ROW  AT-XY  ;
: EDLINE    ( -- addr len ) [REC#]RECORD  #80 ;
: BLKCURS   ( -- n ) ECOL @  SOL @  + ;          \ cursor pos. in record
: 'CHAR     ( --  adr ) [REC#]RECORD BLKCURS + ; \ address in disk block
: !CHAR     ( n -- )   'CHAR C!    ;
: 'EOL      ( -- adr )  EDLINE 1- + ;    \ End of Line address
: RIGHTSIDE ( -- addr len) EDLINE BLKCURS  /STRING ;
: 'SCRPOS   ( -- vdpaddr) COL&ROW >VPOS ;

: RELINE    ( -- )
     RIGHTSIDE DROP        ( -- addr )
     WIDTH ECOL @ -        ( -- addr bytestoend)
     'SCRPOS               ( -- addr bytestoend vdpaddr)
     SWAP VWRITE  PUTCURS ;
.( .)
: REDRAW    ( -- ) .HEADER LIST PUTCURS ;

: |MARGINS|  ( n -- n')  0 RMARGIN CLIP ;
\ left/right text window scrolling
: SOL+!      ( n -- ) SOL  @ +  |MARGINS| SOL ! ; \ 0..79 virtual screen wih
: HORIZONTAL ( n -- ) SOL+! REDRAW ;  \ +n  slide right, -n slide left

: TOPLINE+!  ( n -- ) TOPLINE @ +   0 MAXLINES 15 - CLIP   TOPLINE ! ;
: LASTLINE!  ( -- ) LASTLINE @  REC# MAX  LASTLINE ! ;

\ decrement a varible, clip at zero
: SAFE-! ( n addr -- ) TUCK @ SWAP - 0 MAX SWAP ! ;
: LEFT  ( -- ) \ automatically scrolls screen if at limits
     ECOL 1 OVER SAFE-!
     @ 0=  IF -1 HORIZONTAL     THEN RELINE ;

: RIGHT ( -- )
     ECOL [email protected] RMARGIN >
     IF  1 HORIZONTAL
         RMARGIN ECOL !
     THEN RELINE ;

\ end allows escaping from a routine in an IF statement
: END      ( -- )   S" EXIT THEN " EVALUATE ;  IMMEDIATE

: AT-EOF?  ( -- ?) REC# LASTLINE @ = ;
: MEMFULL? ( -- ) LASTLINE @ MAXLINES = ;
: .MEMFULL ( -- ) PROMPT: ." Mem full" HONK  1000 MS  REDRAW ;

: +LINE ( -- )
     AT-EOF?  IF HONK END
        EROW DUP @ 1+ SWAP !
        EROW @ 15 >
        IF   1 TOPLINE+!  15 EROW !
        THEN LASTLINE!  REDRAW ;

: -LINE ( -- )
     EROW 1 OVER SAFE-!
     @ 0= IF -1 TOPLINE+! THEN REDRAW ;

: -TAB  ( -- ) ECOL  -8 HORIZONTAL REDRAW ;

: +TAB  ( -- )
     ECOL 8 OVER +!
     @ RMARGIN >
     IF  8 HORIZONTAL
         RMARGIN ECOL !
     THEN REDRAW ;

: TOSTART ( -- ) ECOL OFF  SOL OFF  RELINE REDRAW ;
\ this is complicated because we manage 2 cursor variables
\ ECOL and SOL (start of line)
: TOEND   ( -- )
     EDLINE -TRAILING NIP
     DUP RMARGIN <
     IF    |MARGINS| ECOL !

     ELSE  WIDTH SOL !  ECOL OFF
           RIGHTSIDE -TRAILING NIP |MARGINS| ECOL !
     THEN  RELINE REDRAW ;
.( .)
\ page movement
: PGUP  ( -- )
     TOPLINE @ 0=
     IF    EROW OFF
     ELSE -16 TOPLINE+!  THEN REDRAW ;

: PGDN  ( -- )
     REC# EL/SCR +   LASTLINE @ >  IF  HONK  END
     16 TOPLINE+!  REDRAW ;

\ EDITOR functions
DECIMAL
.( .)
: WRITECHAR  ( c -- ) DUP !CHAR VPUT RIGHT  UPDATED ;

: DELCHAR    ( -- )
     RIGHTSIDE  1 /STRING  \ get string right of cursor, cut leading char
     'CHAR SWAP 1+ MOVE    \ write buffer back to CURSOR position +1 space
     RELINE  UPDATED  ;

: PUSHRIGHT ( -- )
     RIGHTSIDE PAD PLACE
     PAD COUNT 'CHAR 1+ SWAP 1- MOVE  \ write back at 'CHAR+1
     BL !CHAR                         \ blank at cursor position
     RELINE UPDATED ;
.( .)
HEX
: TOGGLE  ( -- )
     INSERTING DUP DUP @ -1 XOR  SWAP !
     @ IF BAR CURSOR
          PROMPT: ." Inserting"
     ELSE BOX CURSOR
          PROMPT: ." Overwrite"
     THEN PUTCURS ;

DECIMAL
: BSPACE  ( -- )
     LEFT
     INSERTING @
     IF    DELCHAR
     ELSE  BL DUP  !CHAR VPUT
     THEN  PUTCURS ;

: ESCAPE  ( -- )
     FORTHCOLOR
     PROMPT: ." Forth ok"
     [CHAR] _ CURSOR
     CR QUIT ;

\ VDP clipboard is a stack of lines in VDP RAM
HEX
1000 CONSTANT CLIPBASE     \ start of VDP RAM clipboard
: VDPHEAP   ( -- vaddr) VP @ ;
: VMALLOC   ( n -- vaddr ) VP +! VDPHEAP ;
: VFREE     ( -- ) VDPHEAP #80 - CLIPBASE MAX VP ! ;
DECIMAL
\ clipboard management
: LINE2CLIP ( -- )  [REC#]RECORD  #80 VMALLOC  #80 VWRITE ;
: CLIP2LINE ( -- )  VDPHEAP [REC#]RECORD #80 VREAD  VFREE ;

DECIMAL
: MARK-EOF ( -- ) S" <End of File>" LASTLINE @ 1+ ]RECORD 13 + SWAP MOVE ;

\ Need to double buffer record moves for page to page transfers
: DEL-LINE  ( -- )
      AT-EOF? 0=
      IF
        LASTLINE @ 1+  REC#
        ?DO
           H @  I 1+ ]RECORD OVER #80 CMOVE
          ( heap)  I ]RECORD #80 CMOVE
           SPINNER
         LOOP
      ELSE
         [REC#]RECORD RECSIZE BLANKS
         -LINE
      THEN
      LASTLINE @ 1+ ]RECORD #80 BLANKS
      1 LASTLINE SAFE-!
      MARK-EOF
      REDRAW  UPDATED ;
HEX
: CUT    ( -- )
      VDPHEAP CLIPBASE < IF HONK  END
      LINE2CLIP  DEL-LINE  UPDATED ;

: DEL-CHAR    ( -- )
      EDLINE -TRAILING 0 MAX   \ blank line?
      IF   DELCHAR
      ELSE DEL-LINE
      THEN UPDATED ;

: COPY-LINE ( -- )  VDPHEAP CLIPBASE < IF HONK END   LINE2CLIP ;
DECIMAL
: INSRT-LINE ( -- )
      LASTLINE 1+!
      REC# LASTLINE @
      ?DO
          H @ I ]RECORD OVER #80 CMOVE
           I 1+ ]RECORD #80 CMOVE
          SPINNER
     -1 +LOOP  UPDATED ;

: NEW-LINE  ( -- )
      MEMFULL? IF HONK END
      INSRT-LINE [REC#]RECORD #80 BLANKS RELINE REDRAW  UPDATED ;

: PASTE   ( -- )
      CLIPBASE VDPHEAP >= IF HONK END
      INSRT-LINE  CLIP2LINE  REDRAW  UPDATED ;

: +FILE   ( -- ) SEG @ +  1 10 CLIP SEG !  REDRAW .FILENAME PUTCURS ;

: ENTER   ( -- )
      MEMFULL? IF .MEMFULL  END
      ECOL @ 0=
      IF  EDLINE 2DUP PAD PLACE BLANKS
          INSRT-LINE +LINE
          PAD COUNT [REC#]RECORD SWAP MOVE
      ELSE
          +LINE NEW-LINE
      THEN
      TOSTART ;
.( .)
HEX
: KEYHANDLER ( char -- ) \ TI-99 BASIC key codes used
      CASE
         01 OF  +TAB              ENDOF  \ TAB
         02 OF  PGDN              ENDOF  \ FCTN 6
         03 OF  DEL-CHAR          ENDOF  \ PC Delete / FCTN 1
         04 OF  TOGGLE            ENDOF  \ PC Insert / FCTN 2
         06 OF  NEW-LINE          ENDOF  \ FCTN 8
         07 OF  DEL-LINE          ENDOF  \ FCTN 3
         08 OF  LEFT              ENDOF  \ FCTN S
         09 OF  RIGHT             ENDOF  \ FCTN D
         0A OF  +LINE             ENDOF  \ FCTN X
         0B OF  -LINE             ENDOF  \ FCNT E
         0C OF  PGUP              ENDOF  \ FCTN 4
         0D OF  ENTER             ENDOF  \ ENTER
         0F OF  ESCAPE            ENDOF  \ Esc
         83 OF  COPY-LINE         ENDOF  \ ^C
         84 OF  TOEND             ENDOF  \ ^D
         93 OF  BSPACE            ENDOF  \ ^backspace
         95 OF  TOSTART           ENDOF  \ ^U / PC Home
         96 OF  PASTE             ENDOF  \ ^V
         99 OF  CUT               ENDOF  \ ^Y
         9D OF   1 +FILE          ENDOF  \ ^+
         B7 OF  -TAB              ENDOF  \ ^TAB
         BB OF  -1 +FILE          ENDOF  \ ^-
      ENDCASE
;
.( .)
DECIMAL
: PARSE-PATH ( -- addr len)
      BL PARSE-WORD  2DUP [CHAR] . SCAN NIP
      0= ABORT" '.' Path expected" ;

: .LINES ( -- ) CR LASTLINE @  DECIMAL . ."  lines" ;
: (SAVE) ( -- ) FILENAME COUNT SAVEDV80 .LINES   UPDT OFF  ;
.( .)
: (PURGE) ( -- ) \ erases 4K pages at once
      16 0
      DO
         I 4K * PAGED 4K BLANKS
         SPINNER
      LOOP
      TOPLINE OFF   LASTLINE OFF
      SOL OFF       UPDT OFF
      S" DSK1.UNTITLED" FILENAME PLACE
      HOMECURS ;

HEX
: EDIT ( -- )
      DECIMAL
      DEF-CHARS   EDCOLOR   DRAW.SCR
      INSERTING ON  TOGGLE
      BOX CURSOR
      CLIPBASE VP !  \ set clipboard in VDP RAM
      SAMS-ON
      LIST
      BEGIN
         RKEY DUP  BL [CHAR] ~ BETWEEN
         IF INSERTING @
            IF PUSHRIGHT
            THEN WRITECHAR
         ELSE
            KEYHANDLER
         THEN
      AGAIN ;

DECIMAL
\ User commands
: GO     ( page# --)  1 LASTLINE @ CLIP TOPLINE ! EDIT ;
: FILE  ( n -- ) SEGMENT EDIT ;
: SAVEAS ( -- ) PARSE-PATH FILENAME PLACE  (SAVE) ;
: SAVE   ( -- ) BL PARSE-WORD NIP 0> ABORT" Use SAVEAS command" (SAVE) ;
: LOAD   ( -- )
      ." Purge " (PURGE) ." Loading"
      PARSE-PATH 2DUP FILENAME PLACE
      LOADDV80 MARK-EOF .LINES ;
: PURGE  ( -- ) (PURGE) MARK-EOF DRAW.SCR PROMPT: ." Ready" ;
: PURGEALL   ." Purging segments"
        CR 11 1 DO   I DUP . SEGMENT (PURGE) MARK-EOF   LOOP
        1 SEGMENT ;

CR ." ED99 loaded. "  HERE SWAP -
DECIMAL . .( bytes used)
PURGE 

 

 

  • Thanks 1

Share this post


Link to post
Share on other sites

Camel99 Forth Update 2.62

 

This is a bug fix for the KSCAN routine that made repeating key  (RKEY)  routine fail erratically.

 

There are now two E/A5 binary programs

  1.  CAMEL99     is the 8K program which loads at >A000 as before
  2.  CAML99SC   is the 8K program which loads at >6000 and requires a SuperCart or Classic99 Emulator. This program gives you 8K more CPU RAM.

 

With RKEY working this version has a working version of ED99, an text editor for Camel99 Forth that handles 10 files simultaneously. It requires a SAM 1M card

It is possible to copy multiple lines to the clipboard, with ^C, from one file, change to another file and paste lines into the other file.

It works in 40 columns and seems to compile and run fine in 80 columns (looking forward to someone testing that for me) :) 

More loadable functions are coming... ( COPY file into current file, LOAD current file as Forth code, THRU compile specific line numbers as Forth code and a background printer would be nice) :) 

 

The editor uses the common key commands that we are used to in the simple TI Editor.  For fancy stuff you press escape (FNCT BACK) which drops you into the Forth interpreter.

To compile the editor at the Forth ok prompt type: INCLUDE DSK2.ED99

 

Here are the  key commands:

        Function   	       Key
		-----------    	  ---------
	  	TAB    	      		TAB
        PGDN   		       	FCTN 6
        DEL-CHAR 	       	PC Delete / FCTN 1
        Insert/Overwrite    PC Insert / FCTN 2
        Insert NEW-LINE     FCTN 8
        DEL-LINE            FCTN 3
        Cursor LEFT  	    PC Arrow / FCTN S
        Cursor RIGHT        PC Arrow / FCTN D
        Cursor Down         PC Arrow / FCTN X
        Cursor Up           PC Arrow / FCNT E
        Previous Page 	    PGUP     / FCTN 4
        ENTER               ENTER  ( Inserts a new line as well)
        ESCAPE to commands  Esc
        COPY-LINE           Ctrl C ( non-destructive)
        Goto end of line    Ctrl D
        BSPACE & del char 	Ctrl Backspace
        Start of line       Ctrl U / PC Home
        PASTE               Ctrl V
        CUT                 Ctrl Y
        Next File No.       Ctrl >
       	Tab left            Ctrl TAB
        Previous File No.   Ctrl <

Here is the slightly updated text commands:
 

ED99  Interpreter Commands
---------------------------
: GET    <dsk?.path>   load file, remain in interpreter
: EDIT   [ <dsk?.path? ]  Optional file path. Edit the current file OR Load path

: GO     ( LINE# ) GOTO the line # in the file
: FILE   ( file# ) select the file# segment

: >>     Goto next file#
: <<     Goto previous file#

: SAVEAS <dsk?.path> save current file as new file path name
: SAVE   Save the current file with current file path.

: PURGE  Erase memory for the current file number.

: PURGEALL  Erase the memory segments for all files.

: SAVEALL   Save all files that have been updated

New START file:

I have changed the  DSK1.START file so that it loads DSK1.MARKER  and DSK1.LOADSAVE.  This allows the START file to load binary font file and then remove the loader from memory.

This happens so fast that it doesn't seem to be a big inconvenience. If you don't like it comment it out of the DSK1.START.

If you need help creating new fonts see the "SRC" files on DSK2.  These examples are pretty easy for a TI-99 programmer but just ask if you need help.

\ V2.1 START file loads NEEDS/FROM and then loads ANS Forth extensions
 
S" DSK1.SYSTEM" INCLUDED
 
NEEDS MARKER FROM DSK1.MARKER
 
MARKER RECLAIM
 NEEDS LOAD-FONT FROM DSK1.LOADSAVE
 
 S" DSK2.FONT0230" LOAD-FONT
 
 RECLAIM
 
HEX 17 7 VWTR
 
CR RP0 40 + HERE - DECIMAL . ." bytes free"
 
CR CR .( Ready)
HEX
 

 

Replaced with V2.62b  

 

CAMEL99.262.zip

Classic99 QI399.025 2020-06-19 9_16_10 PM.png

  • Like 2
  • Thanks 1

Share this post


Link to post
Share on other sites

Trying ED99 in 80 column mode

 

After Forth starts type:

INCLUDE DSK1.80COL

The screen resets into 80 column mode. type:

INCLUDE DSK2.ED99

Share this post


Link to post
Share on other sites

Bug Fix to ED99 keyboard speed

In my various attempts to solve the repeating key problem I added a line to RKEY that read a key and threw it away. It was a failed attempt to prevent random characters in the output.

This obviously slows down the ability to read keys from a fast typist :)  and it is no longer needed since the real problem was corrected in KEY?

I forgot to remove this line from the RKEY library file.

 

Fortunately it is an easy fix and you can do it yourself. 

 

INCLUDE DSK2.ED99 in the CAMEL99 system (wait 1 minute for the compile)   {or you could use the E/A editor if you are in a hurry}

 

When the PURGE has completed type:  EDIT DSK1.RKEY

Page down to the following code:

: RKEY ( -- char)
   (RKEY) DROP
    VPOS [email protected]             \ read char from screen
    BEGIN
      PAUSE
      [email protected] 1FFF >        \ read 9901 timer, compare to 50% expired
      IF   CURS @        \ true? fetch cursor char
      ELSE DUP           \ false? use screen char
      THEN VPUT
     (RKEY)
      ?DUP
    UNTIL
    SWAP VPUT ;       \ put the char back
  • Cursor to the line  (RKEY) DROP.
  • Press FCNT 3 or Alt 3 on a PC and remove the line.
  • Press escape and type SAVE
  • Type REMOVE to remove the editor but keep all the support code.
  • Type INCLUDE DSK2.ED99  to re-compile the editor.

 

You will find the keyboard now has normal response.

 

 

  • Like 1

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

  • Recently Browsing   0 members

    No registered users viewing this page.

×
×
  • Create New...