Jump to content

TheBF

+AtariAge Subscriber
  • Posts

    4,470
  • Joined

  • Last visited

Posts posted by TheBF

  1. MOVE in ANS Forth does a test to determine if it should do CMOVE or CMOVE>.

    (not very true to Forth philosophy but there it is)

     

    I just tried it before I posted to make sure that darn thing actually worked. :)

    It seems to. 

    Maybe because my top of stack in R4. ?

     

    (Way back , after I found the recursive one in your source code, I just played around until something seemed to work. I have not actually put it in a program to your point.)

     

    • Like 1
  2. Here is a word you can tuck away on a TURBO Forth block somewhere.

     

    POSTPONE replaces COMPILE and [COMPILE] and so it can make translating ANS Forth code a bit easier.

     

    I tried it on TF and it seems to work.

     

    : POSTPONE ( <name> -- )
     \ replaces COMPILE and [COMPILE]
        BL WORD FIND DUP 0= ABORT" POSTPONE can' find"
        0< IF COMPILE COMPILE
        THEN , ; IMMEDIATE

     

    You use POSTPONE like COMPILE or [COMPILE] but it knows the difference between compiling an IMMEDIATE word or a normal word. 

     

    Example:  > is normal,  IF is immediate.  No problem

    : >IF      POSTPONE >  POSTPONE IF ; IMMEDIATE 

     

     

    Test 

    : TEST   >IF  ." bigger" ELSE   ." less than"  THEN ; 

     

    Classic99 QI399.046 2024-01-26 3_10_41 PM.png

    • Thanks 1
  3. 52 minutes ago, Lee Stewart said:

     

     

    OK...Here is an ALC recursion that works! It is 40 bytes, so 6 bytes longer than the simple loop, but it certainly is satisfying to accomplish it!

     

    ROLL   DATA $+2
           LI   R7,ROLLIT   ;load entry point for recursive call
           MOV  *SP+,R2     ;pop position (count)
           BL   *R7
    ROLLEX B    *NEXT
    
    ROLLIT 
    *++ Push return address to return stack
           DECT R
           MOV  R11,*R
    *++ 1-
           DEC  R2
    *++ IF
           JLT  ROLITX      ;we're done if negative
    *++ >R       
           DECT R
           MOV  *SP+,*R
    *++ MYSELF (recurse)
           BL   *R7
    *++ SWAP R>  (pop return stack to stack and SWAP)
           DECT SP
           MOV  @2(SP),*SP  ;over
           MOV  *R+,@2(SP)  ;under
    *++ Pop return address and return
    ROLITX MOV  *R+,R6
           B    *R6

     

    Can it be refactored to tighter code?

     

    ...lee

    Is there a way to not load R7 and rather replace the MYSELF line with 

             BL @ROLLIT

     

    or some such computed address to the entry to the code

  4. 46 minutes ago, Lee Stewart said:

     

     

    OK...Here is an ALC recursion that works! It is 40 bytes, so 6 bytes longer than the simple loop, but it certainly is satisfying to accomplish it!

     

    ROLL   DATA $+2
           LI   R7,ROLLIT   ;load entry point for recursive call
           MOV  *SP+,R2     ;pop position (count)
           BL   *R7
    ROLLEX B    *NEXT
    
    ROLLIT 
    *++ Push return address to return stack
           DECT R
           MOV  R11,*R
    *++ 1-
           DEC  R2
    *++ IF
           JLT  ROLITX      ;we're done if negative
    *++ >R       
           DECT R
           MOV  *SP+,*R
    *++ MYSELF (recurse)
           BL   *R7
    *++ SWAP R>  (pop return stack to stack and SWAP)
           DECT SP
           MOV  @2(SP),*SP  ;over
           MOV  *R+,@2(SP)  ;under
    *++ Pop return address and return
    ROLITX MOV  *R+,R6
           B    *R6

     

    Can it be refactored to tighter code?

     

    ...lee

     That is totally awesome.  I got called away and didn't get to play with this.

    Felicitations!

     

    • Thanks 1
  5. 21 minutes ago, apersson850 said:

    I don't know which language they intended that to be, but it's not Pascal. In Pascal, it would be like one of these two:

    function empty(q:queue): boolean;
    begin
      if q.front=q.rear then
        empty := true
      else
        empty := false
    end;
    
    function empty(q:queue): boolean;
    begin
      empty := q.front=q.rear
    end;

     

    Just because you don't use Forth you don't have to overcomplicate things.

     

    Very nice.  It shows how people who write text books don't always have a clear view on the real world engineering demands. 

     

    If you do complicate things now Herr Wirth will probably come to haunt you. :)

     

    I notice that I typed that in wrong with that leading '('.    mea culpa. 

     

  6. By the way I counted wrong in that comment above.

    GForth takes 10 instructions in Intel land.

    Code pick
    ( $40339C )  mov     dword ptr 41F2D8 , ebp  \ $89 $2D $D8 $F2 $41 $0
    ( $4033A2 )  mov     eax , dword ptr [edi]  \ $8B $7
    ( $4033A4 )  add     edi , # 4  \ $83 $C7 $4
    ( $4033A7 )  mov     eax , dword ptr [edi] [eax*4]  \ $8B $4 $87
    ( $4033AA )  sub     edi , # 4  \ $83 $EF $4
    ( $4033AD )  mov     dword ptr [edi] , eax  \ $89 $7
    ( $4033AF )  mov     eax , dword ptr 0 [ebp]  \ $8B $45 $0
    ( $4033B2 )  add     ebp , # 4  \ $83 $C5 $4
    ( $4033B5 )  mov     esi , eax  \ $89 $C6
    ( $4033B7 )  mov     ebx , dword ptr [eax]  \ $8B $18
    ( $4033B9 )  jmp     40152A  \ $E9 $6C $E1 $FF $FF
    end-code
     ok

     

    But I just checked out VFX Forth's version!

    see pick 
    PICK 
    ( 004323D0    488B5CDD00 )            MOV     RBX, [+RBX*8]
    ( 004323D5    C3 )                    RET/NEXT
    ( 6 bytes, 2 instructions )
     ok

     

    • Like 1
  7. After I saw your Forth version I took the approach that since "thou shalt not roll",  the recursive Forth version was good enough. :)

     

    My Pick looks like this.  I never considered putting ABS in there. 

    CODE PICK   ( n -- n)   \ GForth ITC takes 8 intel instructions for PICK
                  TOS  1 SLA,       \  (" n CELLS")
                  SP TOS ADD,     
                 *TOS TOS MOV,  
                  NEXT,         
    ENDCODE
    

     

     

    But in mission critical uses I load 3RD and 4TH which are the same size as OVER in 9900 code. 

    HEX
    CODE 3RD  ( a b c d --  a b c d b)  \ ANS: 2 PICK
              0646 , C584 ,  \ TOS PUSH,      
              C126 , 0004 ,  \ 4 (SP) TOS MOV, 
              NEXT,  
              ENDCODE
    
    CODE 4TH  ( a b c d e--  a b c d e a) \ ANS: 3 PICK
              0646 , C584 ,  \ TOS PUSH, 
              C126 , 0006 ,  \ 6 (SP) TOS MOV,
              NEXT,
              ENDCODE

     

    • Like 1
  8. 2 hours ago, khanivore said:

    Looking at the generated code, while gcc normally calls a function like this:

            bl   @puts          


    If you optimise using -O2 or -Os it decides to use an intermediate register for some reason:

            li   r2, puts                                                                                                 
            bl   *r2


    which is generally worse not better.  It might be slightly better if the load was outside a loop but the compiler rarely does the load outside the loop from what I've seen.


    Even worse, when it runs short of registers it spills the reg to the stack resulting in this absolute mess:

            li   r2, testColorText                                                                                        
            mov  r2, @>4(r10)                                                                                             
            ...        
            mov  @>4(r10), r2                                                                                             
            bl   *r2


    I've been desperately trying to find a way to stop it from storing labels to registers before doing a branch or call and I just can't.  I added cost functions that made calls to registers prohibitively expensive but they made no difference.  I tried a peephole which sometimes worked but it crashed when I encountered cases like above where the label had been pushed to the stack.

    Then I stumbled across the switch -fno-function-cse which happily stops gcc from doing the stupidity above.  Even with -Os now we don't get label stores to regs.  I'd recommend everyone add this to their CFLAGS in their Makefiles if using optimisation.  So I'm going to consider this issue as "closed won't fix" as there is a valid workaround 🙂

    That's an amazing win. Well done.

     

    I am absolutely flabbergasted at the complexity of this monster, and the patience you guys have to keeping flipping switches until it does your bidding.

    It flies in the exact opposite direction of what I play with... but it gets results. 

     

    I joked about writing the lisp dialect that controls this GCC process in RPN but after pondering it for while I realize it is not a crazy idea.

    Forth like LISP makes creating a domain specific language pretty simple.

    in fact boolean functions in RPN are quite neat and have far less brackets. :) 

     

    Example so you know what I mean and then I will stop distracting the thread.

    HEX
    
    DEAD 00FF AND  0080 OR  -1 XOR .   \ dot prints the result
    
    \ logic language extensions
    : NAND ( n n --?)  AND NOT ; 
    : NOR  ( n n --?)  OR NOT ; 

    Your head stops hurting after a short time using it and testing stuff in the REPL.

     

    >>We now rejoin our regularly scheduled program already in progress<<

     

    • Like 1
    • Haha 3
  9. I think recursion here is  a "call" in machine code. So for 9900 we would need to make the code a nestable sub-routine that pushes R11 on entry and pops R11 on exit.

    Essentially you are making one Forth word a "subroutine threaded" word. 

     

    I will play around a bit too and see if I am blowing smoke on this. :) 

    Come to think of it I don't think I got around to making RECURSE in my machine code project so maybe I can try implementing and testing on that platform.

    I predict a few crashes... ;)

     

     

    • Like 1
  10. What would it look like if you strung the Forth primitives end-to-end, without NEXT,  use Assembler IF ENDIF and a JMP to do the recursion?

     

    : ROLL  ( [n]..[0] +n --- [n-1]..[0][n] )
                 \ #instructions
       -DUP      \  3
       IF        \  1
          1-     \  1 
          SWAP   \  3
          >R     \  2
          MYSELF \  1 ??
          R>     \  2
          SWAP   \  3
       THEN ; \ =  15  

     

    Potentially the same number of instructions. :( 

    Maybe some optimizations could be found with SWAP because you are using registers in the code. So maybe you just SWAP the argument order?

    Might worth a look.

     

    • Like 1
  11. Back 2021 I needed a way to capture text output from programs. 

    I threw something together but it was not ideal. For example if you sent strings to the screen without a CR now and then it would fail. 

     

    This updated version is more robust and bettered factored. 

    >> If you have a Camel99 system disk, please replace DSK1.OUTFILE with this file. 

     

    Of note to the student of Forth on TI-99, I am accessing the PAB, in VDP memory, just as easily as CPU RAM by using the VDP operators V@ V!  VC@ and VC!.

    The do the same things as their regular Forth namesakes. 

    The various fields of PAB are accessed referenced to the "SELECTed" file PAB with a syntax using the active PAB with a field selector word.

    The field selector simply adds an offset to the base address of the PAB.  These are the words that have square brackets.

     

     To use this file you INCLUDE DSK1.OUTFILE  first.  Then any program loaded afterwords will use the dual output versions of the text output words.

    If you MAKE-OUTPUT or OPEN-OUTPUT (append mode)  the program text will go to the screen and echo to the file. 

    Kernel words that use the kernel output words will not echo to the file. 

     

    In future I might patch the kernel words which would make everything to echo but at this time I don't need that. 

     

     

    Spoiler
    \ OUTFILE.FTH   echo screen output to text file      May 2021  Brian Fox
    \ updated Jan 2024 
    
    \ Method: Write data directly into PAB file buffer
    \ Use the PAB char count in the PAB as pointer into the PAB when we write.
    \ ie: the buffer address= [PAB FBUFF] V@  + [PAB CHARS] VC@ 
    \ Only write to disk when CR is encountered or if buffer will overflow.
    \ No control characters allowed. Use spaces for DV80 files
    
    \                   *** THIS VERSION WORKS **** 
    NEEDS WRITE-FILE  FROM DSK1.ANSFILES
    NEEDS VALUE       FROM DSK1.VALUES
     
    DECIMAL
    0 VALUE OUTH   \ output file handle
    VARIABLE FOUT  \ byte counter for outfile 
    
    : MAKE-OUTPUT ( a u -- ) \ *G creates a new output file
        DV80 W/O CREATE-FILE ?FILERR  TO OUTH 
        FOUT OFF ;
     
    \ : W/A   APPEND FAM @ ;  \ Moved to DSK1.ANSFILES
    : .OUT  ( -- ) FOUT @ U. ." bytes output"  ; 
    
    : OPEN-OUTPUT  ( a u -- ) \ open output file in APPEND mode
        OUTH ABORT" Output file is already open"
        DV80 W/A OPEN-FILE ?FILERR  TO OUTH 
        FOUT OFF ;
     
    : CLOSE-OUTPUT ( -- )
        OUTH CLOSE-FILE DROP   0 TO OUTH 
        .OUT ;
     
    : WRITE-PAB ( handle -- ) SELECT  3 FILEOP ?FILERR ;
    
    : [PABCHARS]+! ( n -- ) [PAB CHARS] VC@  +  [PAB CHARS] VC! ; 
    : [OUTBUFF]    ( -- Vaddr) [PAB FBUFF] V@   [PAB CHARS] VC@ + ;
    
    : FLUSH-BUFFER ( -- ) OUTH WRITE-PAB    0 [PAB CHARS] VC! ;
     
    : OVERFLOW?  ( n -- ?)  \ test n bytes will overflow buffer
        [PAB CHARS] VC@ +   \ add n to chars in the buffer 
        [PAB RECLEN] VC@ >  \ compare to the maximum size 
    ;
    
    : >>OUT ( caddr len -- )
        OUTH 0= ABORT" Output file not open"
        OUTH SELECT 
        DUP OVERFLOW? IF  FLUSH-BUFFER  THEN 
        TUCK  ( -- len caddr len )         \ get a copy of the length
        [OUTBUFF] SWAP VWRITE              \ write string to PAB buffer
        ( len) DUP [PABCHARS]+!  FOUT +! ; \ update Char count
     
    \ ==========================================
    \ redefine standard output words to echo to file if output handle<>0
    : EMIT  ( c --)   OUTH IF DUP HERE C!  HERE 1 >>OUT  THEN EMIT ;
    : TYPE  ( a u --) OUTH IF 2DUP  >>OUT  THEN TYPE ;
    
    : ."  (  ccc" -- )
        POSTPONE S" 
        STATE @ IF POSTPONE TYPE   EXIT   THEN TYPE ; IMMEDIATE
    
    : SPACE   BL EMIT ;
    : SPACES  ( n -- ) 0 MAX  0 ?DO  SPACE LOOP ;
     
    : CR   ( -- )
        OUTH IF \ file is open
           [PAB CHARS] VC@  0= IF SPACE THEN FLUSH-BUFFER
        THEN CR  ;
     
    \ number output with echo
    : UD.  ( d -- ) <#  #S  #> TYPE SPACE ;
    : U.   ( u -- ) 0 UD. ;
    : .    ( n -- ) DUP ABS 0 <#  #S ROT SIGN  #> TYPE SPACE ;
     
    

     

     

    OUTFILE

    • Like 1
  12. I know you are well beyond the Intel hex thing now @VORTICON but I am trying to confirm/deny that code I got from MaxForth is generating a compliant checksum.

     

    Based on a post by @apersson850 I think one line of your code would need to change to give the same result that my version generates. 

    On 1/19/2024 at 10:00 AM, apersson850 said:

    That was supposed to be the 1's complement. For 2's complement i used the odd(-n) instruction. A minus sign in Pascal is like NEG in assembly and that's the same as 2's complement.

     

    Could someone confirm that the 2nd line below would be the correction from 1s' complement to 2's complement.

    (Lee is watching I hope I spelled that right or I will only get part marks) ;)

     

    ( ORIGINAL LINE } 
     DATACHECK := ORD(NOT(ODD(DATACHECK)) AND ODD(255)) + 1;
    
    { Should be ? }
      DATACHECK := ORD((ODD(-DATACHECK)) AND ODD(255));

     

    • Like 1
  13. Here is a version of of LOADHEX that calculates a checksum as the file records are parsed and compares it to the checksum at the end of each record. 

    The checksum addition is embedded in each parsing word that cuts the record string and converts to a number. 

     

    If you type CHECKSUM OFF the loader will ignore the checksum byte at the end of each record.

    CHECKSUM ON   will cause the program to halt with an error and a line no. if the checksums do not match. 

     

    The MaxForth encoder seems to do something tricky. I have not figured out if it is compliant with the checksum specification

    Randy's code adds each binary byte to a variable.

    But the value it puts at the end of each record is that total, taking only the lower order bits , NEGATE that byte and mask with >FF. 

    (see CHKSUM@ below) 

     

    Anyway this loader uses what it was given. I will review the spec. and see if there is something wrong.

    (I suspect Randy was smarter that I am in this area) :)

     

     

    Spoiler
    \ HEXLOADER.FTH  loads intel hex files into memory   Fox 2024 
    
    INCLUDE DSK1.TOOLS 
    INCLUDE DSK1.ANSFILES 
    INCLUDE DSK1.VALUES 
    
    VARIABLE CHKSUM     \ Accumulator for to compute check sum
    VARIABLE CHECKSUM   \ flag:. halts on checksum error if CHECKSUM=TRUE
    
    HEX 
    \ renamed for clarity of purpose 
    : LEFT$  ( addr len n -- addr len' ) NIP ;
    : RIGHT$ ( addr len m -- addr' len') /STRING ;
    
    : CHOP  ( addr len n -- addr1 len1 addr2 len2 )
        >R                 \ we need n twice, use return stack 
        2DUP  R@ LEFT$     \ substring 
        2SWAP R> RIGHT$    \ "RIGHT$" is remainder
        2SWAP ;            \ substring back on top
    ;
    
    : $VAL  ( addr len -- n) NUMBER? ABORT" Bad number" ;
    
    \           *** data management tags ***
    \ Words that are in angle brackets operate on a string.
    \ They take a part of the string convert it to a number
    \ and leave the remainder of the string on the data stack 
    \ for the next function to use. 
    
    \ aborts if start code not found 
    : <?START>  ( addr len -- addr' len') 
       1 CHOP DROP  C@ [CHAR] : <> ABORT" Start code not found" ; 
    
    \ field parsers update the chksum variable
    : <RECLEN>   ( addr len -- C ) 2 CHOP $VAL DUP CHKSUM +!  ;
    : <ADDRESS>  ( addr len -- n ) 4 CHOP $VAL DUP SPLIT + CHKSUM +! ; 
    : <RECTYPE>  ( addr len -- C ) 2 CHOP $VAL DUP CHKSUM +! ;
    : <DATABYTE> ( addr len -- C ) 2 CHOP $VAL DUP CHKSUM +! ;
    
    
    \ This is the last tag. It consumes the string. Returns file's chksum
    : </CHKSUM>  ( addr len --  n ) $VAL ; 
    
    0 VALUE #1  \ file handle holder 
    
    : OPEN     ( fam -- )  OPEN-FILE ?FILERR ;
    : READLN   ( addr -- addr size ?) DUP 80 #1 READ-LINE NIP 0=  ;
    
    : <DATALINE> ( addr len -- ) BOUNDS DO  <DATABYTE> I C!  LOOP ;
    
    \ This matches the checksum calc used by MaxForth's intel HEX save. 
    : CHKSUM@  ( -- c) CHKSUM 1+ C@ NEGATE 0FF AND ;
    
    : .DEC        BASE @ >R  DECIMAL  .  R> BASE ! ;
    
    : ?ABORT  CHECKSUM @ ABORT" LOADHEX halted" ;
    
    : ?CHECKSUM  ( n -- ) 
       CHKSUM@ <> 
       IF  
          CR ." >>> Checksum error Line: " LINES @ .DEC
          ?ABORT
       THEN  ;
    
    : LOADHEX ( path$ len -- )
        LINES OFF 
        HEX 
        DV80 R/O OPEN TO #1 
        BEGIN 
           PAD READLN  ( -- addr len ?)
           LINES 1+!       
        WHILE ( read=true)
           CHKSUM OFF 
           <?START>      \ TEST for start code. Abort if wrong
           <RECLEN>  >R  \ use this later 
           <ADDRESS> >R  \ use this later ( r: -- len addr)
           <RECTYPE> 0=  \ 0 means a data record  
        WHILE     
           R> R>       ( -- addr len )    
           <DATALINE>  \ parse the data and write to memory 
           </CHKSUM>   \ clean up what's left. Return file line chksum 
           ?CHECKSUM   \ compare to computed chksum from file load
        REPEAT 
         UNLOOP        \ first time I ever used this word :-)
        THEN 
        2DROP
        #1 CLOSE-FILE ?FILERR
    ;
    
    \ HEX 2000 2000 FF FILL \ for testing 
    CHECKSUM ON 
    
    

     

     

    • Like 2
  14. Some SAMS ideas that others may find useful. ?

     

    In my SAMS system I remember the last SAMS page that was used in a memory location.

    When it comes time to pull in a page I test if it's already in memory and jump around the mapping code. 

    Otherwise I update the variable, which adds one instruction to the mapping code. 

     

    This works well on simple setups where I just have one 4K window reserved for SAMS pages.

     

    Another thing I have done is to think of 1M SAMS as 16  64K segments.

    I keep a variable for the active segment. 

    This lets you use 16 bit address math and 64K is usually enough for a specific purpose in my programs. 

     

    Also have a piece of code that given a 16 bit address, it computes the SAMS page and the offset which is added to the RAM window address. 

    This can be done with a DIV by 4096, to get a quotient and remainder or with some bit twiddling that @Lee Stewart created for me. 

     

    This gives you a contiguous 64K virtual memory space that you can access sequentially like it really existed. :) 

     

    I would show you the code but it is in Forth's reverse polish Assembler so you need to read it hanging from the ceiling by your feet.

    (so said @apersson850 one time) :)

    And these ideas are not complicated for people to implement their own way. 

     

     

     

     

    • Like 2
  15. I forgot mention enabling the mapper with SBO 1.

    and disabling with SBZ 1. 

     

    But now I am confused because I see the web page link shows SBO 2/SBZ 2  enabling the mapper. 

    ??? 

     

    Can it be either bit, because my code works on real iron last time I checked. 

     

    (And I just rechecked)

     

    COM1_19200bps - TI-99 VT100 VT 2024-01-22 10_28_34 PM.png

    • Like 2
  16. 3 hours ago, dhe said:

    What is my best source for easily understood assembly code for manipulating the bank switching in a SAMS memory card?

    For what it is worth I spent some time getting my head around the card from that same document.

    Here is synopsis what have I learned at a high level. It might give you a jumpstart. 

     

    1. The SAMS card is controlled by the CRU I/O buss that the 9900 uses. 

        The base address for control of the card is >1E00 

        Turn on the card with bit '0'  while R12 is holding >1E00 

       

    2.  Once the card is on, the memory addresses starting at >4000 are a series of "registers" that control where each 4K "page" of SAMS is mapped into CPU RAM. 

         Register 0 at >4000 holds the value when you map SAMS into a CPU memory window at >0000 

                      1 at >4002  for mapping SAMS into RAM >1000 

                      2 at >4004  for mapping SAMS into RAM >2000 

                      3 at >4006  for mapping SAMS into RAM >3000 

                      etc. 

     

    If you only need one window for your software you only need to deal with one of these registers. 

    If you want 8K (2 pages) mapped you use two registers and so on...

     

    3.  What goes into the registers can be thought of like a number from 0 to >FF (for 1Meg cards) were each value is the 4K page that you want to map into the CPU RAM window. 

         (4K x >FF= 1M) 

         You must remember that this value goes in the left side of the 16bit number. 

          So if you want page 9 mapped into memory at >3000 in CPU RAM , you would do:

         

      >0900  ->  >4006   

     

    4. One thing that was not obvious to me was that the default values in the SAMS card setup the SAMS card to be the 1st 64K of RAM for the TI-99.

    This is done by a "SAMSINI" program that simply fills the registers with sequential page numbers.  

    If you remap the memory at >A000,>B000,>C000, and above and you have a program in there it will crash. :) 

     

     

    5. Here is a way to map a SAMS page into CPU RAM >3000, in the smallest amount of code I know of. 

    (translated this without testing but I think it's correct)

    * setup 
          LI R0,9         \ put the sams page we want in R0 
          LI R12,>1E00    \ set SAMS card CRU address 
    
    * map the page      
          SWPB R0         \ get the page no. on the correct side 
          0SBO            \ enable SAMS registers
          MOV R0,@4006    \ put the page number in the register for window >3000 in CPU RAM 
          0SBZ            \ card off

     

    Have fun!

    • Like 2
  17. 7 hours ago, apersson850 said:

    The p-system does some of this improvements by itself, since it pre-scans for relevant interrupts and stores their entry points at boot time.

    When running, it polls the interrupt inputs and then execute the relevant code when it sees them. Still this is integrated with happening at suitable times in the PME's interpretation of p-code, so it will not react as fast as if you have a hardware interrupt allowed to happen between any machine instruction, of course.

     

    I have two cards I designed myself in the expansion box. They both have interrupt capability, so I've tested adding an unknown (to the p-system designers) hardware interrupt, and that can work too.

    In your substantial computer experience Is there any other machine besides TI-99 where the term "polls the interrupts" is used. It's like an oxymoron to me. :)  

    In my little world interrupts are about removing the need to poll.

     

  18. 11 minutes ago, Vorticon said:

    I did read about UNITREAD/UNITWRITE but did not see anything about any "control word"...

    In any case I did manage to get text files transferred using UNITREAD.

     

    Oddly enough however, I noticed that there were 10 bytes of junk added to the end of the file even though the file itself transferred perfectly. Easy enough to edit out but not sure why this is happening. On the PC side I'm using the "Send File" option of TeraTerm which sends a raw file without any communication protocol. I do suspect however that I will have issues with larger files once the RS232 buffer is full since there is no flow control here.

    Things did not go well for binary transfers however. No matter what I tried, I always got garbage bytes from beginning to end. Here's the binary transfer program:

     

    All in all, I think I've already spent an inordinate amount of time experimenting with this, and my conclusion is that raw serial file transfers without protocols is a very dicey and unreliable affair. 

    I have no doubt your conclusion is correct.

    With such a slow machine flow control is critical on the receive side in my experience without resorting to some new tricks for RS232 interrupt handling that were invented by someone who's name escapes me just now. I think I got a copy from @InsaneMultitasker 

     

     

  19. While looking for something else I found this question by @FarmerPotato

     

    "Does anyone know of a FORTH implementation of the TI tagged object file loader?

    I found some old assembly code for a game. It would be nice if there were a way to use the assembled code so far in  FORTH wrappers. 

    And continue to develop in FORTH. Changes to the assembly code would be assembled outside, then imported to the project. Ultimately the whole thing gets BSAVEd and run out of a FORTH prompt." 

     

    Well my latest linker seems more practical and I can save a binary program that also loads LOW ram with the set of files so I think I could get this going.

    Do you still have those files Erik? 

     

    • Like 1
  20. 27 minutes ago, mizapf said:

    The funny thing is that the phlogiston theory (17th-18th century) just postulated something similar for fire, before people learned that fire is an exothermic reaction with oxygen.

     

    They believed that combustible substances were able to absorb phlogiston, and when burning, the phlogiston emerged into the air by the well-known appearance. When you put it in a closed container, the substance stopped burning because the air became saturated with phlogiston.

     

    This is because of those three little words that men find so difficult to say:

     

    "I don't know"

     

    Red Green, Canadian comedian 

     

    :)

     

    • Like 3
    • Thanks 1
×
×
  • Create New...