RXB Posted July 17, 2021 Share Posted July 17, 2021 10 minutes ago, OLD CS1 said: You made the explicit comparison. MINIMEM, EXPMEM1, EXPMEM2, for instance. Then there is RS232, ALPHON, SPEECH, CLOCK, &c., not seven letters but more than three. And how many people use these 7 letter names vs how many use the 3 letter names with number? Do you have a issue with backwards compatibility? Quote Link to comment Share on other sites More sharing options...
+OLD CS1 Posted July 17, 2021 Share Posted July 17, 2021 2 hours ago, RXB said: And how many people use these 7 letter names vs how many use the 3 letter names with number? Do you have a issue with backwards compatibility? Our failure to communicate should not continue to pull this thread further off-topic. 3 Quote Link to comment Share on other sites More sharing options...
+Ksarul Posted July 18, 2021 Share Posted July 18, 2021 8 hours ago, OLD CS1 said: You made the explicit comparison. MINIMEM, EXPMEM1, EXPMEM2, for instance. Then there is RS232, ALPHON, SPEECH, CLOCK, &c., not seven letters but more than three. Don't forget TP, as that one is only two. . .but I definitely like the thought of using STRANGE as the device name pointer, as it is just appropriate, somehow. TI device name lengths have definitely been all over the map. . . 2 2 Quote Link to comment Share on other sites More sharing options...
fe2o3 Posted August 1, 2021 Share Posted August 1, 2021 STRANGE is certainly more than appropriate for the device name. DRSTRNG... because it's all magic! ARMCPU? 2 Quote Link to comment Share on other sites More sharing options...
speccery Posted August 8, 2021 Author Share Posted August 8, 2021 I posted a quick video on Youtube on accelerating BASIC listing with the StrangeCart. This is the result of a bit of work to integrate the StrangeCart into TI BASIC. To say it shortly, it use the processing power of the StrangeCart to speed up the listing of a Basic program. The listing is produced at 14 times of the speed of TI BASIC list command. According to my measurement, during the listing the ARM core is spending 99.7% of its time waiting for the TMS9900 to update the screen. This measurement is a bit inaccurate, since I used a timer interrupt ticking at 10kHz, and at that low frequency it causes aliasing of the measurement given the speed of the ARM. But the point is that it's much faster And with that, I now finally have the first working pipeline to go from TI BASIC to ARM C/C++ (and back) while getting the output on the TI's screen. In this instance the ARM core is not generating TMS9900 machine code on the fly, but rather the machine code is simply part of a modified version of the mini memory cartridge. I had to learn a bit of GPL to get this far. And now, the next step is pretty obvious - get the ARM to run the Basic program I am using the Lasergate TI BASIC game by the user @tibasic as test material. 4 1 Quote Link to comment Share on other sites More sharing options...
HOME AUTOMATION Posted August 8, 2021 Share Posted August 8, 2021 1 Quote Link to comment Share on other sites More sharing options...
speccery Posted August 9, 2021 Author Share Posted August 9, 2021 I've had a bit of good fun working on the Basic interpreter for StrangeCart. My workflow is like this: I am implementing my TI Basic clone as a C++ module. I am developing it on my Mac, and the same module can be compiled and linked into the StrangeCart firmware. This is how I developed the Basic list command presented in the video I linked. The benefit of developing the algorithms on the Mac is that I can use Xcode and all the debugging tools in it. This is much more productive and faster than working in the embedded software world of StrangeCart, without having to flash the MCU all the time. So I am using @tibasic's Lasergate as a test game. I can load the binary into my interpreter both on the StrangeCart and on the Mac. On the StrangeCart this is done with "SAVE STRANGE.LASER" after loading the game from disk. On the Mac I have a wrapper program which loads Lasergate from disk into the interpreter module. On both cases my Basic interpreter is interpreting the binary of produced by the SAVE command, so it is unmodified Basic binary. There is some extra work here, since both the Mac and StrangeCart are little endian machines, while the TMS9900 is big endian, so there is a whole lot of byte swapping going on. Also pointers on the Mac are 64-bit, on the StrangeCart 32-bit and on TI-99/4A 16-bit, so one needs to be careful with these. But with a high level language like C++, you just need to get it right once. I am working on this in an iteratetive manner, basically so that I let the interpreter start running the program. It will then decode the tokens. Since I only have the beginning of a Basic interpreter, the interpreter will almost immediately halt to an error, when it finds code it cannot interpret yet. That way I get constant instant gratification as the interpreter can run Lasergate a bit more each time I add functionality into the interpreter. So currently the interpreter halts when it gets to line 1420. This line has the statement "DIM A$(16)", and it can't handle it yet, since it does not know how allocate an array, nor how to handle strings. But in the few hours I have put into this after gaining the capability to LIST the program, I have added preliminary support for: REM (this is easy ) CALL SCREEN / COLOR / CLEAR FOR .. TO .. STEP and NEXT GOSUB Before getting to line 1420, the game has already for example executed a for loop, and the interpreter is doing it properly. There is quite a bit of underlying code to handle quoted and unquoted string tokens, capture variable names, allocate symbols, search through symbols, store numeric values as floating point entities, find lines by number, implement 10-level stack for nested for-next loops as well as a separate stack for gosub-return (no return yet though). I would say that a portion of the code is of what I call industrial strength, while a perhaps half of it is still a bit hacky since I'm only working with Lasergate as the test program. It is pretty amazing that I have not had to write a proper expression evaluator yet, since so far (at line 1420) the program is only assigning constants or fetching variables. Once I hit the first real expression in the game's code, I will do a quick-and-dirty recursive descent parser for floating point values. Even if I'm doing development on a Mac, I am only using a subset of C++ and for example not doing any dynamic memory allocation or exception handling with C++, but rather using my own small heap (currently set to 512 bytes) where memory allocation occurs. Also on the Mac I am not writing implementations for the aforementioned CALL functions, since they only really make sense when running on the StrangeCart plugged into the TI. Thus once the Mac version can interpret Lasergate, after I recompile the code for the StrangeCart I still need to write the implementations for the TI specific Basic calls. But this is going to be simple, since I am already doing the hard part of evaluating the expressions at that point. Anyway I am quite enjoying this incremental approach, it is very gratifying to be able to (seemingly) correctly handle line after line. I am also discovering that there is a ton of error checking the interpreter needs to be doing all the time... Luckily a lot of that is very simple, and not a big burden for the CPU. I will be very interested in seeing what performance I can reach with the first version. I estimate that I will have around 128K of RAM as working space available for Basic programs once done with this. 5 Quote Link to comment Share on other sites More sharing options...
RXB Posted August 9, 2021 Share Posted August 9, 2021 RXB source for GPL and ROMs have source for how ARRAYS work in XB, but they are exactly the same in TI Basic. The only real difference is TI Basic does not have enough memory for use of 7 Dimensional Arrays. Matter of fact not even 5 Dimensional Arrays would work in TI Basic and still make a TI Basic program fit into the 12K of VDP. RXB 202E.zip 1 Quote Link to comment Share on other sites More sharing options...
speccery Posted August 10, 2021 Author Share Posted August 10, 2021 7 hours ago, RXB said: RXB source for GPL and ROMs have source for how ARRAYS work in XB, but they are exactly the same in TI Basic. The only real difference is TI Basic does not have enough memory for use of 7 Dimensional Arrays. Matter of fact not even 5 Dimensional Arrays would work in TI Basic and still make a TI Basic program fit into the 12K of VDP. RXB 202E.zip 14.75 MB · 2 downloads Thanks @RXB I will probably use this as reference material. I'm currently just trying to do regular TI Basic, not extended Basic, at least yet. I want to see how far I get with TI Basic first. I am trying to keep StrangeCart a fun project, and building the Basic interpreter is certainly a fun part. I spent a lot of time working with the low level software of the microcontroller - that has nothing to do with the TI and it is interesting in its own way, but when something is not working it's pretty labour intensive to find out what's wrong. A quick question: where does extended Basic store the line number table? With TI Basic it's "simple" (and slow), since everything is in VDP space. But extended Basic can use memory expansion, and also work without it... I assume the line number table is still in VDP memory, even if the code is in processor memory, but I might be wrong. My C++ implementation is greatly simplified in that I only have one memory address space to work with 1 Quote Link to comment Share on other sites More sharing options...
RXB Posted August 10, 2021 Share Posted August 10, 2021 11 hours ago, speccery said: Thanks @RXB I will probably use this as reference material. I'm currently just trying to do regular TI Basic, not extended Basic, at least yet. I want to see how far I get with TI Basic first. I am trying to keep StrangeCart a fun project, and building the Basic interpreter is certainly a fun part. I spent a lot of time working with the low level software of the microcontroller - that has nothing to do with the TI and it is interesting in its own way, but when something is not working it's pretty labour intensive to find out what's wrong. A quick question: where does extended Basic store the line number table? With TI Basic it's "simple" (and slow), since everything is in VDP space. But extended Basic can use memory expansion, and also work without it... I assume the line number table is still in VDP memory, even if the code is in processor memory, but I might be wrong. My C++ implementation is greatly simplified in that I only have one memory address space to work with XB works exactly like TI BASIC but if you have a 32K it moves the line number table from VDP to upper 24K. Look in GPL Source SRXB4 for OLDZ5 this is where the table is moved from VDP to RAM. Also you will see RXB unlike normal XB the location CPUBAS is changed so you can modify the location of XB programs reside using my CALL PRAM command that lets you pick where XB programs reside in RAM. This even allows multiple XB programs in memory as to run one just pick the locations to run. You can run 20 small XB programs all from 32K RAM as all are loaded. XB programs as small as single lines of XB Programs. Anyway hopes this helps. 2 Quote Link to comment Share on other sites More sharing options...
speccery Posted August 10, 2021 Author Share Posted August 10, 2021 1 hour ago, RXB said: XB works exactly like TI BASIC but if you have a 32K it moves the line number table from VDP to upper 24K. Look in GPL Source SRXB4 for OLDZ5 this is where the table is moved from VDP to RAM. Also you will see RXB unlike normal XB the location CPUBAS is changed so you can modify the location of XB programs reside using my CALL PRAM command that lets you pick where XB programs reside in RAM. This even allows multiple XB programs in memory as to run one just pick the locations to run. You can run 20 small XB programs all from 32K RAM as all are loaded. XB programs as small as single lines of XB Programs. Anyway hopes this helps. Thank you for the quick response and the pointer - I found the code you mentioned. Interesting that XB has quite a bit flexibility - having 32K seems to enable a fair amount of alternate code paths. I think it is helpful. The feature of being able to select the XB program location is interesting, and gives a lot of flexibility. If you change CPUBAS, I guess the user must know what he/she is doing, as it probably would be easy to overwrite other programs unless you're careful - I assume there can't be too much protection in place. Quote Link to comment Share on other sites More sharing options...
RXB Posted August 10, 2021 Share Posted August 10, 2021 2 hours ago, speccery said: Thank you for the quick response and the pointer - I found the code you mentioned. Interesting that XB has quite a bit flexibility - having 32K seems to enable a fair amount of alternate code paths. I think it is helpful. The feature of being able to select the XB program location is interesting, and gives a lot of flexibility. If you change CPUBAS, I guess the user must know what he/she is doing, as it probably would be easy to overwrite other programs unless you're careful - I assume there can't be too much protection in place. Yea I have to do a few demos to show it working with multiple small XB programs: Rich Gilbertson - YouTube 3 Quote Link to comment Share on other sites More sharing options...
speccery Posted August 16, 2021 Author Share Posted August 16, 2021 (edited) My implementation of TI BASIC clone continues. I've added some static code analysis to my interpreter, giving me this output: Spoiler All call destinations: SOUND : 5 HCHAR : 7 VCHAR : 3 KEY : 2 CHAR : 4 COLOR : 7 SCREEN : 2 CLEAR : 8 Used tokens: 0x81 used 7 times ELSE done 0x84 used 17 times IF done 0x86 used 8 times GOTO done 0x87 used 2 times GOSUB done 0x88 used 2 times RETURN done 0x8A used 2 times DIM done 0x8B used 2 times END not implemented 0x8C used 8 times FOR done 0x92 used 2 times INPUT done 0x95 used 2 times RANDOMIZE done 0x96 used 8 times NEXT done 0x9A used 19 times REM done 0x9C used 29 times PRINT done 0x9D used 39 times CALL done 0xB0 used 17 times THEN done 0xB1 used 8 times TO done 0xB2 used 4 times STEP done 0xB3 used 74 times , done 0xB4 used 8 times ; done 0xB5 used 40 times : done 0xB6 used 72 times ) done 0xB7 used 72 times ( done 0xBE used 72 times = done 0xBF used 7 times < done 0xC0 used 7 times > done 0xC1 used 46 times + done 0xC2 used 33 times - done 0xC3 used 21 times * done 0xC4 used 2 times / done 0xC7 used 50 times quoted string done 0xC8 used 199 times unq string done 0xC9 used 30 times line num done 0xCB used 3 times ABS not implemented 0xCF used 7 times INT done 0xD7 used 3 times RND done 0xDC used 3 times ASC not implemented In the "call destinations" above I am calculating a histogram of the number of calls to different subprograms. That, and the used tokens table with appearance counts, is a sort of static analysis of the @tibasic's program LASERGATE. The done / not implemented is a listing of all tokens I am already supporting vs. the ones I am not support yet. This represents the breadth of my Basic implementation, since I have implemented TI BASIC in "lightweight" c++ code as required by LASERGATE to run. The tokens I have not implemented yet are on code paths the game does not reach yet while running under my interpreter. The reason why it doesn't get there is that my implementation (under Mac OS with Xcode) implements CALL KEY(..) subprogram so that a button is never pressed, and the code thus cannot get everywhere since user input is not recognised. I'm also currently issuing a warning when a variable is used before it is initialised (this happens with the variable X2 on line 530) - the variable is created at that moment and assigned to zero. I believe I have implemented now a full-blown expression evaluator for numeric expressions. It is only lacking some functions (such as ABS listed in the table above) but those should all be trivial to implement. For string expressions the expression evaluator is not there: the basic support strings and assigns them to variables (including arrays), but since LASERGATE does not do string manipulation that is not supported yet. Of course values form string variables can also be fetched. I have setup two separate memory pools (heaps): one for symbols and another one for strings. I'm currently keeping their sizes small, to see that the system functions when memory is very scarce. The symbol pool is 768 bytes and string pool 1024 bytes for LASERGATE to run. The string pool works pretty much the same was as in the original TI Basic as far as I know:all strings encountered are stored there and the string entries contain pointers to symbol table for strings associated with variables. The string pool also contains temporary strings (such as ones generated with PRINT "HELLO") which are not associated with a variable. The string pool supports compacting (garbage collection) when string space is exhausting. It's been kind of fun to see how the string heap fills up while debugging the code. Since I am developing in Mac OS, the pointers to symbols are 64-bit entities and thus consume 8 bytes. In my system a 1-byte string consumes in the string pool the following memory: - symbol pointer (8 bytes), zero for temporary strings - string length (1 byte) - the actual payload, for a 1-byte length string this is one byte - a terminating zero (1 byte) to keep the strings compatible with C library functions All of that is 11 bytes. Now, since on the ARM pointers are 32-bits and must be naturally aligned (i.e. 32 bit quantities need to be aligned on 32-bit boundaries in memory, similar to TMS9900 which requires 16-bit entities at 16-bit aligned addresses (even addresses)) I am aligning all entities with pointer sized alignment. This is done even on the Mac OS where alignment is not needed since the CPU can fetch unaligned entities, and thus for Mac OS the entries must be 8 byte alignment. And with that, the 11 bytes becomes 16 bytes after padding. On the ARM this would be 8 bytes, and on the TMS9900 (if this basic was ported to it) 6 bytes. Thus with my 1024 byte string pool not too many strings can be stored Of course I could make the string pool for example 8 gigs on the Mac, but that would not really expose bugs with garbage collection... It's been a fun project so far and soon at a point I will port the code back to StrangeCart to get TI Basic a well deserved speed boost. Edited August 16, 2021 by speccery 9 Quote Link to comment Share on other sites More sharing options...
speccery Posted August 31, 2021 Author Share Posted August 31, 2021 (edited) I've now gotten to a point where I've been able to run LASERGATE on the StrangeCart for the first time. I think it is supporting enough of TI Basic to run it correctly, although without sound (CALL SOUND is implemented but does not propagate yet to sound chip). I have now implemented all TI Basic CALLs so that they actually show display output and capture key presses on the real iron. Also PRINT and INPUT statements work with some limitations. CALL GCHAR is still missing but is trivial to add. I've been also testing with some other programs - such as SKI99 - but found bugs in my Basic implementation and some unimplemented features, which will be simple to add. In order to be able to play LASERGATE I had to add a dummy for loop to slow down the gameplay to somewhat manageable levels. I'm pleased to say that the amount of loop iterations is currently at 50 000 to slow down the main loop to reasonable speeds. Basically at line 1170 of LASERGATE there is normally a CALL CLEAR to prepare for next game loop iterations. I did this change to add the delay loop before CALL CLEAR: 1170 FOR I=0 TO 50000 1172 NEXT I 1176 CALL CLEAR And voila, now the game is playable and I dare say more enjoyable than with normal TI Basic, since the delay before CALL CLEAR causes the graphics to be visible for a bit before wiping the screen. I also ran the the speed test which was presented in Noel's Retro Lab Youtube channel (and I don't right now remember his AA handle). On the real iron it takes 78 seconds. Well, just save it to the StrangeCart with SAVE STRANGE.S, and issue CALL RUN(0) to have it executed by the StrangeCart. And the runtime just became a bit shorter - just less than 0.25s Bear in mind that this is still an interpreted Basic, nothing is compiled or preprocessed. Everything is calculated in floating point. I am having a hard time from keeping myself from going into full code optimisation mode before the whole Basic is implemented... Even in the current unoptimised state the FOR..NEXT loops in interpreted Basic run faster than what the TMS9900 can do in machine code with 16-bit integers, while the StrangeCart is doing floating point loop variable, step and limit... I need to make a video of this, it is pretty fast even if I say so myself. Edited August 31, 2021 by speccery 11 Quote Link to comment Share on other sites More sharing options...
+dhe Posted September 1, 2021 Share Posted September 1, 2021 Any chance of getting some boards out to the community soon? Quote Link to comment Share on other sites More sharing options...
speccery Posted September 1, 2021 Author Share Posted September 1, 2021 25 minutes ago, dhe said: Any chance of getting some boards out to the community soon? Yes I think I have gained now enough confidence that the board works, at least on my specific computers. There's of course still work with the firmware, but that will remain the case for a while. I will start building them gradually and then sending the first ones out for further testing with the community, including you 3 Quote Link to comment Share on other sites More sharing options...
+TheBF Posted September 2, 2021 Share Posted September 2, 2021 On 8/31/2021 at 3:42 PM, speccery said: I've now gotten to a point where I've been able to run LASERGATE on the StrangeCart for the first time. I think it is supporting enough of TI Basic to run it correctly, although without sound (CALL SOUND is implemented but does not propagate yet to sound chip). I have now implemented all TI Basic CALLs so that they actually show display output and capture key presses on the real iron. Also PRINT and INPUT statements work with some limitations. CALL GCHAR is still missing but is trivial to add. I've been also testing with some other programs - such as SKI99 - but found bugs in my Basic implementation and some unimplemented features, which will be simple to add. In order to be able to play LASERGATE I had to add a dummy for loop to slow down the gameplay to somewhat manageable levels. I'm pleased to say that the amount of loop iterations is currently at 50 000 to slow down the main loop to reasonable speeds. Basically at line 1170 of LASERGATE there is normally a CALL CLEAR to prepare for next game loop iterations. I did this change to add the delay loop before CALL CLEAR: 1170 FOR I=0 TO 50000 1172 NEXT I 1176 CALL CLEAR And voila, now the game is playable and I dare say more enjoyable than with normal TI Basic, since the delay before CALL CLEAR causes the graphics to be visible for a bit before wiping the screen. I also ran the the speed test which was presented in Noel's Retro Lab Youtube channel (and I don't right now remember his AA handle). On the real iron it takes 78 seconds. Well, just save it to the StrangeCart with SAVE STRANGE.S, and issue CALL RUN(0) to have it executed by the StrangeCart. And the runtime just became a bit shorter - just less than 0.25s Bear in mind that this is still an interpreted Basic, nothing is compiled or preprocessed. Everything is calculated in floating point. I am having a hard time from keeping myself from going into full code optimisation mode before the whole Basic is implemented... Even in the current unoptimised state the FOR..NEXT loops in interpreted Basic run faster than what the TMS9900 can do in machine code with 16-bit integers, while the StrangeCart is doing floating point loop variable, step and limit... I need to make a video of this, it is pretty fast even if I say so myself. This is extremely cool to me. Did you write the BASIC interpreter from scratch or did you start with something like Chipmunk BASIC for a template? 3 Quote Link to comment Share on other sites More sharing options...
speccery Posted September 2, 2021 Author Share Posted September 2, 2021 5 hours ago, TheBF said: This is extremely cool to me. Did you write the BASIC interpreter from scratch or did you start with something like Chipmunk BASIC for a template? I wrote it from scratch, that's much more interesting to me ... and all bugs are on me... 8 1 Quote Link to comment Share on other sites More sharing options...
James Wilson Posted September 7, 2021 Share Posted September 7, 2021 would it be possible to add a usb keyboard interface on to this cart? It may make it easier to get keyboard input fast enough to play games etc. Quote Link to comment Share on other sites More sharing options...
speccery Posted September 7, 2021 Author Share Posted September 7, 2021 9 hours ago, James Wilson said: would it be possible to add a usb keyboard interface on to this cart? It may make it easier to get keyboard input fast enough to play games etc. That's an interesting idea, but I'm not planning to make major changes to the present version of the board. The LPC54114 MCU I am using does not have USB host capability (it does have USB Device capability which I'm using a VCOM serial port), so adding a USB host interface would require an additional chip. The other issue is that even if it had USB host, it would not be able to inject the keyboard data in a standard way, since that's handled by the TMS9901 chip on the motherboard. The CRU bus used for communicating with the TMS9901 is available on the cartridge slot, so forcibly overriding the data might be possible, but not good practice and might damage the TMS9901. The strangecart uses the TMS9900 code for most I/O, so the normal keyboard will work, with the usual performance There is a USB keyboard adapter design by @Tursi , have you looked at it? It's using a USB host chip (on a breakout board) and connects to the standard keyboard connector as I recall. I actually did order that board, but haven't had time to play with it. 2 Quote Link to comment Share on other sites More sharing options...
+OLD CS1 Posted September 7, 2021 Share Posted September 7, 2021 2 hours ago, speccery said: The CRU bus used for communicating with the TMS9901 is available on the cartridge slot, so forcibly overriding the data might be possible, but not good practice and might damage the TMS9901. Also, this bus is not available to the QI's GROM port. 2 Quote Link to comment Share on other sites More sharing options...
Tursi Posted September 8, 2021 Share Posted September 8, 2021 14 hours ago, speccery said: There is a USB keyboard adapter design by @Tursi , have you looked at it? It's using a USB host chip (on a breakout board) and connects to the standard keyboard connector as I recall. I actually did order that board, but haven't had time to play with it. No, my board only does PS/2, uses an AVR, and has a dedicated PCB. 2 Quote Link to comment Share on other sites More sharing options...
+jedimatt42 Posted September 8, 2021 Share Posted September 8, 2021 Looks like one of my hosting sites in down but the resources for the USB keyboard are here: https://www.jedimatt42.com/ti99usbkeys.html and here: https://github.com/jedimatt42/TI-99-usb-keys Quote Link to comment Share on other sites More sharing options...
speccery Posted September 8, 2021 Author Share Posted September 8, 2021 (edited) 4 hours ago, Tursi said: No, my board only does PS/2, uses an AVR, and has a dedicated PCB. Sorry my bad, wrong on all accounts - I was thinking the @jedimatt42 board and thought it was done by you. Edited September 8, 2021 by speccery 2 Quote Link to comment Share on other sites More sharing options...
speccery Posted September 8, 2021 Author Share Posted September 8, 2021 2 hours ago, jedimatt42 said: Looks like one of my hosting sites in down but the resources for the USB keyboard are here: https://www.jedimatt42.com/ti99usbkeys.html and here: https://github.com/jedimatt42/TI-99-usb-keys Thanks for posting the links - and sorry for misremembering who did the project... Nice project, all credits to you I actually have in my drawer two of these USB host boards waiting to go into a TI. I don't have a spare Teensy lying a round, but I have a ton of other microcontroller boards which would work for this purpose. Including rewiring one for the first strangeCart prototypes for this purpose to replace the Teensy. 2 Quote Link to comment Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.