Version 1.1.04B1 of MFORTH, my Forth environment for the M100/M102 laptops, has now been released. Binaries can be found on the MFORTH page.
This version adds a couple of important features, namely an integrated 8085 assembler and the completion of the multitasking system. You can now write M100 programs in both ANS Forth as well as 8085 assembler using MFORTH, although for the most part I would recommend that you use the assembler to access parts of the M100 that MFORTH does not yet expose and/or to accelerate performance-critical portions of your software. Forth is plenty fast for almost anything that you would need to do (most of MFORTH is written in Forth, not assembler).
Here is an example of how to use the assembler, the following code gives you access to the Main ROM’s “PLOT” routine, which draws a pixel at any location on the screen:
code plot ( x y --) saveregs h pop l e mov h pop l d mov 29772 romcall restoreregs next end-code
You can then use “PLOT” just like any other MFORTH word:
120 30 plot 120 31 plot 120 32 plot 120 33 plot
Note that the MFORTH assembler is a traditional, postfix assembler, so the arguments are “reversed” from how they might look in something like TASM. That said, the MFORTH assembler also has all of the power of the Forth environment, so you can easily write loops and if statements without having to deal with labels. Here is an example of a word that converts a lower case string to upper case:
hex code toupper ( c-addr u --) saveregs d pop h pop begin d a mov e ora 0<> while m a mov 60 cpi cc if 20 sui a m mov then d dcx h inx repeat restoreregs next end-code decimal
Here is how to use the new word:
S" Hello World" 2DUP TOUPPER TYPE (outputs HELLO WORLD)
The multitasking system is also a fun new addition and will be featured pretty heavily in some of the additional work that I have planned for MFORTH. In a nutshell, you can create multiple tasks and have them execute alongside each other, even while you are writing more code and interacting with MFORTH. Tasks are very small (256 bytes), so you can fit a lot of them into RAM before you will run into problems. That said, I would be surprised if anyone needed more than a couple of tasks, even for the most complex program. Tasks are created by passing an xt to the TASK word; the task will then run that xt until it returns (which, in most cases, it should never do). Tasks can suspend themselves and give time to the next task by calling PAUSE and should do that fairly often. The primary task (the one that provides the text interpreter) calls PAUSE every time it checks the keyboard queue, for example.
Here is an example of a task that displays a clock in the upper-right corner of the screen. The clock will continue to update, even as you do other things in MFORTH:
: .NN ( u) 0 <# # # #> TYPE ; : .NNNN ( u) 0 <# # # # # #> TYPE ; : .- [CHAR] - EMIT ; : .DATE ( d m y) .NNNN .- .NN .- .NN ; : .: [CHAR] : EMIT ; : .TIME ( s m h) .NN .: .NN .: .NN ; : .TIME&DATE TIME&DATE .DATE SPACE .TIME ; : SEC ( --u) TIME&DATE 2DROP 2DROP DROP ; : NEWSEC? ( u1--u2 f) SEC TUCK <> ; : .CLOCK GET-XY 21 0 AT-XY .TIME&DATE AT-XY ; : CLOCK 0 BEGIN NEWSEC? IF .CLOCK THEN PAUSE AGAIN ;
You start the clock by typing:
' CLOCK TASK
There is no way to stop the clock display other than to exit MFORTH.
That’s the code exactly as I typed it in to my M102, but I would be happy to go into detail as to what each of the words are doing if people are interested.
Enjoy the new version of MFORTH, and please let me know if you have any questions about how to use the new features (or any of the old features).