P2 Taqoz 2.8: Classic Cooperative Multitasking
So, this was something I wanted to do for long time: Classic cooperative multitasking for Taqoz.
I do think, that multitasking can be handy to split a bigger project into smaller slices. And this sometimes helps to get it done.
What is Classic Cooperative Multitasking?
When a task comes to the word "pause", this task is suspended and the next task in a round robin list is executed. "pause" just swappes out the relevant data and the instruction pointer to a task-private area and swappes in the data and instruction pointer of this next task. This next task restarts just after it's last own "pause". So tasks have to be fair and have to have enough pause statements, that multitasking happens often enough. In old times several users could use the same minicomputer this way.
There is some advantage of cooperative multitasking against preemptive multitasking: Each task can do the pause at some convenient point, which is uncritical for shared ressources. There are no interrupts between pauses.
Application for P2 Taqoz:
At P2 Taqoz has the stacks sitting in Lut Ram to reduce (relatively slow) Hub accesses. Additionally Taqoz uses some more stacks as usual and has some elements of stacks in Cog Ram for fast handling. So while some other Forths can switch tasks very fast, we have to move a lot of data here. The complete Lut Ram has to be swapped out and in together with some Cog registers. I had been wondering for a long time, how to do the task switching, until I read Matthias Kochs's article in https://wiki.forth-ev.de/lib/exe/fetch.php/vd-archiv:4d2021-01.pdf page 24. There he describes the same problem for his Mecrisp Forth.
So we use "brute force" of block copies which result in a task-switch time of about 0.3ms for P2@200MHz. So this is certainly way too slow for fast controls but it is on the other hand no problem at all for many other tasks. So this is only intended for the main console Cog, while other Cogs can be used for the fast controls.
When swapping tasks, we do only swap some cog registers, for example we do not swap the serial receive buffer registers. This enables, that serial RX interrupt can even be handled, while swapping tasks. To achieve this, the usage of the individual cog registers have to be known. **So this will only work with the version _BOOT_P2.BIX in Taqoz.zip in https://sourceforge.net/projects/tachyon-forth/files/TAQOZ/binaries/ . ** In this zip there is a listing file taqoz.lst, which gives the relevant information. Additionally some parts of my auto-load file AutoN.fth are used.
At the end of coop_E.fth you can find some tests as examples.
0 value cnt# taskLen longs bgTask : bgCount bgTask dup registerTask exitTask swapTasks begin 1 +to cnt# pause again ;
This task can be started by typing "bgCount".
bgTask dup registerTask exitTask swapTasks
These two lines make sure, that this task is taken into the round-robin list and that we come back to the console task after the second line.
' pollPause +poll will include the cooperative multitasking into the polls, which are executed during wait for keys. With this mechanism the background tasks are handled while you are free to use the console.
.tasks will print a list of tasks.
2 killTask will kill task number 2.
singletask will stop multitasking.
multitask will restart multitasking.
Task switching is certainly not optimised here, first priority was to get it going. I am looking forward for good ideas. :-) Unfortunately streamer and rep are not possible while hubexec. Perhaps use cogmod?
Other ideas, comments?
Many thanks to Peter for Taqoz and also for lots of help here in this forum!!!!