Implementations
Riscy Pygness is a family of Forths. The members are very similar in
terms of both the primitives and the high-level Forth words. The
differences are primarily related to the implementation and the
tradeoffs that result. The first two variants have been implemented
but the second is now preferred and is used in the current version.
All variants have ColorForth and/or cmFORTH
features such as
- "tail call optimization" (i.e. dropping
EXIT when possible by
changing the previous call to a jump).
- capability of having multiple entry points (Forth names) and
multiple exit points for a Forth word.
FOR ... NEXT
- simple recursion (with no "smudging" of word names), e.g. the first
and second versions below are equivalent:
: TEST ( u -) ?DUP IF DUP . 1- TEST ; THEN ;
: TEST ( u -) BEGIN ?DUP WHILE DUP . 1- REPEAT ;
First Version (16-bit tokens, no heads, code only in flash)
- Summary
- Use this version only when maximum compactness is needed.
Otherwise, use the second version (even then, you probably should
develop with the second version and come back to the first version
only at the last minute).
- Threading
- High-level Forth words consist primarily of 16-bit subwords. This
is more or less a direct-threaded Forth but with a "smart" next.
- The 16-bit token begins as a 17-bit address pointing into the 128K
bytes of flash ROM starting at address zero. The address must be
aligned on a 4-byte boundary, thus only 15 bits are needed (i.e. the
17 bits shifted right by two bits). So, those 15 bits representing
the address form the most significant 15 bits of the 16-bit token,
leaving the least significant bit for use as the "Exit Flag" to say
whether this is a call or a jump.
- We need one more bit of information which is whether the word being
called (or jumped to) is a primitive or a high-level word. There is
no room left in the 16-bit token so we determine this based on the
address itself. All the primitives sit at lower addresses than any
of the high-level words. So, if the address is less than the
address that marks the boundary between primitive and high-level
words, then the word must be a primitive; otherwise, it must be a
high-level word.
- Heads
- Heads are stored only on the host, thus taking no space on the
target chip.
- Advantages
- This implementation has the advantage of compactness. All the words
sit in flash, but with subwords taking up only two bytes each, a lot
of Forth code can fit into the Philips LPC2106 chip.
- Disadvantages
- it is difficult to add new definitions on the fly. Actually,
the code is in place to this. If the interpreter running on the
host notices the first character of a line starts with a colon,
rather than sending addresses to the target to execute, it
compiles the whole line and then asks the target to burn that
addition into its flash. However, this burning of the flash is
so slow and the need to make sure the flash has been erased,
etc. makes this so awkward that I personally never do it.
Instead, I alter the source code, recompile (to make a new
target image), and use the bootloader to reburn the whole image
into the target.
- the special host-based interpreter/terminal program is required,
since the heads are stored on the host, not the target. This
means you do not have an interactive Forth with just any old
serial terminal, but must run the special terminal program on
the host.
- Interactivity
- A special interpreter/terminal program running on the host PC
provides the usual interactivity for executing existing words on
the target. This program has access to the table of
names/addresses built at compile time so it can look up the
address each word you type, convert it to the proper format for
a token, and forward that token to the target for execution.
The target runs a simple loop which collects and executes
tokens.
Second Version (16-bit tokens, 32-bit lookup table, code may reside anywhere in either flash or RAM)
- Summary
- Use this version unless extreme compactness is needed. Then,
still use this version for development, finally switching to the
first version at the last minute.
- Threading
- This next variant is similar to the first with regard to 16-bit
tokens and threading. However, the tokens now use 13 bits (the
most significant 13 bits of the token) to hold a token number,
plus 3 bits for flags. Instead of shifting the token to produce
a 17-bit flash address of a Forth word (as is done in the first
version above), the 13-bit token number is used to look up a
full 32-bit address (in either the flash token table or in the
RAM token table).
- Flags
- Bit 0 of the token is the Exit Flag (same as in the first
version),
- Bit 1 indicates whether to use the flash token table or the RAM
token table,
- Bit 2 of the token is the Enter Flag (it indicates whether the
word is a primitive or a high-level Forth word).
- Heads
- Heads are stored only on the host, thus taking no space on the
target chip.
- Advantages
- Because of the 32-bit table, Forth words may reside anywhere, not
merely in the first 128K bytes.
- New Forth words can be defined interactively into RAM (which is
much simpler to do than the first version's approach of extending
the dictionary by reburning flash).
- Allows easier porting to other ARM variants regardless of their
flash/RAM memory maps.
- By keeping a 16-bit token, code size is still quite compact,
allowing a lot of Forth to be crammed into, say, the LPC2106's
120K of available flash.
- Disadvantages
- The token table (the table of 32-bit addresses) takes up space, 4
bytes per Forth word.
- Interactivity
- A special interpreter/terminal program running on the host PC
provides the usual interactivity for executing existing words on
the target. This program has access to the table of
names/addresses built at compile time so it can look up the
address each word you type, convert it to the proper format for
a token, and forward that token to the target for execution.
The target runs a simple loop which collects and executes
tokens.
- New definitions are compiled by the host then sent to the
target's RAM.
- Typical usage
- Interactive poking at your hardware and testing snippets from
the keyboard are perhaps the strogest advantages of Forth for
developing embedded systems. It is so very convenient to do a
little extending of the dictionary while testing interactively,
such as defining a short word to perform a longer sequence of
words, to save typing, to try out ideas quickly, etc. These
definitions go into RAM. We don't need room for very many. We
work a while and then, once the testing for this session is
done, the results are incorporated into the main source code and
a new flash image is generated. So, for any one testing
session, the ability to extend the dictionary is very
convenient.