Contents

Introduction

The base pbForth distribution has all the base components to make the target board into a versatile embedded system. Unfortunately there is no monitor task included because every programmer is likely to want something slightly different.

Why would you want a background monitor? It allows your RCX do do useful work while it's sitting idle (which is most of the time). You can scan for button presses, update the display, calibrate light sensors, and many other things while the system is idle. Without a monitor, you are forced to type in every command to the pbForth system, including POWER_OFF!

This series of articles will help explain how to write a background monitor for the RCX in pbForth, and offers examples of some of the unique features of the Forth language.

I'm assuming that you have at least a basic grasp of programming in Forth and are familiar with the concept of pointers or indirection in at least one programming language. You should also know how to upload scripts to the RCX. You might also review pbForth RCX Extension Scripts if you're unfamiliar with pbForth on the RCX.

To get the most up to date version of pbForth firmware and the example scripts, you can get the pbForth Scripts as a zip archive or the pbForth Scripts as a tar.gz archive.

Vectored Execution in Forth

Don't let the name scare you - vectored execution is just a simple way of changing which word will be called at a certain time. This is the key concept that lets us "plug-in" our background monitor to the pbForth system.

The key to understanding how this works is the Forth word ' (pronounced "tick"). When followed by the name of a word in the Forth dictionary, it returns the address of the word ready for use by EXECUTE. As you can imagine, EXECUTE will actually execute - or run - the the code at the address returned by '.

Be careful! If the address at the top of the stack is not a real Forth word, the system will probably hang or crash and you'll need to reload the firmware.

Here's a simple example script you can upload (vectorExecute/vectortest.txt) to get you going:

\ -----------------------------------------------------------------------------
\ vectorTest.txt - illustration of Vectored Execution
\
\ This example is taken from Leo Brodie's "Starting Forth"
\ -----------------------------------------------------------------------------
\ Revision History
\
\ R. Hempel   2002-04-12 - Original
\ -----------------------------------------------------------------------------

: HELLO   ." Hello " ;
: GOODBYE ." Goodbye " ;

0 VALUE 'ALOHA

: ALOHA 'ALOHA EXECUTE ;

' HELLO TO 'ALOHA

ALOHA

' GOODBYE TO 'ALOHA

ALOHA

\ -----------------------------------------------------------------------------

The first time ALOHA is executed, the RCX will print "Hello" to the console, and the second time, the RCX will print "Goodbye". It's pretty easy to see how this concept can be extended to let ALOHA do anything we want, like so:

: GREET ." Dude! You're writing code!" ;

' GREET TO 'ALOHA

ALOHA

This time, when ALOHA is executed, the RCX will print "Dude! You're writing code!". Neat huh?

The 'ALOHA variable stores the address of the word that will be executed when ALOHA gets executed. We call 'ALOHA a vector because it is a pointer to the word that will actually get executed, which is where the term vectored execution comes from.

So far so good, but how does this help with monitoring buttons in the backgound?

The Idle pbForth Background Task

Most computers sit in a loop doing essentially nothing waiting for you to type something on the keyboard or move the mouse. The RCX is no exception. Most of the time it's just sitting around waiting for characters to come in on the IR port.

If you're interested in looking through the pbForth source code you'll see that the definition of KEY in h8300/rcx/pbforth/h8300-primary-rcx.tcl is essentially a tight loop waiting for characters. You'll also notice a short bit of code that looks like this:

'UserIdle EXECUTE

Look familiar? It's the same basic construct as the ALOHA word in the first example. If you're following along to this point, you've already figured out that 'UserIdle is the vector we'll be modifying with the address of our background monitor.

Lets start out with a dead easy background task, one that displays the current value of a low-resolution timer and updates it continuously. Upload the example (vectorExecute/displayTimer.txt) to the RCX:

\ -----------------------------------------------------------------------------
\ displayTimer.txt - display the contents of a low resolution timer
\ -----------------------------------------------------------------------------
\ Revision History
\
\ R. Hempel   2002-04-12 - Original
\ -----------------------------------------------------------------------------

BASE @
HEX

: DISPLAY_TIMER
  0 TIMER_GET
  3002 SWAP 301F LCD_NUMBER
  LCD_REFRESH ;

BASE !

\ -----------------------------------------------------------------------------

After the script is uploaded, you can test it by typing the following:

DEPTH U.
DISPLAY_TIMER
DEPTH U.

This is a helpful trick to make sure that the word you are going to put into the vector works and does not leave garbage on the stack. The DEPTH word pushes the number of cells on the stack to the stack. There should be the same number of cells on the stack before and after DISPLAY_TIMER executes.

Now for the interesting part - we're going to run DISPLAY_TIMER in the background. Here's how:

' DISPLAY_TIMER TO 'UserIdle

You should see the display incrementing fairly quickly. The RCX interrupt service routine increments the timer about ten times a second. If all you see is 9999 then the counter value is too large to display. You can easily set it to another value like this:

100 0 TIMER_SET

This demonstrates that the pbForth interpreter is running even though we have the DISPLAY_TIMER word running all the time. To get back to where we were at the beginning, just restore the NoOp word to the vector, like this:

' NoOp TO 'UserIdle

The counter in the display should stop incrementing. This is the first baby step we'll take in getting a background task to run a monitor for the RCX. For the next step, look at HowTo Make An RCX Monitor - Part 2