Jump to content

TheBF

+AtariAge Subscriber
  • Posts

    4,469
  • Joined

  • Last visited

Posts posted by TheBF


  1. Let's Make an Assembler
     

    Now that we have a simple number compiler what would it take to make an Assembler for Forth?  For simple instructions that take no arguments (registers or addresses) not very much at all.  The colon compiler in Forth let's us glue things together very easily and gives each routine a name that can be run by giving the name to the Forth interpreter.

    Let's define the 9900 instructions that stand alone.

    : IDLE, ( -- )  0340 , ;  
    : RSET, ( -- )  0360 , ;
    : CKOF, ( -- )  03C0 , ;  
    : CKON, ( -- )  03A0 , ;
    : LREX, ( -- )  03E0 , ;  
    : RTWP, ( -- )  0380 , ;

    Notice that we name each instruction with a comma on the end. This is just to remind us of what these Forth words really do.  They "comma compile" numbers into memory.

    Some 9900 instructions need a single register included in the instruction. For the easy instructions we can simply add the Register number to the instruction!

    : STST, ( Rx --)  02C0 +  , ;  
    : STWP, ( Rx --)  02A0 +  , ;

    Notice we use the Forth data stack to hold the input parameter (the register) and the instruction takes the register value and simply adds it to the instruction and then it compiles the sum with our comma compiler.

     

    Speaking of Registers how would we create "named" registers like using the R option in the TI Assembler.  They are just names for specific numbers so this works.

    DECIMAL 
     0 CONSTANT  R0    
     1 CONSTANT  R1 
     2 CONSTANT  R2    
     3 CONSTANT  R3 
     4 CONSTANT  R4    
     5 CONSTANT  R5 
     6 CONSTANT  R6    
     7 CONSTANT  R7
     8 CONSTANT  R8    
     9 CONSTANT  R9
    10 CONSTANT R10   
    11 CONSTANT R11
    12 CONSTANT R12   
    13 CONSTANT R13
    14 CONSTANT R14   
    15 CONSTANT R15

    You can also find 9900 instructions that take a number or address as a parameter. Since the parameter is a 16 bit value it is not part of the instruction but rather is compiled in memory directly after the instruction. That's easy. Use two commas. One for the instruction and another to compile the parameter from the Forth data stack into the next memory location.  (corrected)

    : LWPI,  ( addr --) 02E0 T,  T, ;
    : LIMI,  ( n --)    0300 T,  T, ;

     

    We can see the convenience of using the reverse notation because we don't have to make a special parser for an assembler syntax. We just use Forth's existing systems.


    * About this time the mystique of what an Assembler program does begins to melt away. (but the big programs do more than just this)

     

    There are some 9900 instructions that can take an address or a register as a parameter. That means we need to add some decision making to our assembler.  

    Here is a routine that can decide if the parameter is a address or not.

    : ADDRESS? ( n -- ?) DUP 1F > SWAP 30 < AND ;

    Given a number n it returns a true flag if n is an address or a false flag if n is a register.

     

    Here is a Forth word that uses the address detector and compiles the correct code for either type of input.

    It's not important to understand all the details of this code. This is more about seeing how it's done.

    : REG|ADDR,  ( arg -- )  \ register or address compiler           
    	OVER ADDRESS?        \ address or register?           
    	IF   +  ,  ,         \ compile instruction & address           
    	ELSE +  ,            \ compile register           
    	THEN ;

    Using REG|ADDR, we can define a bunch more instructions

    : B,      0440 REG|ADDR, ;    
    : BL,     0680 REG|ADDR, ;
    : BLWP,   0400 REG|ADDR, ;    
    : CLR,    04C0 REG|ADDR, ;
    : SETO,   0700 REG|ADDR, ;    
    : INV,    0540 REG|ADDR, ;
    : NEG,    0500 REG|ADDR, ;    
    : ABS,    0740 REG|ADDR, ;
    : SWPB,   06C0 REG|ADDR, ;    
    : INC,    0580 REG|ADDR, ;
    : INCT,   05C0 REG|ADDR, ;    
    : DEC,    0600 REG|ADDR, ;
    : DECT,   0640 REG|ADDR, ;    
    : X,      0480 REG|ADDR, ;

    This exercise continues for the rest of the instructions but we won't show them all here. Some require more complicated logic and computation to embed the correct bits into the instructions but the process is the same. It takes a bit of fiddling but normal humans can build their own assembler this way. I have read that some CPUs do make it much more difficult than others to make nice syntax without a lot of nasty extra "add-ons" in the Forth Assembler syntax. The 9900 is not one of those CPUs.

     

    The full source code for a Forth assembler is available in all the TI-99 Forth systems. Many are based on the original TI-FORTH Assembler. :) 

    If you dare to study them be aware that they use some "black magic" Forth stuff (CREATE DOES>)  to save space and reduce typing as well as some fancy compiler extensions to create structured branching and looping. (which is pretty cool) All questions are welcome. Don't hesitate to ask.

     

    Next Up

    In a Forth system, when we use an Assembler of this style, the code and the names of the routines, constants and variables all exist in the Forth dictionary together.  

    This is fine if we don't mind the entire Forth system travelling along with our application. In the next writeup we will look at what it takes to turn this assembler into a cross-assembler that keeps the names of routines and variables inside Forth but writes the code and text into a different part of memory so we can save it as an executable program.


     

     

     

     


     

    • Like 2
  2. The Simplest Compiler

     

    In the spirit of the tutorial topic, I thought I would share something that I actually missed in its importance back when I was trying to learn Forth. That thing is what Forth calls a compiler.

    To most other people a compiler is a complicated piece of software and to be fair the Forth compiler "program" is also a little daunting to swallow in one bite. However at the bottom of the pyramid is something very simple.  We will build up this simple thing from its roots and later explain how to use the same concept to make stand-alone programs in Forth.

    For review let's start with a block of memory. The memory is a bunch of "locations"  for numbers and each location has an address a bit like the homes we live in. The Forth "compiler" when given a number, puts the number in an empty memory location and informs the system that the memory location is used. That's it.

    Here is how it works:

    Forth's memory is called the dictionary.  There is a variable that keeps track of what memory is used and what memory is free. The variable is called the "dictionary pointer" customarily called DP for short. 

    VARIABLE DP

    When you start a Forth system DP contains the address of the next available memory location in the dictionary. Any memory lower than the value in DP is considered in use.

    If we wanted to move DP we need to increase its value by some amount. 
    How about this?

    : ALLOT     ( n --)    DP +!  ;  ( this will add n to the value in DP)

    When you need to know where the free memory starts Forth says it's right HERE.  :) 

    : HERE  ( -- addr)     DP @ ;   ( fetch the memory location in DP )

    With this little tool kit we can make an integer compiler just this easy.

    : ,         ( n --)    HERE !   2 ALLOT ;

    Notice that the name of the Forth integer compiler is called "comma".

    Let's review how it works:

    • 1234          consider a number on the data stack
    • HERE !       stores the number from the stack at the address "HERE" (ie: the address in variable DP)
    • 2               goes on the data stack
    • ALLOT       moves the value in DP ahead by 2 (the number of the stack)
    • DP            now contains the address of a free memory location. 

     

    What good could that possibly be you might ask?
    Well computer programs are just numbers stored in memory. 
    With our little compiler we could make a TMS9900 program like this:

    HERE  0580 ,  10FE ,

    We used HERE to put the DP memory location on the DATA stack so we remember where our program begins. 
    We then compiled the numeric instruction:  INC R0
    Last we compile the instruction JMP $-1 (ie: jump back 1 memory cell)

    If we had a way to "branch" to that address on the Forth stack our little program would take off and never come back, looping forever.

     

    I hear you asking what if we had to compile a single byte into memory?
    Simple.

    : C,        ( c --)    HERE C!  1 ALLOT ; ( Forth's "char" compiler)

    It works the same as "comma" but only stores 1 byte with "c store" (C!) and bumps the value of DP by 1.

    Its now easy to see these simple operators, comma and c-comma, are the basis of making a Forth Assembler.

    Some CPUs make it difficult but it is possible to understand the Forth Assembler for the 9900 without much trouble.

    We look at that in the next installment and then make an assembler to make stand alone E/A 5 programs.  

     

     

     

     

     

      

     

    • Like 1
  3. Since I now have the tools to test on "real iron" I put this to the test.

     

    The video shows that using LSHIFT with 2 parameters doesn't give us any benefit this partially because the Forth interpreter is 3 extra instructions so we loose time with each parameter.

    Also LSHIFT on the 9900 needed some support code to make it compliant with the standard for LSHIFT.  

    I could optimize this a little but it would still be slower than a single shift instruction like 8*.

    CODE: LSHIFT  ( n bits -- n') \ shift left arithmetic
                  TOS R0  MOV,    \ the shift bits MUST be in R0 to do this
                  TOS POP,
                  R0 R0 MOV,
                  NE IF,
                     TOS R0 SLA,
                  ENDIF,
                  NEXT,
                  END-CODE
    
    CODE: 8*      ( n -- nx8)   \ use in graphics & sprite calculations
                  TOS 3 SLA,
                  NEXT,
                  END-CODE

     8* gives a 33% speed up.

     

     

    • Like 3
  4. 21 hours ago, FarmerPotato said:

    How long if you replace 4 * with 2 lshift?

     

    Since this is a tutorial Topic, I will address GDMike's  googly eyed reaction.

     

    The good Farmer is making reference to the definition:

    : []     ( x y addr -- addr' ) + SWAP 4 * + ;

    He is asking  if using 2 LSHIFT ( shift the number 2 bits to the left)  would be faster than using 4 * (multiply by four)

    You might asking how are they the same thing?

     

    This is a function of binary numbers.

    Consider the number 1.

    Let's print it as the 9900 CPU would see it:  0000 0000 0000 0001   (spaces inserted for human CPUs) :)

     

    If we multiply 1 x 4   We would get         :  0000 0000 0000 0100

     

    In Forth if we do "1  2 LSHIFT"  we get    :  0000 0000 0000 0100

     

    The same result!  

    So shifting 2 bits to the left will multiply by 4.  Therefore shifting 1 bit left is a 2* multiplication, 3 bits -> 8* and so on.

     

    This is done in Assembler with the 9900  shift instructions and if you look up the speed of the shift instructions compared to the multiply instruction, shifts are faster.

     

    Standard Forth has the words 2*  (shift left 1 bit)  and 2/  (shift right one bit)  for this very reason. On most CPUs they are faster than multiply and divide.

     

    So in Camel99 Forth I added the words  4*  and 8* in Assembler because these are useful in processing graphics data structures like sprites and characters on the TI-99.

     

    ANS/ISO Forth 94  added the words LSHIFT and RSHIFT so you can do this to any number of bits as you can do in the instruction set of most CPUs, the 9900 included.

     

    Of course the 9900 has more shifts than this in the instruction set and in TI-Forth and FbForth you can see SRC for example. Shift right circular which lets you slide bits to the right and have them wrap around to the other side. Pretty fancy.  

     

    Hope that removes the confusion emoji. :) 

    And apologies if you already knew this.

     

     

     

    • Like 2
  5. Not sure if the audience here is ready for this but I found this a few years ago in some docs for the TI MSP430 CPU.

     

    I looked at this C program and thought how would I do this in Forth?

    This demonstrates why it is not always best to translate directly from one language to another.

     

    (Back then I posted this on comp.lang.forth and asked the experts how they would do it and there were a large number of options that I would never think of.)

     /******************************************************************************
     *
     * Name : 8-bit 2-dim Matrix
     * Purpose : Benchmark copying 8-bit values.
     *
     *****************************************************************************/
     typedef unsigned char UInt8;
     const UInt8 m1[16][4] = {
                                {0x12, 0x56, 0x90, 0x34},
                                {0x78, 0x12, 0x56, 0x90},
                                {0x34, 0x78, 0x12, 0x56},
                                {0x90, 0x34, 0x78, 0x12},
                                {0x12, 0x56, 0x90, 0x34},
                                {0x78, 0x12, 0x56, 0x90},
                                {0x34, 0x78, 0x12, 0x56},
                                {0x90, 0x34, 0x78, 0x12},
                                {0x12, 0x56, 0x90, 0x34},
                                {0x78, 0x12, 0x56, 0x90},
                                {0x34, 0x78, 0x12, 0x56},
                                {0x90, 0x34, 0x78, 0x12},
                                {0x12, 0x56, 0x90, 0x34},
                                {0x78, 0x12, 0x56, 0x90},
                                {0x34, 0x78, 0x12, 0x56},
                                {0x90, 0x34, 0x78, 0x12}
                                                         };
     void  main(void)
     {
          int i,j;
          volatile UInt8 m2[16][4], m3[16][4];
          for(i=0;i<16;i++)
          {
             for(j=0;j<4;j++)
             {
                m2[i][j]=m1[i][j];
                m3[i][j]=m2[i][j];
             }
          }
          return;
     }

    Forth using the same method. It would be possible that a Forth system would have an array library that goes faster than what I did here.

    \ Matrix move demo for Camel99 Forth
    \ Forth Equivalent written in C "style"
    NEEDS BUFFER: FROM DSK1.BUFFER
    NEEDS ELAPSE  FROM DSK1.ELAPSE
    
    CREATE M1   HEX  12 C, 56 C, 90 C, 34  C,
                     78 C, 12 C, 56 C, 90  C,
                     34 C, 78 C, 12 C, 56  C,
                     90 C, 34 C, 78 C, 12  C,
                     12 C, 56 C, 90 C, 34  C,
                     78 C, 12 C, 56 C, 90  C,
                     34 C, 78 C, 12 C, 56  C,
                     90 C, 34 C, 78 C, 12  C,
                     12 C, 56 C, 90 C, 34  C,
                     78 C, 12 C, 56 C, 90  C,
                     34 C, 78 C, 12 C, 56  C,
                     90 C, 34 C, 78 C, 12  C,
                     12 C, 56 C, 90 C, 34  C,
                     78 C, 12 C, 56 C, 90  C,
                     34 C, 78 C, 12 C, 56  C,
                     90 C, 34 C, 78 C, 12  C,
    
    DECIMAL
      4 16 * CONSTANT 4x16
    
      4x16 BUFFER: M2
      4x16 BUFFER: M3
    
    \ ==================================================================
    \ forth needs byte matrix operators but they are simple
    
    : []     ( x y addr -- addr' ) + SWAP 4 * + ;
    : []C@   ( x y addr -- char )  [] C@ ;
    : []C!   ( char x y addr -- )  [] C! ;
    
    : MAIN()
                16 0 DO
                   4 0 DO
                       J I M1 []C@  J I M2 []C!
                       J I M2 []C@  J I M3 []C!
                   LOOP
                LOOP ;
    

    And here is how one could do it in Forth :)

    : FMAIN
                M1 M2 4x16 CMOVE
                M2 M3 4x16 CMOVE ;
                

    MAIN() runs in about 160 milli-seconds

    FMAIN runs in about     4 milli-seconds

     

     

    • Like 1
  6. 6 hours ago, Tursi said:

    (That said, I see you are crediting being forced to do it with forcing discipline in your code. I guess I can appreciate that, but I still think your profs were silly. ;) )

     

    I am with you on this Tursi. I prefer the main be more of a high-level synopsis of the program. Not many lines but enough to describe what the darn thing does.

    I coded Pascal that way as well. The main program was never more than a page but it was not one line.

     

    To your point about why have the extra call, in Forth if we followed the advice of one line in the main program it could look as silly as:

    : MAIN    GO ;

    :)  

    • Like 1
  7. So now that I have created a monster sized editorI am struggling with how to shoe-horn it all into a functional system running on a real TI-99 that leaves more room for building applications.

    I have a solution for DATA in the SAMS card but up to now I have not focused on compiling into SAMS memory.

    I realized today that some of the work I did earlier of compiling tools into LOW RAM and then removing the tools from the dictionary gives me some insights.

     

    I took the time to re-organize that code so it is more generally useful.  The words  TRANSIENT, PERMANENT and ERADICATE give some nice new functionality.

    A typical use would be when you need the Assembler but don't want the Assembler to take up 2.5K of space after it is used to compile your program.

    Here is how the new words let you load the assembler at compile time and then "ERADICATE" it when you are done with it.  The only penalty being that you must compile the assembler at least once.

    In the example below the assembler is put into Low RAM but TRANSIENT takes any address as an argument.  However you must put it somewhere that will not be overwritten! ?

    \ test transient assembler
    NEEDS TRANSIENT  FROM DSK1.TRANSIENT
    
    1E00 MALLOC TRANSIENT  ( transient code will go into the HEAP)
    
    INCLUDE DSK1.ASM9900   ( compile the assembler as normal)
    
    
    PERMANENT              ( Now compile to normal Forth dictionary)
    CODE @ ( addr -- n)
         *TOS TOS MOV,
          NEXT,
    ENDCODE
    
    ERADICATE              ( assembler is gone, but '@' remains)
    

    Here are the definitions that do the job. The concept is generally transportable to the other TI-99 Forth systems but the devil is in the details.

    CR .( Compile Tools in LOW RAM)
    NEEDS MALLOC FROM DSK1.MALLOC
    HEX
    VARIABLE SAVEDP
    VARIABLE KEEP
    
    CR .( Set up low ram compiling ...)
    \ *INSIGHT*
    \ SAVEDP holds the LINK field of the 1st new word we will create in HI RAM
    : TRANSIENT ( addr -- )
               LATEST @ KEEP !
               HERE SAVEDP !     \ save the dictionary pointer.
               DP ! ;            \ Point DP to transient memory
    
    CR .( Restore high ram compiling ...)
    : PERMANENT ( -- )
               HERE H !          \ give back what we didn't use to the HEAP
               SAVEDP @ DP ! ;   \ restore DP back to original address
    
    : ERADICATE ( -- )
              KEEP @ SAVEDP @ !  \ relink the dictionary
              2050 H ! ;         \ init-the heap. (INCLUDE buffer is at >2000)
    

     

    • Like 2
  8. It took quite a while for me to recover from BASIC. 

    I remember wondering "How do I make a loop like with a GOTO that scans for a key?"   ?

     

    Doh!   "KEY" is a loop that waits for a key and gives it to you when one is pressed.

  9. A Little Preview of VI99

     

    It's about 470 lines of Forth at the moment and sucks up 5K of memory. Not very Forthy but I have to make it work first.

    I bought a SAMS card specifically because I wanted to handle larger text files.  I think I will need to create a SAMS CODE segment to allow switching the editor in/out of the system to make a better IDE.

    However even as is there is 8K of Forth memory left for project code plus 4K of HEAP when this big editor is loaded. With Forth running in super cart I will have a whopping 16K of project space. :) 

     

    I am still experimenting with how best way to work with escape characters but it's now starting to feel useable even at 9600 bps, my default speed on Camel99 Forth /TTY.

     

     

     

    • Like 2
  10. 8 hours ago, WhataKowinkydink said:

    Interesting... the command line reminds me a bit of Vim.

    Funny you should mention. I am working on a VI like editor for Camel99 Forth TTY version.

    It's harder than I thought it would be.

    • Like 1
    • Thanks 1
  11. Forth is a very different approach to programming.  If you have any experience with Assembly Language that can help. 

    Forth looks like a high level language from the outside having an interpreter and a compiler but...

     

    Forth is actually the Assembly Language of a computer that uses two stacks instead of registers.  Start there.

    On top of the Forth "virtual" machine instructions like fetch (@) , store (!), DUP, DROP, SWAP etc... there are a bunch of small "programs" which are the rest of the words in the system.

     

    A word like DEPTH that gives you the stack depth is actually a tiny program written in the "instructions" of the stack computer.

     

    You should program Forth by making more tiny programs that let you do the job you want done.

    Each of these tiny programs work together to complete your larger project.

    You use the interpreter to quickly test your tiny programs and use FORGET to remove the incorrect versions. This is the key to using Forth.

     

    We can think of the tiny programs like Lego blocks that fit together.  

    This is challenging at first because you have to make the lego blocks yourself and then assemble those lego blocks to make a program.

    Compare this to BASIC which is more like a Lego set with the blocks pre-made. 

     

    So if you come BASIC where the system is protecting you from mis-steps at every turn, Forth feels like chaos.

    Forth like Assembler lets you shoot yourself in the foot, in the head or anywhere you point the gun. :) 

     

    Not sure if that helps but sometimes getting a fundamental concept of something makes for clearer thinking.

     

    This is a first level understanding of Forth. After you get more familiar with these underlying concepts there is another level.

    (Enhancing/Extending the compiler is possible but not for the novice)

     

    Exercises:

    1. Write a program (a Forth word) that waits for a KEY and prints "TRUE" if a '1' is pressed and "FALSE" if any other key is pressed. Call your program "ONE?"

    2. Write a program that  loops and prints "HELP!" continuosly UNTIL any key is pressed. Call your program "HELP"

    3. Write a program the loops and prints "PRESS Q" continously until "Q" is pressed. Call your program WAITFORQ.

    4. BONUS: Write a program that loops forever waiting for the ascii key you give it as a parameter. 

                    Call the program WAITFOR. Usage:  65 WAITFOR (waits for "A")

     

    Show your work here. :) 

     

     

    • Like 3
  12. 10 hours ago, GDMike said:

    Nope. I'm wondering if I have one of those RTC chips. I'll have to dig around. Now you're supposed to say, "I Know how to make that work in the supercart" 

    Lol. Well it's a great idea. 

    I just ordered a card and an old cartridge this week. I really like running Camel99 Forth with the supercart version on Classic99.

    When it boots and says "24,008 FREE" it makes me happy. :) (we are an easy to please lot aren't we)

     I found 3 of these chips while unpacking some boxes.  They are only 8K bytes but that is all I really want.  We shall see if the batteries are still good.

    I will let you know how it goes. I already have the Forth code to access the clock and calendar.

    • Like 1
  13. 13 minutes ago, GDMike said:

    I think what would help the group is an example of each command. I started doing that then got sidetracked into assembly. But if it doesn't get done by next year I'll try to pull it off.

     

     

    The real challenge for newbies with Forth is there are a lot more words to learn than in other languages. It makes a reference sheet into a multi-page document. This gave rise to the Forth "Glossary" something I have yet to complete for Camel99 Forth.

    • Thanks 1
  14. I am still having trouble managing the escape sequences fired at the editor when using the PC extended keys. (arrows, Pgup etc.) 

    I have decided to make the editor for TTY interface emulate VI. This way the commands and text editing handlers are separated to a greater degree.

    Interestingly I read that some version so VI don't work right with the extended keys either so I don't feel quite so inadequate.

     

    The good news is that I have most of the editor code in good shape so I just have to make the command acceptance part.

    More to come.

    • Like 1
  15. 7 hours ago, GDMike said:

    Just a fyi. I put together a little"Turboforth" manual in word format.

    It's basically the words and definitions categorized from the Tf.net web site. It's available in the file section in ti99er Facebook page.

    But it's great to have it in a booklet when you're looking for a word. 

    Reminds me of those great "cheat sheets" that TI made for BASIC and XBASIC. Mine were well worn. :)

    Come to think of it I had one for ANS Forth made back in the 90s after the standard was published. Wonder where that might be...

    • Haha 1
  16. On 5/11/2020 at 10:03 PM, DavidC said:

    Now this is gonna come off as weird, but ....LOGO is a bit like Forth..define definitions of stuff, what was first?  LOGO or Forth?

    Now everyone knows that God speaks Forth but some people have this view about LOGO

     

    LOGO is the Language Of God, and we are His turtles.
        L: Language
        O: Of
        G: God
        O: Only God knows what the last "O" stands for.

    ?

    • Haha 3
  17. 14 hours ago, apersson850 said:

    You don't. It's normal for Pascal implementations of the time to allow only simple data types for the selection variable. This is because the compiler makes a jump table with the different outcomes, and that becomes too complex if strings can be used for the case variable.

    You also need to be aware of this when you select your constants to compare with in the case statement.

     

    Compare these two case statements.

    
    case a of
       1: bla;
       2: blah;
    end;
    
    case a of
       1: bla;
       20: blah;
    end;

    They will do the same, but the first requires a case jump table using two words or memory. The second will require 20 words of memory, where 18 of the words will just be unused fillers! Thus if you enter the two constants 1 and 20000, you'll get the dreaded ERROR: STACK OVERFLOW*REBOOT

    On the other hand, this overhead makes the case statement very fast.

    The same principle applies if you use char constants, with 'A' and 'B' versus 'A' and 'Z'.

    Now when you know how the compiler implements this statement, it should be obvious why an array can't be used. Neither can real numeric values, but only integers.

     

    This is a classic problem;  conditional branching or computed lookup table for a case statement. 

    ANS Forth took the conditional branch approach for the "standard" which is versatile but slower. In time critical situations most people create a table like Pascal is doing here.  

    Now I want to know how this is done in modern Pascal systems like Delphi or Wirth's later creations, Modula and Oberon. 

    Do you have any insights on this?

    I suppose the compiler carries both methods in its bag of tricks and makes a decision on which one to use.  ?

     

     

  18. 13 minutes ago, GDMike said:

    Just back up your screens, as nothing is worse than losing a formula that wasn't easy to come up with.

    The great thing about today's TI-99 programmer is Classic99's ability to take pasted text.

    You can have great fun just using text files for your programs and pasting them into the emulator at blazing speed.

     

    I am working again here with floppy drives and I wish they had a "Viagra" for their floppy-ness. :)

     

    It is slooooowwww.

     

     

    • Haha 3
  19. 2 minutes ago, DavidC said:

    Now this is gonna come off as weird, but ....LOGO is a bit like Forth..define definitions of stuff, what was first?  LOGO or Forth?

    You are perfectly correct.  TO   in LOGO  is like :  in Forth.

     

    I think Forth was first.  It was one guy who made it for himself in 1969 ish.   and then developed it over the next few years.

    It was a stack of punched cards in the beginning. :) 

     

    https://www.forth.com/resources/forth-programming-language/

     

     

    • Like 1
×
×
  • Create New...