Jump to content

TheBF

+AtariAge Subscriber
  • Content Count

    3,161
  • Joined

  • Last visited

Posts posted by TheBF


  1. Just now, apersson850 said:

    In the p-system, the system itself uses R8-R15. Of particular interest for this program is R10, the stack pointer, and R11, the return address. You can use R0-R7 on your own. But I needed a little more.

    To be able to mess with the other registers I used a BLWP inside this program to my own workspace, and some data moving to get hold of the number of items to sort and their starting address. Note that I also pop the stack by changing the p-system's stack pointer before returning. Otherwise you crash the p-system.

    Today I would have just LWPI a new workspace, but back then I didn't know what to LWPI back to get back to the p-system. Now I know. PASCALWS is 8380H.

    Thanks. I was noting the register usage just now.

    Most of it is very compatible with what I have.  I can create a workspace and load its registers directly from Forth so setting it up is pretty easy.

    This would mean I don't need to reach back to Forth's stack to get the array address and size.

    Lots more study at this end.  I will have to adjust for TI-99 assembler with some directive names.

    Very nicely commented.

    Succinct and helpful.   

     

    • Like 1

  2. Now if I am clever enough to remember how to use my own tools I should be able to:

    1. Assembler this program
    2. Link the object file into Forth with my linker
    3. Fill the array with Forth
    4. Run the sort from the Forth command line. 

    We shall see. I might have to make some memory location tweaks but in theory I can do this.

     

    Thank you. This is very educational for me.

    • Like 1

  3. 12 minutes ago, apersson850 said:

    I used Quicksort too, with bubble sort to finish off the last subsegments. Quicksort itself isn't efficient on short lists.

    My algorithm also removes the recursion, for higher efficiency. Half a second is some average for randomly ordered arrays. It's least efficient if the array is already sorted.

    Do you want to see it?

    I thought you would never ask. :)

    Yes please

    • Like 1

  4. It's nice to see a little progress in my health and the kernel.

     

    I have been beating up my newest kernel where I have moved my stacks around a bit. 

    I had packed things a little tight up in hi RAM and on occasion things were getting stomped. 

    There have also been the changes to what I keep in 16bit RAM and the improvements made in how the "executor" words were being compiled.

     

    I found a "performance notes" file in my folders from 2018 and there was this little test program:

    0 VARIABLE X
    HEX
    : TEST  ." Running..."
            0 X !
            BEGIN
               X @ 4 <
            WHILE
               0
               BEGIN
                 1+ DUP
                 FFFF =
               UNTIL
               DROP
               1 X +!
               X @ 4 =
            REPEAT
            0 X !
            CR ." Done!" ;

     

     

    Back in 2018 with a different computer and a different version of Classic99 I wrote these results. ( I used TF as the gold standard for speed) 

     

    Jan 2018:
    Turbo Forth   57 sec.
    CAMEL99      57.3 sec.

     

    Re-testing this January I get this:

     

    Jan 2022 on Classic99

    Turbo Forth   57.4
    Camel 2.69   55.7   

     

    There are still tons of programs where TF is faster but I finally caught up to Mark on something. :)


     

     

     

     

    • Like 2

  5.  

    7 hours ago, apersson850 said:

    It's all about what you value most.

    Forth is fast and efficient, which makes it effective at runtime, even on low spec hardware.

    The advanced data structures available in Pascal makes software development and maintenance easier. The cost is a bit lower performance at runtime. Mainly speedwise, since the UCSD p-system was developed when memories were small and is therefore pretty advanced when it comes to memory management. Something you have already seen, if you read my previous posts about the internal workings of the p-system.

     

    When I ramped up my use of the 99/4A, Forth was not yet available. I did a little in BASIC, then quickly moved to Extended BASIC, to get more value from the system.

    Tape recorder storage became too limited, so I moved on to expansion box, which I then equipped with everything then available (memory, RS232, disk system and p-code card). From that time, I did all work with the p-system, unless there was a need for it to be useful for people with less equipped machines too.

    Thus I learned how to use it well, what was fully doable in Pascal and how to support with assembly, for the things that were too slow. Like sorting a thousand integers in less than half a second.

    When Forth became available, and then I used what we called PB Forth (Programbiten Forth), a version developed in Sweden from TI Forth, I found it interesting, but not as well structured for software development as the p-system. I also noticed that execution time was less of an issue compared to development time for me. And Pascal excelled in development support and structure.

     

    As a side note, I think PB Forth was the first Forth version for the TI that allowed loading from tape. Thus it was enough with a memory expansion to run it.

     

    Nowadays, when I maintain software for more than a decade, software with tens of thousands of code lines, at work, I do appreciate tools that allow easy development and maintenance of the code itself more than utmost execution speed. With today's hardware, the latter is usually good enough anyway.

    Indeed every language has strengths. The P-code system's comprehensive feature set is very impressive on the TI-99. There is really nothing that comes close that I know of.

    The time I spent (4 years) maintaining and upgrading a significant Turbo Pascal project was very enjoyable.

    I just remembered that back in the 1980s I had a "centerfold" from Byte Magazine of a Pascal program printout laid out on a red satin sheet (a la Playboy magazine) hanging in my locker at work. :) 

    So I was a Pascal fan back in those days.

     

    My opinion on Forth is that one should never program in Forth. :)

    It's extensible like LISP so the first order of business is to make the intermediate language that will allow you to build the application. This makes it harder in the beginning and easier (if you do it well) later.

    IMHO one should borrow any great feature from other languages that wlll get the job done. But that's just my style. 

     

    *QUESTION*

    "Like sorting a thousand integers in less than half a second."

     

    What sorting algorithm did you use for this? 

    I have a quicksort here in Forth  (unoptimized) from Rosetta code that takes 4.4 seconds on a reversed order set and 8 seconds on an empty set with only 2 integers in it which seems to be the worst case.

     

    Apologies to @GDMike  for stealing the thread. 

     

    I used to be confused but now I am not sure

     

    • Like 2

  6. I sat down tonight to look into this a bit more and it's clear why Chuck Moore didn't mandate fancy data structures in the core language.

    The simplest array of strings is created with almost nothing and in some ways is handier to use than simple C strings because they are counted not zero terminated.

     

    \ simplest string arrays. Calculated addresses. No protection. Bare bones 
    CREATE Q$  32 20 * ALLOT
    
    : ]Q$  ( ndx -- addr) 32 * Q$ + ;

    In an embedded application this may be all you ever need. 

    S" Now we can assign strings" 0 ]Q$ PLACE

     

    You can put some "lipstick" on these if you needed to: :) 

    \ fancier: Remember the size and number of strings in the array itself
    \ create operators for this kind of array
    : STRINGS:  ( len # )
      CREATE  2DUP  ,   ,   *  ALLOT   \ compile time: remember the parameters
      
      DOES> 2 CELLS + ;                \ runtime: skip past the parameters
                                       \ returns the base address of the array
    
    : LEN[]    ( addr -- len) 1 CELLS - @ ;
    : MAX[]    ( addr --  n)  2 CELLS - @ ;
    : ERASE[]  ( addr -- )  [email protected] * 0 FILL ;
    
    \ address calculator
    : []    ( ndx addr -- addr') TUCK LEN[] * + ;
    
    64 20 STRINGS: X$
    S" These are a little more verbose." 0 X$ [] PLACE
    S" But they do the job" 1 X$ [] PLACE
    S" Note: These strings reside in CPU RAM"      2 X$ [] PLACE
    S" But we can use other memory spaces as well" 3 X$ [] PLACE
    

     

    Creating an array of pointers with string addresses will require a way to dynamically create a string in memory and assign the pointer to an integer array.

    Forth doesn't have that.  Instead it has the components to make that.  These of course are static strings in this example.

    If we wanted fancier we would have to use ANS/ISO  ALLOCATE  FREE RESIZE . 

    And if we needed garbage collection we would have to build it or find a library and adapt it for for TI-99.

    The cool thing about these pointer based arrays is the strings could be allocated in VDP RAM or SAMS memory or even disk based virtual memory with the pointer arrays in RAM.

     

    \ allocate strings on the fly and assign to an array
    INCLUDE DSK1.ARRAYS
    
    32 ARRAY Y$   \ normal integer array
    : ERASE  ( addr n -- ) 0 FILL ;
    
    0 Y$ 32 CELLS ERASE  \ init pointers to 0
    
    \ compile a string into memory and return it's address
    : $"     ( -- addr)  HERE  [CHAR] " PARSE  S,  ;
    
    $" This string can be of any length up to 255 characters"  0 Y$ !
    $" Each string must be stored in the Y$ array of pointers"  1 Y$ !
    $" Notice that to assign the string we use the integer store operator"  2 Y$ !
    $" To read these strings we use the 'fetch' operator '@' to deference the pointer" 3 Y$ !
    
    : WRITE$   ( addr -- ) @  COUNT  CR TYPE ;
    
    : .Y     4 0 DO  I Y$ WRITE$   LOOP ;
    

    That's all I got for now.  Not nearly as fancy as USCD Pascal but then again we are writing in the extensible assembly language for a 2 stack virtual machine. 

    So for that level of language it's not too shabby. :) 

     

     

     

    • Like 3

  7. I thought might be able to help your project with some modern structures used in Forth these days.

    Here is the structure code and a demo structure definition.

     

    And while I was at it I thought I would demonstrate a way that you can use block files as a database.

    It might give you some new insights on how you could do the bottom end of your database.

    Spoiler
    \ forth 2012 structures with TurboForth Harness   B Fox 2022
    \ A.15 The optional Facility word set
    
    \ TF Harness
    : ALIGNED  1+ $FFFE AND ;
    : PLACE   ( src n dst -- ) 2DUP C! 1+ SWAP CMOVE ;
    
    \ =============================================================
    \ these 2012 Forth words are not 100% necessary, but people like them
    DECIMAL
    : BEGIN-STRUCTURE  \ -- addr 0 ; -- size
       CREATE
         HERE 0 0 ,        \ mark stack, lay dummy
       DOES> @             \ -- rec-len
    ;
    
    : END-STRUCTURE  \ addr n --
       SWAP ! ;      \ set len
    
    \ simplest FIELD creator
    : +FIELD  \ n <"name"> -- ; Exec: addr -- 'addr
       CREATE OVER , +
       DOES> @  +
    ;
    
    \ define forth 2012 field types for TI-99
    : FIELD:   ( n1 "name" -- n2 ; addr1 -- addr2 ) ALIGNED 1 CELLS +FIELD ;
    : BYTE:   ( n1 "name" -- n2 ; addr1 -- addr2 )          1 CHARS +FIELD ;
    
    \ BF custom field types
    : DFIELD:  ( d1 "name" -- d2 ; addr1 -- addr2 ) ALIGNED 2 CELLS +FIELD ;
    : CELLS:  ( n --)  CELLS +FIELD ;
    : CHARS:  ( n --)  ALIGNED CHARS +FIELD ;
    
    
    \ ===================================================================
    \ example: using [ ] brackets as a naming convention
    \ to identity record and fields
    DECIMAL
    
    BEGIN-STRUCTURE ID-RECORD ( returns the size of an ID record )
           FIELD: ID#]
        32 CHARS: NAME]
        32 CHARS: FAMILY]
        64 CHARS: ADDRESS]
        32 CHARS: CITY]
        15 CHARS: PROV]
        25 CHARS: COUNTRY]
        10 CHARS: PHONE#]
        10 CHARS: AREACODE]
    END-STRUCTURE
    
    VARIABLE REC#
    : RECORD     REC# ! ;  \ set the active record
    
    
    \ blocks are 1024 bytes so records should be even multiple
    \ 1024, 512, 256, 128, 64, 32
    \ ID-RECORD is 224 bytes so use 256 as the record size
     256 CONSTANT REC_SIZE
    1024 CONSTANT BUFF_SIZE
       0 CONSTANT 1STBLOCK   \ set YOUR first block to use for database
    
    \ *** needs an open block file to work ***
    \ This is the magic part:
    \ */MOD multiplies rec# x record_size / block_size
    \ it returns: offset and block#
    : [EMPLOYEE ( -- buffer_addr)
      REC# @ REC_SIZE BUFF_SIZE */MOD  1STBLK +  BLOCK + ;
    
    \ load a dummy record
     1 RECORD
      9901        [EMPLOYEE ID#] !
     S" Brian"    [EMPLOYEE NAME] PLACE
     S" Forth"    [EMPLOYEE FAMILY] PLACE
     S" 116 Settlement Park Ave." [EMPLOYEE ADDRESS] PLACE
     S" Markham"  [EMPLOYEE CITY] PLACE
     S" Ontario"  [EMPLOYEE PROV] PLACE
     S" Canada"   [EMPLOYEE COUNTRY] PLACE
     S" (201)"    [EMPLOYEE AREACODE] PLACE
     S" 555-1212" [EMPLOYEE PHONE#] PLACE
    
    
    : WRITE$ ( addr len --) COUNT TYPE  ;
    
    : .REC
    PAGE
          ." == Simple Database =="
    CR    ." ID# " [EMPLOYEE ID#] @ .
    CR
    CR   ." Last  Name: " [EMPLOYEE FAMILY] WRITE$
    CR   ." First Name: " [EMPLOYEE NAME] WRITE$
    CR
    CR   ." Address   : " [EMPLOYEE ADDRESS] WRITE$
    CR   ." City      : " [EMPLOYEE CITY] WRITE$
    CR   ." Prov      : " [EMPLOYEE PROV] WRITE$
    CR   ." Country   : " [EMPLOYEE COUNTRY] WRITE$
    CR
    CR   ." Phone#    : " [EMPLOYEE AREACODE] WRITE$ SPACE
                          [EMPLOYEE PHONE#] WRITE$
    CR
    ;
    

     

     

    • Like 2

  8. 5 hours ago, apersson850 said:

    What you are doing here isn't a string array, though, but a list containing strings. An array does allow random access of any item inside, without having to traverse the list first.

     

    If you want to both have a flexible memory usage and be able to replace a string, the typical approach in a language like Pascal is to use a linked list. Then each data item contains a string as well as a pointer.

    For this to be truly flexible, you need to keep track of the string, the pointer to the next string and the number of words allocated to each variable.

    In UCSD Pascal, they are created by varnew, a command which allocates any number of words on the heap. To release the memory, you must use vardispose. So this is similar to using the standard functions new and dispose, except that the first pair allows the number of words allocated to be undetermined at compile time.

     

    Takes more time to handle, of course, but if memory is at a premium, it may still be worth it. And by handling the pointers, you can delete a string in the list, insert a string and, combining both, replace a string with one of a different length.

    Point taken on this being a list not an array.   It was a mental diversion to distract me from my coughing.  :) 

     

    Linked lists are very cool and flexible but coding in a tiny environment for specific needs they might be needless complication.

    It would be perfectly acceptable to use a computed address for each string in the array for fixed sizes in simple cases if that's all one needed.

     

    To atone for my sins I will make a version that is more analogous to the C example with computed addresses of fixed length strings. :)

     

    As I write this I realize that in the traditional Forth systems with BLOCK based disk systems the common way to do this was to allocate some disk blocks to hold the strings and compute block number and offset with the /MOD operator.

    This allowed strings "arrays" to be the size of the entire disk system with one definition.  Since the BLOCK system is virtual memory, performance was reasonable and you can add more buffers if you need them.

    In fact the error message system used this technique.  Typical of how Chuck Moore removed complexity.

     

    (Verbose constant names used to explain the purpose)

       64 CONSTANT MAX_STRING_LENGTH
    1024 CONSTANT BYTES_PER_BUFFER
    
    :  RECORD ( n -- addr)    MAX_STRING_LENGTH  *   BYTES_PER_BUFFER  /MOD ( -- addr rem)  BLOCK + ;  

     

    But now you have "gone and done it"  @apersson850 as they say the USA.  

    Now I have to see what it would take to make arrays that are lists of pointers to strings.

    I am betting the code is about 100X more complicated than Chuck's solution in the example above. :) 

     

    • Like 2
    • Thanks 1

  9. String Arrays in Forth

     

    I am watching with interest the exploration of @dhe as he works out the details of using C99.  The latest work on string arrays made me wonder how we might do this in Forth.

    Disclaimer: These examples are all in Forth '94 dialect and will need some tweaking to work on FbForth or TurboForth but either system is perfectly capable of doing this.

     

    So this code creates string literals as a tight list.  The start of each of these strings is the length stored in a byte. These are called byte counted strings and are also used in Pascal.  A cool trick with these is you can put them end to end in memory and use the length byte to jump through the list. This the advantage of making this kind of array.

    The disadvantage is you should not change the strings once they are compiled into memory.  (you could but its easy to crash the system this way) 

     

    These are a bit different than the C string arrays @DHE made. 

    The C arrays are of a fixed width because they are using the [,] operators to make a fixed size 2D array in memory.

    This also means you have to be careful. If you dimension the array with each string 10 bytes long and then later write an 11 byte string into that array an "undefined behavior" might occur. :) (It's not a good thing usually) 

     

    So as with all things Forth you first have to teach the machine how to do what you want.  There are no arrays, just memory.

    The amazing thing to me is how we can create something very functional with the simple operations Forth gives us, with a little imagination.

     

    Here is what it took to make arrays and then define one analogous to the C string arrays.

    Spoiler
    \ diy compact string Literal array                       Jan 27 2022 Brian Fox
    
    \ this word is in the kernel.  Shown for reference
    \ Allocate u bytes, "place" string at caddr in memory as byte-counted string
    \ : S,  ( caddr u -- ) HERE OVER 1+ ALLOT PLACE  ALIGN ;
    
    : ,"       [CHAR] " PARSE  S, ; \ parse until " and compile into memory
    
    : NEXT$   ( $addr -- $addr')  COUNT + ALIGNED ;
    : NTH$    ( $list n -- $addr)  0 ?DO  NEXT$  LOOP ; \ GOTO the nth string
    
    \ syntactic sugar
    : LEN  ( $addr -- ) [email protected] ;   \ fetch the length byte of a string
    : {      0 , ;  \ compile 0 to start array
    : }      {   ;  \ compile 0 to end array
    
    \ only now can we make the array because we taught Forth how to do it
    CREATE []STR
         {
           ," first string"   ," second string"  ," third string"
           ," fourth string"  ," fifth string"
         }
    
    

     

     

     

    And here is some example code that does something with the strings 

    Spoiler
    \ code to do something
    : PRINT$  ( $addr --) CR  COUNT TYPE ;
    
    []STR 3 NTH$ PRINT$
    []STR 2 NTH$ PRINT$
    
    \ higher order function to do things to each string in an array
    : [ALL]  ( addr Xtoken --)
            >R
            BEGIN
              NEXT$ DUP LEN
            WHILE
              DUP  [email protected] EXECUTE
            REPEAT
            R> DROP
    ;
    
    []STR ' PRINT$ [ALL]
    

     

     

    Screen shows what happened

     

    ForthStringArray.png

    • Like 2

  10. Feeling a little congested this week. Might have the dreaded plague but tests are not to be found.

    No big deal. I have not even needed to take an aspirin so its pretty mild. Feels like a cold. Might even be a cold.

     

    In the mean time I took some advice that I saw about SAMS cards posted by Lee and others to update my SAMSINI so it works properly for my 1M card and also on Classic99.

    The method recommended is swap the page  selection byte and write 16 bits.  Then to test if it's good, I only read the byte value and compare to what I put in.

    This of course is only good for the 1M card but that's what I own.  If anyone needs something different I am happy to write it up for them.

     

    To make sure it works on real hardware I sent this code to Camel99 TTY and it passed. 

    Spoiler
    DECIMAL
     24 USER 'R12  \ address of R12 in any Forth workspace
    
    HEX
    : SAMSCARD  ( -- ) 1E00 'R12 ! ;   \ select sams card
    \ 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-ON   ( -- ) SAMSCARD 1SBO ;  \ enable mapper
    : SAMS-OFF  ( -- ) SAMSCARD 1SBZ ;  \ disable mapper
    
    \ * SAMSINI sets 1Mbyte card to "pass-through" condition
    : SAMSINI
           SAMSCARD          \ select SAMS card
           0SBO              \ turn card on
           0                 \ register value stays on stack
           4000 20           \ register address, # SAMS regs
           BOUNDS ( -- 4100 4000)
           DO
               DUP >< I !    \ swap bytes and write 16 bits to reg
               I [email protected]  OVER <> ABORT" SAMSINI failed"
               01 +          \ next passthru value
           2 +LOOP
           0SBZ              \ turn off card
           DROP
    ;
    

     

     

    COM1_19200bps - TI-99 VT100 VT 2022-01-27 2_44_27 PM.png

    • Like 3

  11. 15 hours ago, dhe said:

     The CROM is installed "resistant" in extraRAM space (>6000).

    I have never heard the term "resistant" used like this. What does it mean?

     


  12. 24 minutes ago, FarmerPotato said:


    Anyone have ideas on extending the TI tagged object file format?

     

    (I'll call it TOFF)

     

    I'm interested in ways to add long symbol names, up to 31 characters.

     

    If you had a new object file wouldn't you need a new loader in a cartridge too?

     

    It would be up to the all the assemblers and compilers to generate it so they all need changing too.

    What do the new tool chains generate?  They allow long label names.

     

    It would not be hard to modify my linker to read them by changing the 6 to 31 below. :) 

    : GETLABEL  ( addr len -- addr' len' label len)
            /TAG  6 CHOP  -TRAILING ;
    

    But something has to generate the new format. 

    Or are you proposing creating a "standard" for tools chains to comply with?


  13. 1 minute ago, Lee Stewart said:

     

    Not sure how this would play in TI Forth and fbForth. The payloads for DOVAR DOCON DOUSER all call DODOES , which falls through to DOCOL and $NEXT . All colon definitions end in ; , which executes $SEMIS , which executes a copy of $NEXT , which actually might make it possible to separate direct calls to $NEXT with your improvement (would also affect DOEXEC ). All of this code is in scratchpad RAM on the 16-bit bus for speed:

    DODOES DECT SP
           MOV  W,*SP
           MOV  LINK,W
    DOCOL  DECT R
           MOV  IP,*R
           MOV  W,IP
    $NEXT  MOV  *IP+,W
    DOEXEC MOV  *W+,R1
           B    *R1
    $SEMIS MOV  *R+,IP
           MOV  *IP+,W   <<<----copy of $NEXT
           MOV  *W+,R1   <<<----copy of DOEXEC
           B    *R1      <<<---+

    ...lee

    Yes this the traditional way the data words were implemented in FIG Forth.

    I think to do this NEXT "improvement" (if it is one) you would change both instances of $NEXT.

    AND... you have to add  INCT W  in DOCOL before you move W into IP. 

    With the alternative NEXT, W contains the CFA when $NEXT completes and we need the PFA. So DOCOL is slightly slower but it seems NEXT is what matters most.

     

    The other thing I found that broke was any cool code that I wrote with ;CODE. (fast arrays now need a INCT W  instruction added) 

    So it's not free. I was mostly curious at this stage to see if it made a difference. But it is probably not too big to fix up my libraries which are mostly Forth.


    For comparison my existing implementation in Forth Assembler. with macros.  The following is in scratchpad RAM.  ( _exit is your $SEMIS )

    l: _exit      IP RPOP,        \ >8388
    l: _next                      \ Forth ITC NEXT routine (>838A)
    @@9:         *IP+ W  MOV,     \ move CFA into Working register & incr IP 
                 *W+  R5 MOV,     \ move contents of CFA to R5 & INCR W 
                 *R5  B,          \ branch to the address in R5 
    
    l: _enter     IP RPUSH,       \ push IP register onto the return stack 
                  W IP MOV,       \ move PFA into Forth IP register 
                  @@9 JMP,                                                  
    

    Rather than a duplicate copy of _NEXT for _enter (compiled as DOCOL in Forth words)  I just used a cheap JMP instruction and use the saved space for some fast primitives.

     

    The new version became: 

    l: _exit      IP RPOP,        \ >8388
    l: _next                      
    @@9:         *IP+ W  MOV,     
                 *W   R5 MOV,   
                 *R5  B,        
    
    l: _enter     IP RPUSH, 
                  W INCT,                                                   
                  W IP MOV, 
                  @@9 JMP, 
    

     

    So the bottom line is as long as you convert the new W register to the PFA in all the words that need it it should work. I think... :)

     

     

     

     

     


  14. Now that I seem to have a stable build

     

    I have read that an ITC Forth system spends about 50% of its time running the inner interpreter called NEXT.

     

    I often wondered how much difference this would make:

     

    NEXT as it exists in the existing TI-99 Forth systems...

    l: _next     *IP+ W  MOV,    
                 *W+  R5 MOV,    
                     *R5 B,         
    

    Versus this:

    l: _next     *IP+ W  MOV,    
                 *W   R5 MOV,    
                     *R5 B,      

    The difference is only one auto-increment, 4 clocks, but it is a reduction from 56 total to 52 total or a speedup of 3.7%

     

    Now that I have a nice build file it was easier to find out.

    I made a new version of my primitives file with this new NEXT code and I had to add one line to four routines:

    W INCT, 

    to  DOVAR  DOCON DOUSER and DOCOL.

     

    And the results are...  its a bit faster. :) 

    On code like OPTEST below where each word is short and NEXT makes up a big piece of the running time I measured

    12.6 sec.  vs  12.2 sec   or  3.3% speedup.

     

    On a big test like the SEVENS benchmark it was 64.7 secs vs 64.1 secs so very little, but still faster. 

    HEX
    : OPTEST      ( mixed )
              3000 0
              DO
                   AAAA   ( lit)
                   DUP
                   SWAP
                   OVER
                   ROT
                   DROP
                   DUP AND
                   DUP OR
                   DUP XOR
                   1+
                   1-
                   2+
                   2-
                   2*
                   2/
                   NEGATE
                   ABS
                   +
                   2 *
                   DROP
              LOOP  ;

     

    • Like 4

  15. I have an idea.  

    Each silicon diode has a fixed voltage drop of .6 volts.

    If you feed the battery directly with two silicon diodes in series the battery will only ever get 3.8 volts max.

     

    So the circuit is like 

                                                 3.8V                  this diode feeds buss when power is off and buss goes < 3.8 V 

       Earth: -- /\/\/\-----[ battery ] +  ------------------>|----------:  +5 Vcc

                                                        \

                                                          \ ---|<-- |<----------------: +5 Vcc 

                                                              2 diodes charge battery when buss is 5V

     

    I think this will work... 


  16. 3 minutes ago, acadiel said:

    Oh, no - the SuperCap is something I’m doing as an experiment on another board.  The lithium battery is just a replacement battery period.  No SuperCap.  

    Ah.  So same question. The lithium battery needs a source of current to stay charged. It cannot get it via the diode.

    And you cannot connect that lithium cell directly to the 5 volt rail.

     

    I think you now need a path from 5V through some kind of 3.6..3.8 volt regulator that feeds the battery directly.

    A resistor and Zener diode might be sufficient.

     

    So what you have will work until the battery dies. :( (If I am seeing the circuit correcly) 

     

     

     

×
×
  • Create New...