In the hope to improve my knowledge about Forth, I’ve recognized a special topic which can be called controversial. It is called “Multitasking in Forth”. In Mainstream programming languages and CPUs multitasking is no big thing. CISC CPUs like the Motorola 68000 have such a feature integrated as default, and C compiler and Unix operating systems are supporting the feature. Multitasking is one of such things, which makes sourcecode big, and programming in C so interesting.
But we do not want programming in C. Implementing Multitasking in Forth seems a bit more complicated. What I’ve found so far is the statement, that:
“Multi-tasking needs one stack per task (eh, two in Forth: a data and a return stack)”, https://jeelabs.org/article/1621b/
Which is obvious, because after executing the parallel task the CPU wants to go back to the original task. The problem is, that the educational model of a twostack pushdown automaton has only the standard-stack of datastack and returnstack. That means, the total number is 2 not more.
Let us take a look of how the Forth community is realising multitasking. They have the word PAUSE, which is written in assembly language and ´saves the state of the register. The sourcecode of PAUSE does what somebody expects. It saves the current stack to memory and switches the task. The pause command works only on Forth system which are running on x86 cpus, because such hardware have enough memory to save the stack. But, we don’t want run Forth on CISC CPUs we want a Forth CPU.
How multitasking can be realized there is not clear. As far as i know, the J1 minimal Forth CPU has no memory, it has only the datastack and the return stack. How to realize Multitasking there?
Here is the sourcecode for the PAUSE command in Mecrisp, https://github.com/jeelabs/mecrisp-stellaris/blob/master/common/multitask.txt It seems, that the stacks are saved in a variable in memory.
Let us investigate how variables are used in Forth. Writing to a memory cell is done with: “23 i !”, and reading the i-variable is done with “i @”. What we need to do is to save the stack to a variable: “ i !”. Then we are jumping to the parallel task.
The multitasking feature is usually part of an Real-time operating system. .That means, we need a Forth based RTOS which runs on a stackmachine.
We can now describe how Multitasking looks like in Forth. At first, there is no physical stack but only a section in RAM, which is reserved as stack. 10 tasks who are running in parallel need 10×2 stacks. If a stack is 10 cells deep we need around 200 cells in memory. Which of the stacks is used right now is determined by the stackpointer. A context switch is done with the pause word, which changes the stackpointer to another position.
Can we call this setup a stackmachine anymore? I have doubts. It is a normal CISC based system which is using lots of cache. Implementing this on a typical Forth CPU like the J1 is not possible. Because the J1 only has two physical stacks, but not access to larger amount of RAM for creating virtual stacks.
In reality, most Forth programmer are not using Forth CPUs, instead they have normal CISC CPUs like an Arduino which they are programming with Forth. So they can use either the context switch of that CPU or program their own PAUSE command in Forth. But, this setup won’t work on a J1 CPU, because like i mentioned above taskswitching is equal to use different stacks for each task.
Game-loop based multitasking
A possible alternative to real multitasking is to use a concept which is used in game programming. Usually, there is a main-loop which iterates 30 frames per seconds. To call a function every seconds inside the gameloop an if statement is used: “if (frame%30==0) then subtask. That means, the game loop stops and the subtask is executed. Running this program results into a multitask like workflow. That means, there are running two programs at the same the same time.
The context switch is surprisingly not existing. That means, on top of the old stack new data are stored, because it is equal to call a normal routine.
: sleep ms ;
: main 10 0 do i . 1000 sleep loop ;
The Forth code is a for loop (the game loop) which calls a subroutine sleep. From a certain point of view both routines are working in parallel.