Jump to content

TheBF

+AtariAge Subscriber
  • Posts

    4,470
  • Joined

  • Last visited

Posts posted by TheBF

  1. EQU		SP		10
    STACK	BES		32
    
    LI		SP		STACK
    
    * make these macros
    PUSH	DECT	SP
    		MOV		<REG>,*SP
    
    POP		MOV		*SP+,<REG>
    
    * "normal" sub-routines where you know it will not be nested
    LEAF1   * CODE...		* A leaf is a fast in and out
    		* CODE ...
            RT
    
    * manual coding
    SUB1    DECT 	SP
    		MOV		R11,*SP
            * CODE...
            * CODE...
            MOV		*SP,R11
            RT 
            
    * PUSH/POP MACROS        
    SUB2    PUSH R11
    		* CODE ...
            * CODE ...
            POP R11
            RT 
            
    * FANCIER MACROS
    ENTER 	PUSH R11
    
    RETURN  POP R11
    		RT
    
    SUB3   	ENTER
    		* CODE ..
            * CODE ..
            RETURN
            
    

    I don't use the conventional tools but I make use of Assembler macros to help my brain.  I  have written  up the ideas in "psuedo" Assembler code.

    (Do people use a macro-assembler for the TI-99?)

     

    The concept is that a "leaf" is the native 9900 sub-routine and you keep them for those little fast things and you know you will never nest them.

    For bigger sub-routines I like the stack that Apersson created but I automate it with macros.  With a good macro assembler you can get the code to a pretty hi level.

    (Some Assembler coders might call that heresy) :) 

     

     

     

    • Like 1
  2. 6 hours ago, mizapf said:

    As our machine language programs have direct hardware control, the VRAM address auto-increment should be used, of course. I sometimes wonder how things would like like when we had a full multitasking operating system (maybe for the Geneve 2020?). It would be reasonable to block all direct access to hardware, only offering a system call interface (which would be our XOPs). In that case, we would need lots of simple routines in the kernel, like filling VRAM space.

     

    (I just had a short look at the TMS99000 manual; interestingly, there is no restriction on memory access in the user mode, so any memory-mapped device would be directly accessible. But at least some CRU address ranges are restricted to kernel mode, and a memory-mapped device could then be guarded by a CRU bit.)

    My multi-tasker makes sure anything critical runs to completion before giving up the device.  If the task switch overhead is low, which it can be on the 9900, you can turn off interrupts when you enter a time critical routine and turn them on when you leave. BUT... you must make sure those routines that do this are fast and small.  In my case it's cooperative tasking so interrupts are not required.

    The big problem can be disk I/O which was not written with this in mind so they make cooperative tasking clunky stealing time while waiting for the drive.

    • Like 1
  3. 1 hour ago, Asmusr said:

    VSMW is looping for you. All you need is:

    
    CLR  R0
    LI   R1,>2000
    LI   R2,768
    BLWP @VSMW

    The problem is there are many coding styles and ways to pass parameters in assembly. I even find it difficult to reuse my own routines from one game to the next. 

    I thought there was one of those in the conventional system but I couldn't remember the name. Thanks!

  4. For screen clearing and/or initializing any part of VDP RAM I have preferred to write a little routine that I called VFILL.

    It's like VMBW but writes the same byte over and over. The parameters are:

    • R0  VDP address
    • R1  the byte that will written
    • R2  number of bytes you want to write.

    I don't have conventional source code for it so I won't put anything here that might muddy the water for a new Assembly language coder.

    I suppose I could go all academic and say I will leave that as an exercise for the reader. :) 

     

     

  5. Searching for Text

     

    Just like GDMike I need a search routine for ED99.  I had done some work to create a new Forth2012 word but it was clunky. It used a pre-defined buffer for the input string which is really not cool.

    I think I have something better now. 

    The hard core part is COMPARE and in Camel99 Forth it is build onto top of an Assembler word from the original Camel Forth called S=.

    
     CODE S=  ( Caddr1 Caddr2 cnt1 -- n )
        R2 POP,                   \ adrs2 -> R2
        R1 POP,                   \ adrs1 -> R1
        TOS R0 MOV,               \ cnt -> R0
        TOS CLR,                  \ clear output flag (0 means a match)
        NE IF,                    \ if count<>0 do search
           BEGIN,
             R1 *+ R2 *+ CMPB,    \ compare & auto increment
              NE IF,              \ mismatch found,
                  LT IF, TOS DEC, \ $1<$2
                  ELSE,  TOS INC, \ $1>$2
                  ENDIF,
                  NEXT,           \ Return to Forth
              ENDIF,
              R0 DEC,             \ decr. loop counter
           EQ UNTIL,              \ loop while R0 > 0
       ENDIF,
       NEXT,                      \ Return to Forth
       ENDCODE
    

    It's very low overhead to make S= function like ANS Forth COMPARE

    : COMPARE ( addr n addr2 n2 -- -1|0|1) ROT MIN S= ;
    

    . I borrowed an idea from the late Neil Baud with 3RD and 4TH.  These routines work like PICK but are much faster. In fact on the 9900 they are the same two instructions as OVER.  

    CODE 4TH ( a b c d -- a b c d a )  \ same speed as OVER
               TOS PUSH,
               6 (SP) TOS MOV,
               NEXT,            
               ENDCODE

    Armed with that fire power I now have a proper SEARCH for the system.

    \ search.fth  for Camel99 Forth     Brian Fox  26Jun2020
     ( c-addr1 u1 c-addr2 u2 -- c-addr3 u3 flag )
    \ Search the string specified by c-addr1 u1 for the string specified by c-addr2
    \ u2. If flag is true, a match was found at c-addr3 with u3 characters remaining
    \ If flag is false there was no match and c-addr3 is c-addr1 and u3 is u1.
    \
    
    \ NEEDS DUMP   FROM DSK1.TOOLS  \ debug only
    NEEDS 3RD     FROM DSK1.3RD4TH  \ CODE like OVER but for 3rd and 4th items
    NEEDS COMPARE FROM DSK1.COMPARE
    
    \ MARKER /SEARCH
    
    ( 2OVER is macro for more speed)
    : 2OVER    ( d d2 -- d d2 d) POSTPONE 4TH  POSTPONE 4TH ; IMMEDIATE
    : 4DUP     (  d d2  --  d d2 d d2) 2OVER 2OVER ;
    : 2NIP     ( a b c d -- c d ) 2SWAP 2DROP ;
    
    : SEARCH  ( string1 len1 string2 len2-- string3 len)
              2SWAP (  -- caddr2 u2 caddr1 u1 )
              BEGIN
                 DUP ( test u1 )
              WHILE
                 4DUP COMPARE
                 0= IF 2NIP
                       TRUE
                       EXIT       \  jump to ';'
                  THEN
                 1 /STRING        \ remove 1st char
              REPEAT ;
    

     

    • Like 2
  6. 8 hours ago, arcadeshopper said:

    Yes the HDX MOD uses battery backed ram to load the DSR ROM for the RS232 card.. 

     

    www.ti99-geek.nl/Projects/ti99hdx/ti99hdx.html

     

    Thanks for the reply.  I notice you are out of those baby boards. Any thoughts on when another run will be made? I don't think I am going the HDX route for now.

    I would like to try my crazy idea of putting my own RS232 driver on the board. 

    It's easy to BLIT the original code from Forth so I can keep the bank switch idea if your board supports that functionality as I saw in the original project online.

    Or if all else fails I can always put the ROM back. 

  7. The weirdest bug

     

    Last month I went through my VDP routines to make them compliant with advice from Tursi that hitting the VDP ports in any way with Interrupts on was a no/no.

    I was still randomly getting an error every now and again in the debugger but I couldn't pin-point when it would happen.

    I opened up the heat map for a different reason yesterday and I saw this line running slowly through the entire memory map!

    When the line hit the VDP port addresses that green comet flew through the heatmap. :) 

     

    I traced it to the code that runs when a Forth variable runs.  The cursor variable was being repeatedly read in the input loop.

    CODE: DOVAR   ( -- addr) \ Executor that executes a "VARIABLE"
          *SP     DECT,    \ make room in TOS
           R4 *SP MOV,     \ mov TOS register to stack
           R8  R4 MOV,     \ put contents of PFA in TOS
          NEXT,
     END-CODE
    

    I still do not know why it did it.  I moved the code to another place in the source code so see what would happen...

    The line  went away but I am still seeing: Warning: PC >A072 reading VDP with LIMI 2 

    It is still happening at address >A072 but a different piece of code is there now.

     

    More sleuthing to do.

    It's tough when you use homemade tools. :) 

    HEATMAP_WEIRDBUG.png

    • Like 2
  8. Thank you. This is the first big application I have released to the community beyond the Forth system itself so I am a little shy.

     

    I noticed the "outbreak" of editors too. Maybe it's another virus circulating. :) 

     

    Ok I am with you on all those features.  I can expand the exit window have more lines as well with a few tweeks if that has value to you.

    • Files larger than 511 lines   
      • I made a prototype that gave me 1000 lines. 
      • I am wasting tons of space using a record based internal structure which bugs me. I am looking at alternatives.
    • 80 columns support with the F18A 
      • It current runs in 80 columns out of the box but I have to preload my 80 column library first. I will make a version with that)
    • Printing to PIO (I like my old trusty dot-matrix parallel printer :) )
      • Cool!  I can make a PRINT command that takes the TI-99 device string as a parameter so you should be able to "print" to any legal TI-99 device.
      •  Ultimately I want PRINT to run as a separate task. That requires that I write my own drivers (PIO is pretty trivial) since the DSRs don't behave well in a cooperative environment.
    • BLOCK copy/paste
      • I have that on a todo list down the road.  I will need to provide an inverted char set which I can do simply enough, and select a keystroke to "mark" a section and a keystroke to copy the section to clipboard. (DOS used to use ENTER to end the marking process so that will do)
      •  Then I need a command key to paste the entire clipboard rather that just one line. Control P sounds like a mnemonic choice.  I can add control P pretty quickly.

    I will keep noodling on this and post an update when I am happy with the results.

    • Like 4
  9. 2 minutes ago, BeeryMiller said:

     

    Sorta, yes.  MDOS on the Geneve uses it's master DSR and does not use the DSR on the card.  If you think you are going to go that route, you are going to need to support TI, Myarc, and CorComp.  The Geneve has a test routine to identify the cards I think Jeff White came up with years ago.

     

    Beery

     

    OK. Good to know. 

    Supporting all those platforms is way outside my scope. 

    It's not really a practical idea unless everyone gets a new RS232 card with the battery RAM.

    I supposed it wouldn't be too much to write a loader or use some existing loader to allow others to use a card like this. (?)

     

    For me it's about wasting memory in program space for the driver when there is address space devoted to the job on the card. ?

     

    I understand the serial port cards are hard to come by now but it might be fun to mod a second card at CRU >1500 for this purpose.

    It would certainly be the way to go for writing new DSRs for the card.

    • Like 1
  10. Programmable RS232 DSR ?

     

    I didn't want to start another topic so I am putting this here.

     

    I find the RS232 DSR code pretty useless for my (very tiny) world.  In a cooperative multi-tasking system blocks of code that don't yield when they are busy are very bad. :( 

    This has meant that I ignore it and wrote my own driver.

    After building and using a super cart it occurred to me that the RS232 might benefit from a battery backed-up RAM, letting the programmer load a driver that works for them.

     

    Has this ever been done?

    Any thoughts?

     

    I must confess that thought of being able to compile a Forth driver into the card and/or blit a memory image into it when a program starts,  makes me salivate just a little. :) 

    • Like 2
  11. ED99  V1.0

     

    I am finally modestly content with the ED99 editor.  Here is ZIP file with the whole thing wrapped up as an EA5 program. (Thanks Tursi for that amazing emulator)

    I also uploaded a video showing ED99 in operation so people can get a quick start on how to use it.

     

    Features I like:

    • Cut and Paste to a line clipboard
    • DIR and CAT commands available at command line
    • Holds 10 files simultaneously.  (needs 1M SAMS card)  

    (Not mentioned in the video but the Forth DSK1.TOOLS is buried inside the editor so you actually have a working Forth development system here) :) 

     

    Also DSK1.ED99DOC now also has the BYE command documented. No need to turn off the machine)

     

     

    Things to add:  

    • Expand the max file size beyond 511 lines
      •  Might have to change the internal data organization
    • And some UNDO capability
    • File MERGE command
    • File COPY command
    • File PRINT command via RS232. (background is the goal) 

    ED99.DSK.zip

    • Like 1
    • Thanks 1
  12. I found a paper that gives two options. 

     

    https://dl.acm.org/doi/pdf/10.1145/146559.146561

     

    Token-Pointer Threading

    The Code Field contains a token signifying if this is a primitive or a secondary.

    The Parameter Field contains:

    • Primitives: the machine-language definition of the word, ended with a jump to next . (the Forth interpreter)
    • Secondaries: a list of pointers to the subwords in the definition, terminated with a pointer to return

     

    Token-token Threading

    The Code Field contains a token signifying if this is a primitive or a secondary.

    The Parameter Field contains:

    • Primitives: the machine-language definition of the word, ended with a jump to next.
    • Secondaries: a list of tokens of the sub-words in the definition, terminated with the token for return.
    • Like 1
  13. On 6/22/2020 at 5:28 PM, apersson850 said:

    How do they mix 16-bit and 8-bit codes? Or is that not possible?

    I have not looked deeper than the surface. Got sidetracked working on my editor. :) 

    From what I gather there are different ways people do it.  Anything is possible and probably somebody has tried it with Forth.

    I will have to look into it further.  I would think there would have to be a primary token that tells the interpreter the next 2 bytes are a  (table,token) pair?

    How is it handled in USCD Pascal?

     

  14. ED99 SAMS Library Option for faster editor performance

     

    The published source code for ED99 uses the DSK1.SAMSFTH library file which allows SAMS card access written in Forth.

    There is a native code version of the same functionality called DSK1.SAMS.  You can improve the SAMS speed by about 40% by using this library.

     

    Open the source code for ED99 in an editor and look and the NEEDS lines at the top the file.

    Change the line  FROM DSK1.SAMSFTH   -to-   FROM DSK1.SAMS

     

    When you recompile ED99 you will find that memory purges, file loads and saves are faster and scrolling line by line is faster as well.

     

    Classic99 QI399.025 2020-06-20 12_06_39 PM.png

    • Like 1
  15. 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 VC@             \ read char from screen
        BEGIN
          PAUSE
          TMR@ 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
  16. Do all the TI99 games use the interrupt driven sound player?

    It can be done from within the user program so that the program has intimate knowledge of where the list is playing at any given moment using a cooperative thread.

    The 9900 makes this pretty efficient by using a separate workspace for the player thread. It does take some fine tuning to make the music play at consistent speed so that might persuade people to take the interrupt method but there are other ways to do it.

    • Like 1
  17. 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
  18. 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/L@ 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 2@ ;
    : 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 + C@  ;
    : 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/L@ MIN 0 1 >VPOS SWAP VWRITE ;
    : .BOTBAR  ( -- ) 0 18 C/L@  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 R@ 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 1+@ 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
  19.  

    Beware of feature creep. :)    

    Your imagination is infinite.

     

    I chose to make a line-stack for cutting so when you cut lines they pile up on the line-stack and when you Paste they come off the line-stack. 

    The line stack is in VDP RAM at the moment.

    The feature I really miss is ctrl Z.  Undo.  Gotta study some methods on how to do that without sucking up the entire machine. :) 

     

    • Like 2
    • Thanks 1
  20. Ok so there be a future use for CALL.  All good.  Just curious.

    I am finalizing a working version of my ED99 SAMS editor with my repaired repeating KSCAN routine. (rather embarrassing) :) 

    Anyway it is working pretty well now. I just added some commands for the user to "GO" to a line number. 

    • Thanks 1
  21. Just now, GDMike said:

    No absolutely nothing.. but in forth when I was doing a similar thing CALL was

    : CALL decimal ;

    So does the user need to type it or can they just type CHAR(XXX)  ?

     

    • Like 1
×
×
  • Create New...