PropellerForth - announcement and multitasking tutorial (192 simultaneous tasks
Cliff L. Biffle
Posts: 206
There's been a discussion thread on PropellerForth for some time, but this is a bit of a milestone, so I'm starting a new one.
The PropellerForth website is up at www.cliff.biffle.org/software/propeller/forth/, and the multitasking code is now a standard part of the distribution (which you can download there).
Documentation will be coming soon (along with some other niceties, like non-sucky serial I/O) -- but since y'all are my favorites, here's a quick overview of the multitasking system. This information is current as of the 20061112 release, and includes code snippets you can copy-and-paste to play along.
This is the same system that (in the benchmarks I posted to the other thread) supported 256 independent tasks on a single Cog -- but it's become more powerful, more flexible, and easier to use.
The Tasker
Most new code in this release is in support of the tasker, the Forth component that handles in-Cog multitasking. While there is no standard Forth multitasking API, I've reworked the tasker words to be closer to the API shared by several commercial Forths. Like most of the rest of PropellerForth, the tasker itself is written in Forth, and the user can modify it as she pleases.
Currently, the tasker is an optional component, and is off by default. It must be enabled before executing any of the tasker words, including pause:
At that point, you can check your current task:
The value printed is the ID of your task -- or, more specifically, a pointer to your task's task control block. If you've just fired up PropellerForth and haven't skipped ahead in this tutorial, you're running in the default interactive task, named OPERATOR (that's you!). Try executing operator and printing the result; it should match what you saw from this-task.
There are two types of tasks, named and anonymous. Named tasks are accessible from Forth code in all Cogs by a distinguished name; OPERATOR is the most obvious example, but you might also have DISPLAY-DRIVER or FILESYSTEM-MANAGER. Anonymous tasks, on the other hand, are accessible only through pointers to their task control blocks. We'll play with anonymous tasks in a bit.
Named tasks are created by the word task. It takes as arguments the depths of the data and return stacks, as well as the size of its USER area (task-local variables). Let's create a task with small stacks and the default user area size:
Blinky is a named task; you can get a pointer to its task control block by entering its name.
When tasks are created, they sit dormant and unscheduled. That's sad. Let's give Blinky some code to run.
The word pause transfers control to the next task. (You can try pause right now if you want, but with only one scheduled task it's not very interesting.) So blinky-loop loops forever, alternately toggling the LEDs and yielding control like a good task. (This is an important point to note: the code run in a task must loop forever, until it gets shut down by another task. This may change in a future release.)
We can have Blinky run this code using activate:
If you're on a Demo Board, your LEDs just came on. (If you're on some other board, whatever you've attached to pins 16-23 is now on. Good luck with that.) Try entering pause and pressing return. Each time you do this, it passes control back to Blinky, who toggles the LEDs and passes it back.
Congratulations, you now have the world's most labor-intensive turn signal.
When you're working with the interactive Forth interpreter, Blinky is paused. This is important to keep in mind. The next generation interpreter will pass control to background tasks while awaiting your commands, but I haven't finished this yet.
Now, let's spawn some more tasks. Here's a word, son-of-blinky, that will create an anonymous task to do the same work as Blinky:
You can run this word a few times from the interpreter; each time, it'll create a new anonymous task, which will be triggered (along with the others) when you pause.
If you'd like to automate the process, here's a handy word:
Now you can enter
At each pause, all 192 tasks (plus any others you created by hand) will be invoked one by one. Now imagine them doing actual work.
I'm using this infrastructure in PropellerForth's next-generation serial console driver, and I expect the two to evolve in tandem.
Edit: there was a typo in blinky-hordes. I was tempted to leave it, to see if anyone actually got that far, but I decided to be polite.
Post Edited (Cliff L. Biffle) : 11/13/2006 6:52:51 AM GMT
The PropellerForth website is up at www.cliff.biffle.org/software/propeller/forth/, and the multitasking code is now a standard part of the distribution (which you can download there).
Documentation will be coming soon (along with some other niceties, like non-sucky serial I/O) -- but since y'all are my favorites, here's a quick overview of the multitasking system. This information is current as of the 20061112 release, and includes code snippets you can copy-and-paste to play along.
This is the same system that (in the benchmarks I posted to the other thread) supported 256 independent tasks on a single Cog -- but it's become more powerful, more flexible, and easier to use.
The Tasker
Most new code in this release is in support of the tasker, the Forth component that handles in-Cog multitasking. While there is no standard Forth multitasking API, I've reworked the tasker words to be closer to the API shared by several commercial Forths. Like most of the rest of PropellerForth, the tasker itself is written in Forth, and the user can modify it as she pleases.
Currently, the tasker is an optional component, and is off by default. It must be enabled before executing any of the tasker words, including pause:
init-tasking
At that point, you can check your current task:
this-task .
The value printed is the ID of your task -- or, more specifically, a pointer to your task's task control block. If you've just fired up PropellerForth and haven't skipped ahead in this tutorial, you're running in the default interactive task, named OPERATOR (that's you!). Try executing operator and printing the result; it should match what you saw from this-task.
There are two types of tasks, named and anonymous. Named tasks are accessible from Forth code in all Cogs by a distinguished name; OPERATOR is the most obvious example, but you might also have DISPLAY-DRIVER or FILESYSTEM-MANAGER. Anonymous tasks, on the other hand, are accessible only through pointers to their task control blocks. We'll play with anonymous tasks in a bit.
Named tasks are created by the word task. It takes as arguments the depths of the data and return stacks, as well as the size of its USER area (task-local variables). Let's create a task with small stacks and the default user area size:
8 8 #user task blinky
Blinky is a named task; you can get a pointer to its task control block by entering its name.
When tasks are created, they sit dormant and unscheduled. That's sad. Let's give Blinky some code to run.
: blinky-loop begin 255 ledemit pause 0 ledemit pause again ;
The word pause transfers control to the next task. (You can try pause right now if you want, but with only one scheduled task it's not very interesting.) So blinky-loop loops forever, alternately toggling the LEDs and yielding control like a good task. (This is an important point to note: the code run in a task must loop forever, until it gets shut down by another task. This may change in a future release.)
We can have Blinky run this code using activate:
' blinky-loop blinky activate
If you're on a Demo Board, your LEDs just came on. (If you're on some other board, whatever you've attached to pins 16-23 is now on. Good luck with that.) Try entering pause and pressing return. Each time you do this, it passes control back to Blinky, who toggles the LEDs and passes it back.
Congratulations, you now have the world's most labor-intensive turn signal.
When you're working with the interactive Forth interpreter, Blinky is paused. This is important to keep in mind. The next generation interpreter will pass control to background tasks while awaiting your commands, but I haven't finished this yet.
Now, let's spawn some more tasks. Here's a word, son-of-blinky, that will create an anonymous task to do the same work as Blinky:
: son-of-blinky [noparse][[/noparse]'] blinky-loop 8 8 #user anonymous-task activate ;
You can run this word a few times from the interpreter; each time, it'll create a new anonymous task, which will be triggered (along with the others) when you pause.
If you'd like to automate the process, here's a handy word:
: blinky-hordes ( count -- ) 0 do son-of-blinky loop ;
Now you can enter
192 blinky-hordes
At each pause, all 192 tasks (plus any others you created by hand) will be invoked one by one. Now imagine them doing actual work.
I'm using this infrastructure in PropellerForth's next-generation serial console driver, and I expect the two to evolve in tandem.
Edit: there was a typo in blinky-hordes. I was tempted to leave it, to see if anyone actually got that far, but I decided to be polite.
Post Edited (Cliff L. Biffle) : 11/13/2006 6:52:51 AM GMT
Comments
Very, very cool.
I do believe you have the first self-hosted propeller development system!
I visited the site and I could not download fourth. I would like to download it as it sounds like a nice development system. How do I download from the site?
I did try to download the source, but it wasn't on the Google Code SVN Repository for the project. Maybe Cliff hasn't gotten time to import his code into the repository.
Harrison
(Mostly this is because I'm using a custom build system to generate the image, and I hope to have it cleaned up before I admit to having written it.)
Have a quickie Forth for dummies pointer somewhere? When you get this golden, I want to try it out. Will be fun to actually be writing code on the prop itself.
There's a free web edition -- which, while it acknowledges some inaccuracies, describes a much more current dialect of Forth than the 1981 original. You can find it here:
www.amresearch.com/starting_forth/
PropellerForth is not yet complete, so some of what they describe won't work -- but we'll get there soon.
This will read characters from a keyboard (which must be attached at the demo board pins, 26 and 27) and display info. It's entirely in Forth, and part of it will form PropellerForth's PS/2 driver in the next release.
Load the file into PropellerForth (notes below) and run
When you run it, you'll see:
- the scancode
- the equivalent ASCII character and its hex value
The code understands press and release events, and marks them separately.
I've assigned ASCII values to all the nonprintable characters, following the conventions of the Parallax SPIN Keyboard driver (with one exception -- ESC exists in ASCII at 0x1B, but Parallax assigned it 0xCB). I've also given Break a unique code (0x10000), and the PS/2 demo handles it separately -- try it and see.
The file has DOS line endings, since Unix machines tolerate them and Windows machines require them. HyperTerminal users, use Transfer>Send Text File to send it to PropellerForth. (Users of other terminal emulators, you know what you're doing.)
Edit: Whoops, to use this, you'll need the latest PropellerForth build (to get waitpeq in its current form). It's on the site.
Post Edited (Cliff L. Biffle) : 11/15/2006 4:15:32 AM GMT
I haven't run your Forth system yet, but I just looked at your keyboard code and it looks really to-the-point. That is quite nice!
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Chip Gracey
Parallax, Inc.
Jason
Someone could certainly port the PropellerLoader code, I suppose, but it's not a case I'm personally targetting.
How do you mean?
Thanks
Jason
Thanks.
-Dave
Depends:
- If you're referring to the serial console, the demo board wiring (available in the schematics) should be fine. Any terminal emulator that handles 19200, 8N1 will suffice.
- If you're referring to doing serial I/O on other pins for other purposes, there's no code in PropellerForth to do this yet. You'd need to write your own driver, or what for me to finish mine. (I'm actually working on it right at this moment.)
http://www.parallax.com/dl/docs/prod/prop/PropDemoDschem.pdf
I don't see any obvious serial connections, unless I solder leads onto the prop or the FTDI chip.
Please clarify.
Thanks.
-Dave
·
If you want an actual RS-232 serial port, you'll have to add your own level shifter to the demo board (or whatever board you're using); the demo board gives you a USB connection that acts like a serial port to the host.
If you're not working with the demo board (which I'm beginning to suspect you're not ), the serial console is on pins 31 and 30, and this isn't a Forth-specific question; I don't know the answer, so you'll probably get better results by posting a new top-level question.
Is it possible to get a copy of the binary file for a 6MHz crystal(I have a DLP- Prop unit) or will you be posting the source code soon ?
Regards
Gerry
I hope to have the source up in the next few days. (My day job's been interfering.)
However, propasm (the assembler I'm using) doesn't currently support 6MHz crystals. There's a directive I need to add for the next release.
Assuming you want to run at 96MHz, you should be able to change the first four bytes of the binary from
00 B4 C4 04
to
00 D8 B8 05
All PropellerForth time-related definitions work in terms of this clock freq, so that should take care of it for you.
I'll give that a try
Regards
Gerry
I've opened up a bug against propasm for tracking your issue. If you're curious, you can watch it here:
code.google.com/p/propasm/issues/detail?id=6
I hope to have this licked in the next couple days.
Thanks for the input!
I am using the demo board, and I do understand the concept of the level shifter, etc.
Still, I must be misssing something. Either I solder wires to the TQFP Prop chip and wire up the level shifter, etc.
Or, can Hyperterminal or whatever use a USB port as a regular serial port?
Or, more explicitly, how do you conect your demo board your PC?
Thanks.
-Dave
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Who says you have to have knowledge to use it?
I've killed a fly with my bare mind.
Probably not a good idea!
I tried your suggestion by changing the first 4 bytes but ran into checksum problems.
Fortunately the terminal program I have can handle custom baud rates, so I just multiplied your rate by 1.2 and it worked fine.
Next part is to learn forth it looks interesting.
Thanks again
Regards
Gerry
With the USB cable. There's a USB-serial converter on the Demo Board, so if you plug the USB cable into the Demo Board and your computer, you'll grow a new "serial port."
It's COM3 on my XP install, but your number will vary. I think it announces it in the little I'm-an-excitable-Jack-Russel-terrier popups in the corner.
At that point, you can use HyperTerminal (or better yet, someone please tell me about a good, free terminal emulator for Windows -- HyperTerminal is horrible).
Oh, hey, yeah, forgot to mention -- the current serial console driver is a total hack, with hardcoded bit timings. Good catch.
I'm hacking on the new driver now, which is in Forth and does not suffer from such limitations. (Though it may do funny things if you change the clock frequency while a character is being sent, rather than between characters.)
http://bray.velenje.cx/index.php?page=elec, although I've always downloaded it from Smiley Micros:
http://www.smileymicros.com/download/term20040714.zip?&MMN_position=42:42
Bray's apparently inspired CuteCom, which is cross platform and thus might appeal to you more. I've never used it:
http://cutecom.sourceforge.net/
·
*Peter*
thinking-forth.sourceforge.net/
Chris.
--
http://www.bluishcoder.co.nz