I finally got around to getting my TI-99 multi-tasker working pretty much the way I wanted.
Traditionally commercial Forth systems were multi-tasking multi-user systems. I am told Forth Inc. could strap 12 terminals to an IBM PC and have good response for the users.
So why is the TMS9900 so cool? because it can create a new set of registers for itself anywhere in memory and change to that set of registers in 1 instruction!
For those who have never thought about it a conventional multi-tasking systems usea a special program called a scheduler that decides which program is going run and how long they get to do something. At some point while program A is running, the schedule program interrupts program A and gives program B a turn and so on with all the programs that are in the "schedule". So with only 1 CPU, it's really an illusion of multiple programs running at the same time.
The Chuck Moore's Forth multi-tasker was built to be very lightweight and has not got a separate program to schedule which task is going to run and when. (It's heresy, I know)
Instead a new task gets a turn EVERY time an input or output occurs. So after outputting a character to the printer another task gets a turn. If that task reads a key stroke, it releases control to the next task and so on...
This works well because most I/O takes tons of time so the CPU might as well go do something else.
So to make this kind of multi-tasker on the TMS9900 you can do a switch from one program to the next program in only four, yes that's right 4 instructions. This is unheard of.
Below is the code for the word YIELD, which changes control to the next task, written in a Forth Assembler language.
I did something with this that might be unique. I use the RTWP, instruction to jump to the next task in a list of tasks.
I can do that because I manually initialize all the registers in each task's workspace as if each task was already called once by BLWP.
It makes the actual switch to a new program 1 instruction.
Then the only thing we do is check a variable that is right after the workspace to see if the task is awake or asleep.
If it's asleep we just jump to the next workspace and so on.
I love this processor!
CODE: YIELD ( -- ) BEGIN, \ CURRENT TASK: RTWP, \ one instruction switches context 14 l: _TSTAT R1 STWP, \ NEXT TASK: store NEW workspace in R1 8 32 (R1) R0 MOV, \ Read local TFLAG to see if I am awake 28 NE UNTIL, \ loop thru tasks until TFLAG is <> 0 10 NEXT, \ if task is awake, run next \ 60 *.333 = 20uS END-CODE
So when all is said and done I have a set of words that lets me create tasks and run them, stop them or assign them new programs almost like Unix system, but much tinier.
Here is the DEMO program that I tested it with. I will get a Video up here shortly and the multi-tasking kernel up on git hub.
This can be ported to FBForth or Turbo Forth with just a little assembler code but mostly high level Forth.
\ CAMEL99 Forth Multi-tasking Demo \ paste into system with mtask99.hsf installed INIT-MULTI CREATE TASK1 USIZE ALLOT CREATE TASK2 USIZE ALLOT CREATE TASK3 USIZE ALLOT TASK1 FORK TASK2 FORK TASK3 FORK DECIMAL VARIABLE SPEED 25 SPEED ! : JOB1 BEGIN 15 3 DO I SCREEN ( change screen color) SPEED @ 5 MAX MS LOOP AGAIN ; : JOB2 BEGIN 90 65 DO 30 1 I 47 VCHAR 25 MS LOOP AGAIN ; VARIABLE X \ run for a period of time then go to sleep : JOB3 X OFF 2000 MS X ON MYSELF SLEEP \ easy to I am all done PAUSE ; ' JOB1 TASK1 ASSIGN ' JOB2 TASK2 ASSIGN ' JOB3 TASK3 ASSIGN
With that code loaded, you type
TASK1 SLEEP etc..
And the Forth console is still alive the whole time...
unless you say MYSELF SLEEP. :-)
Nighty night Forth.