Multicore Forth execution with multitasking on the RP2040

travis-bemannTravis Bemann wrote 11/23/2021 at 03:10 • 2 min read • Like

RP2040 (e.g. Raspberry Pi Pico) support in zeptoforth includes symmetric multiprocessing support, such that multicore operation is combined with multitasking, aside from that the RP2040 must be rebooted, programmed, or erased from core 0, and the main task running the REPL is always on core 0. Tasks can be spawned on arbitrary cores, and tasks on different cores can use multitasking constructs to communicate with one another.

Here is the source of a test program for demonstrating multicore execution combined with multitasking on the RP2040, repeated here as well:

continue-module forth

  task import
  led import

  \ LED test loop task
  : led-loop ( ms -- ) begin led-toggle dup ms again ;

  \ Star test loop task
  : star-loop ( ms -- ) begin ." *" dup ms again ;

  \ Second core main task
  : core-1-main ( star-ms led-ms -- )
    1 ['] led-loop 256 128 512 spawn run
    1 ['] star-loop 256 128 512 spawn run
    current-task kill

  \ Initialize the test
  : init-test ( -- )
    1000 500 2 ['] core-1-main 256 128 512 1 spawn-on-core run
    250 ms 750 1 ['] led-loop 256 128 512 spawn run

What this code does is, once compiled to RAM and init-test is invoked, first it spawns a task on core 1 with spawn-on-core with the specified dictionary, data stack, and return stack sizes in bytes, with an execution token for core-1-main, which will be executed as the main task of core 1, and two arguments, 1000 and 500, which will be pushed onto the data stack of the main task of core 1 as well as their count.

The main task of core 1 then spawns two tasks on core 1 which each take 1 argument off its data stack and have the specified stack configuration, which execute led-loop and star-loop, and then terminates itself. led-loop takes a number of milliseconds and toggles the LED at that interval forever, and star-loop does the same except it outputs asterisks to serial IO.

Back in the main task of core 0 from which init-test was invoked, it waits 250 ms and then spawns a task on core 0 which executes led-loop with an argument of 750, to toggle the same LED toggled by led-loop on core 1 but at an interval of 750 ms. After this control is returned to the REPL on core 0.