Jump to content

TheBF

+AtariAge Subscriber
  • Content Count

    2,874
  • Joined

  • Last visited

Posts posted by TheBF


  1. I can understand @HOME AUTOMATION 's   confusion emoji. 

    This is outside the realm of normal Forth application programming.

    We are modifying how the compiler works, which is fair game in Forth but it means you must have "carnel knowledge"  of the system.

     

    Something that helps ALC programmers understand Forth a bit better is the word HERE is much like $ in assembler.

    However the use of [COMPILE] and IMMEDIATE takes most people a while to wrap their heads around and I still have to do tests to get it right. 😵

    • Like 2

  2. My daughter just told me that there is an old Irish tradition to open the door at midnight let all of the old year leave the house.

    I am opening both doors!  :)

    Happy 2022 to everyone on Atariage

     

    • Like 1
    • Haha 2

  3. From Rosetta code: "Reverse words in a string"

     

    Every now and then you see some code that makes you go huh!  I would NEVER have thought of that.

     

    I made some edits to the explanation and changed the code to upper case for Camel Forth and also put the CR before (REVERSE) 

    The video shows the operation. 

    \ From rosetta code
    \ The word "parse-name" consumes a word from input stream and places it on the
    \ stack as a two element stack string. (addr,len)
    \ The word "type" consumes a stack string and prints it.
    \ Calling these two words before and after the recursive call effectively
    \ reverses a string.
    
    : NOT-EMPTY?  DUP 0 > ;
    : (REVERSE)   PARSE-NAME NOT-EMPTY? IF RECURSE THEN TYPE SPACE ;
    : REVERSE    CR (REVERSE) ;
    
    REVERSE ---------- Ice and Fire ------------
    REVERSE
    REVERSE fire, in end will world the say Some
    REVERSE ice. in say Some
    REVERSE desire of tasted I've what From
    REVERSE fire. favor who those with hold I
    REVERSE
    REVERSE ... elided paragraph last ...
    REVERSE
    REVERSE Frost Robert -----------------------
    CR 
    

     

    • Like 2

  4. Inline Code Simplified

     

    I tried this kind of thing a few years ago but it seemed overly complicated.

    I think this code is better and it is smaller.  I also think it is easily applicable to other indirect threaded Forth systems.

    The big surprise to me was the new way I return to Forth.  See  ;CODE]  

     

    It adds only 54 bytes to the system and you could use machine code between  [CODE     ;CODE]   

    The total overhead for inserting CODE is  4 byte header + 6 byte return= 10 bytes which is about the same size as adding a short word header so not much saving, but sometimes it is clearer to see short code snippets inline.

    \ INLINEASM.FTH headless code words inside Forth definition   DEC 30 2021 FOX
    \ example below for usage
    
    NEEDS .S     FROM DSK1.TOOLS
    NEEDS MOV,   FROM DSK1.ASM9900
    
    HERE
    HEX
    : [CODE ( -- )
              HERE CELL+ ,
              HERE CELL+ ,      \ create the ITC header for a CODE word
              POSTPONE [        \ turn off the Forth compiler
    ; IMMEDIATE
    
    : ;CODE] ( -- )
              IP HERE 6 + LI,    \ (points to Forth after NEXT,)
              NEXT,              \ compile next into headless code word
              ]                  \ turn on the Forth compiler
    ;   IMMEDIATE
    
    HERE SWAP - SPACE DECIMAL . .( bytes) HEX CR
    

     

     

     

    \ example
    VARIABLE X    2 X !
    VARIABLE Y    3 Y !
    
    : TEST  ( -- )  [CODE  Y @@ X @@ ADD,  ;CODE]   X @ .   ;
    

     

    • Like 1

  5. 12 hours ago, OLD CS1 said:

    Quick-and-dirty in compiled XB.  It is not exact and lacks perspective of the moving lines, also has a ~100ms delay between line moves (deliberate to manage speed.)  This was done using 20 characters.  Perspective on the horizontal lines will add more characters, as will more vertical lines.  The lines currently line up to a for row section, as the least steep angle lines up to four characters.  Could be less, could be more.  But, this is just a simple PoC.

    Are just putting CALL CHAR() in a loop for the demo?


  6. 17 hours ago, Asmusr said:

    Here's an implementation of my idea of using 8 VDP RAM buffers for drawing the background. Once the data are uploaded to the VDP, it takes only a couple of machine code instructions to switch between the images, leaving almost all the CPU for the actual game. It can run at any speed, but I have slowed it down to 30 FPS in the demo, waiting for VSYNC before switching the buffer, which prevents any screen tearing you could get from updating the screen while it's being drawn.

     

    The demo is using 218 characters for all 8 images, but depending on how you draw the images it could probably be done with fewer. Note that the lines have to speed up as they reach the bottom of the screen to make it look like a proper 3D animation, so in some cases there will be more than two lines in one character. The 8 buffers take 8 x 768 bytes of VDP RAM in addition to the patterns, so I don't know if my idea could by used with compiled XB, but if I was to implement the game using assembly, that's what I would do.

    beamrider-gfx-8.bin 32 kB · 13 downloads

    I have a minimal understanding of this concept and would love to learn more.

    Is there any chance we could see the source code... :) 


  7. 17 hours ago, GDMike said:

    Anyone have classic 99 running on a Linux machine yet? I've got extra laptops and I'd like to NoT have windoze.

    "The best surprise was the fact that all my usual TI development tools work under linux using Wine, including Classic 99, albeit the latter is a tad slower than under Windows. As a matter of fact, everything I have thrown at Wine has worked so far, such as TI99Dir, TICodEd, Winasm994a and Convert9918, thus recreating my entire development tool chain. Magellan works perfectly as well since it's Java based and Visual Studio Code is available for linux."

     

    Vorticon does as posted above.

    • Like 1

  8. The typical situation is when people new to electricity connect the Ammeter like a it is a voltmeter, across the load.

    This causes all the current that the power source can deliver to flow through the ammeter. 

    It's hard in the beginning, to remember to put the ammeter in series with the load.

    • Like 3

  9. Here is a neat little compiler extension I just made to optimize some code. 

     

    It always bugged me that to mask a number in Forth we had to run a literal number or a constant and the AND word like:

    ( n ) 7 AND 

    That takes an extra pass through the Forth inner interpreter for the literal number, when the 9900 has two very nice ways to do masking in a single instruction.

     

    So how about this?

    The trick here is that we INVERT the mask value at compile time, so we don't have to do it at run time. ;)

    I think this needs one extra MOV on the Forth systems that keep TOS in memory. (?) But it is still going to be faster than using AND and a literal number. 

    HEX
    : MASK:  CREATE INVERT ,  
            ;CODE 4118 ,  ( *W TOS SZC,) 
                  NEXT, 
            ENDCODE
    
    7 MASK: 7AND
    2 MASK: 2AND
    

    By extending the compiler we can create "MASK" directives. With those we can do a MASK in one instruction in Forth.

     

    I can imagine some other applications of this idea where you need words to do other operations with a constant or literal parameter.

    I did it before come to think of it with +CONSTANT that creates words that adds themselves to the top of stack.

     

     : +CONSTANT    CREATE   ,  
                   ;CODE 
                       *W TOS ADD, 
                       NEXT, 
                    ENDCODE

     

    • Like 2
    • Thanks 1

  10. 1 hour ago, GDMike said:

    Ahh ... great to know about Data statement. Does that still remain true if I define my BYTE statement as:

     BYTE >NNNN  or just for a BYTE >NN ?

    Because I always define as BYTE >NNNN

    BYTE >NNNN   is going to  take 1/2 of that number and put it in memory as a byte.  

    It can't swallow an integer.

     

    And so the program counter could end up on an ODD address which 9900 does not like. 

    Therefore as Lee says, use EVEN after BYTE or TEXT and you don't have to worry about it.

     

    • Like 1
    • Thanks 1

  11. Reviewing the linker code showed me that I was being especially careful in how I was coding, probably because I barely understood what I had to accomplish in the beginning.  :

    This meant there were a number of sub-optimal things I have changed.

    I also found out that reading the the object file is only one second of the time used.

    So processing the object data is the biggest slowdown.  I suspect it is that enormous case statement.

     

    I got a significant speedup by putting the most common object code tags earlier in the case statement. 

    This version in the spoiler is about 19% faster so 21.5 seconds for the scaled back LIFE code by Mark. (versus 26.2 before) 

    I suspect a jump-table replacing the case statement would make a big difference.

    My experimenting with jump tables verse CASE/ENDCASE gave me about a 2X improvement.

     

    I am wondering if I could parse character by character faster with SCAN. That might be worth a try as well.

    The 3 second load time of the E/A linker/loader will be very hard match. 

     

    Spoiler
    CR .( EA3 object file LINKER, Aug 10 2021 Fox)
    \ Dec 2021 improved linking speed by 19%
    
    NEEDS WORDLIST FROM DSK1.WORDLISTS
    ONLY FORTH DEFINITIONS
    
    \ NEEDS .S        FROM DSK1.TOOLS
    NEEDS +TO       FROM DSK1.VALUES
    NEEDS CASE      FROM DSK1.CASE
    NEEDS -TRAILING FROM DSK1.TRAILING
    NEEDS ELAPSE    FROM DSK1.ELAPSE
    NEEDS 3RD       FROM DSK1.3RD4TH
    NEEDS MARKER    FROM DSK1.MARKER
    
    HERE
    VOCABULARY DEFS
    
    MARKER /LINKER  \ remove LINKER
    
    ONLY FORTH DEFINITIONS
    DECIMAL
    0 VALUE #1  \ a file handle
    
    HEX
     2000 CONSTANT $2000
    $2000 VALUE BASE-MEM  \ where we load OBJECT files
    
    : ?BREAK  ( -- ) ?TERMINAL ABORT" *BREAK*" ;
    : SPACEBAR ( -- ) KEY? BL = IF  KEY DROP  THEN ;
    
    \ add words so we don't need to include tools
    HEX
    : .ID     ( NFAaddr --) COUNT 1F AND TYPE ;
    DECIMAL
    .( ..)
    : WORDS   ( -- )
               0 >R  ( word counter on Rstack)
               CONTEXT @ DUP CR .WID CR
               @
               BEGIN DUP
               WHILE
                  ?BREAK  SPACEBAR
                  DUP ( -- nfa) .ID SPACE
                  R> 1+ >R
                  NFA>LFA @
               REPEAT
               DROP
               CR R>
               BASE @ >R
               DECIMAL . SPACE ." words"
               R> BASE ! ;
    
    \ heap memory management
    : HEAP   ( -- addr) H @ ;  \ current heap pointer
    : HALLOT ( n -- )  H +! ;  \ move heap pointer
    : HEAP,  ( n -- )  HEAP ! 2 HALLOT ; \ compile n into heap
    
    HEX
    : NEW.
              $2000 H !
              HEAP $2000 FF FILL  \ erase low ram
              HEAP TO BASE-MEM
              ['] DEFS  >BODY OFF  ;  \ remove all DEFS words
    
    \ string utilities
    : CHOP   ( addr len n --  addr' len' addr2 len2 )
          S" 3RD OVER 2>R  1- /STRING  2R>"  EVALUATE ; IMMEDIATE
    
    : /TAG     ( addr len -- addr' len') \ cut tag character
          S" 1 /STRING" EVALUATE  ;  IMMEDIATE
    
    : ?#ERROR    ABORT" Bad number" ;
    
    : PARSE# ( addr len -- n )
            /TAG  4 CHOP NUMBER? ?#ERROR ;
    
    : GETLABEL  ( addr len -- addr' len' label len)
            /TAG  6 CHOP  -TRAILING ;
    
    : DODEF ( addr len n -- )
            >R         ( -- addr' len') ( r: -- ref_addr)
            GETLABEL ( addr' len'  label len)
            HEADER,  COMPILE DOCON  R> ,  \ make a Forth Constant
    ;
    
    VARIABLE PROGLENGTH
    CREATE PROGNAME  10 ALLOT
    
    : PROG-ID  ( addr len -- addr len)
              PARSE# PROGLENGTH !
              8 CHOP  PROGNAME PLACE ;
    
    : .TOOLVER  ( addr len -- addr 0)
              /TAG  40 CHOP -TRAILING CR TYPE  DROP 0 ;
    
    : ?TAG    CR ." Unknown TAG -> "  EMIT ABORT ;
    
    : RELOCATE ( addr -- addr')  BASE-MEM + ;
    
    \ See E/A manual page 309 for meanings of object file tags.
    : ParseObject ( add len -- )
          BEGIN
            DUP ( len<>0)
          WHILE
            OVER [email protected] ( tag)
            CASE
              [CHAR] 0 OF  PROG-ID              ENDOF
    
              [CHAR] 3 OF  PARSE# RELOCATE ( ref)
                           GETLABEL EVALUATE ( ref def)
                           SWAP ( def ref) !    ENDOF
    
              [CHAR] 4 OF  PARSE# ( ref)
                           GETLABEL EVALUATE ( ref def)
                           SWAP  ( def ref) !   ENDOF
    
             [CHAR] 5 OF  PARSE# RELOCATE DODEF ENDOF
             [CHAR] 6 OF  PARSE# DODEF          ENDOF
             [CHAR] A OF  PARSE# RELOCATE H !   ENDOF
             [CHAR] C OF  PARSE# RELOCATE HEAP, ENDOF
    
              [CHAR] 9 OF  PARSE# H !           ENDOF
              [CHAR] B OF  PARSE# HEAP,         ENDOF
              [CHAR] F OF  DROP 0               ENDOF \ end of record
              [CHAR] : OF  .TOOLVER             ENDOF
    
              [CHAR] D OF  [CHAR] D ?TAG        ENDOF
              [CHAR] E OF  [CHAR] E ?TAG        ENDOF
              [CHAR] 1 OF  [CHAR] 1 ?TAG        ENDOF
              [CHAR] 2 OF  [CHAR] 2 ?TAG        ENDOF
              [CHAR] 7 OF  4 /STRING            ENDOF
              [CHAR] 8 OF  4 /STRING            ENDOF
    
            ENDCASE
            1 /STRING 0 MAX  \ advance to next char
         REPEAT
         2DROP ;
    
    
    DECIMAL
    : EA3LOAD ( caddr len -- )
               CR ." Linking " 2DUP TYPE
               SOURCE-ID @ >IN @ 2>R           \ save source-ID, input pointer
               PSZ NEGATE ^PAB +!              \ make new PAB, on pab stack
               ( $ len ) 80 04 FOPEN ?FILERR   \ OPEN as DISPLAY FIXED 80 INPUT
               SOURCE-ID 1+!                   \ incr. source ID (1st file is 1)
               LINES OFF                       \ reset the line counter
               BEGIN
                 2 FILEOP 0=                   \ file read operation
               WHILE
                 HERE 200 + DUP FGET ( addr n) \ read line to temp mem buffer
                 ParseObject                   \ interpret line of object code
                 LINES 1+!                     \ count the line
               REPEAT
               PSZ ^PAB +!                     \ remove PAB from pab stack
               2R> >IN !  SOURCE-ID !          \ restore >IN, SOURCE-ID
    ;
    
    : ?PATH ( addr len -- addr len)
           2DUP [CHAR] . SCAN NIP 0= ABORT" Path expected" ;
    
    : LINK ( <PATH> )
           TICKER OFF
           BASE @ >R
           HEX
           ONLY FORTH ALSO DEFS DEFINITIONS
           PARSE-NAME ?PATH EA3LOAD
           R> BASE !
    
           HEAP TO BASE-MEM
           CR DEFS WORDS
           .ELAPSED ;
    
    \ Linkage to Forth
    HEX
    CODE RUN  ( def --)  0454 ,  C136 , NEXT, ENDCODE  \ B  *TOS    DROP
    CODE CALL ( def --)  0694 ,  C136 , NEXT, ENDCODE  \ BL *TOS    DROP
    CODE BLWP ( def --)  0414 ,  C136 , NEXT, ENDCODE  \ BLWP *TOS  DROP
    
    : EXTERN:   ( def --)  CODE  0460 , ( addr) ,  NEXT,  ;   \ B @def
    : EXT-SUB:  ( def --)  CODE  06A0 , ( addr)  ,  NEXT,  ;  \ BL @def
    : EXT-PROG: ( def --)  CODE  0420 , ( vector) ,  NEXT,  ; \ BLWP @def
    
    ONLY FORTH DEFINITIONS ALSO DEFS
    
    PAGE .( Camel99 Linker  Dec 2021)
    CR
    CR .( Usage: )
    CR .( NEW.  clear low ram for code)
    CR .( LINK DSK?.FILENAME   load object)
    CR .( Commands:)
    CR .( <def> RUN     branch to def)
    CR .( <def> CALL    BL to def)
    CR .( <def> BLWP    blwp to def)
    CR
    CR .( Declare DEFs as Forth code: )
    CR .( <def> EXTERN: <name>  branches to DEF)
    CR .( <def> EXT-SUB: <name> BL to DEF)
    CR .( <def> EXT-PROG: <name> BLWP to DEF)
    CR .( <def> EXT-DATA: <name> def ->Forth constant)
    CR
    NEW.
    CR .( Low RAM initialized)
    CR HERE SWAP - DECIMAL . .( bytes)
    

     

     

     

    • Like 3

  12. My eyes were starting to cross working on the editor so I looked around the site and saw Mark Will's game of life in the post about John Conway's passing.

    I took a look at the Assembler code and thought this might be a good test of my linker.

    I made a few simple changes:

    1. Removed large amount of text to make sure it was less than 8K as a binary image
    2. Moved the Workspace to high end of LOW RAM to keep GPL workspace un-touched
    3. Remove the AORG directive so it would be relocatable 

    The video shows what happened. It works but there are some artifacts on the screen that means I have something wrong still.

    The linker is naturally much slower at reading the object code than an ALC version would be, about 9 times!. I am just happy that it loaded. :)

    So finding the cause of the artifacts and looking at some optimization in the text interpretation are two goals.

     

     

    • Like 1

  13. 1 minute ago, GDMike said:

    it just sets everything to >2020..but i disabled it and it didnt make a difference..I was thinking maybe it might be hitting high ram and causing an issue but its not.

    I was just thinking it could be a bit faster if you didn't write numbers on the screen. Maybe just "." 

     

     

×
×
  • Create New...