An Example Program
Listing One shows a simple game written using the Forth compiler. The program is essentially a binary search algorithm and guesses your number. The program itself is unremarkable but demonstrates many of the 1Forth features such as variables (both initialized and uninitialized), the monitor.4th words and basic math.
If you are familiar with Forth, Listing One should look almost normal to you. Only the strings look different. The compiled code (Listing Two) shows many of the optimizations employed.
For example, under the _J1 label is the line where the following Forth code appears:
The resulting assembly language is:
MOV 0x100, FDSTK_PUSH
Note, too, that the _L5 label (which is the "=" definition falls through to _L10, the "not" definition. That's because the equal word is:
: = - not ;
In other word, subtract the two values on the top of the stack and then do a logical not on the result. You can also find a hidden return at the end of iwin (_L12) where a jump to register 60 causes that library routine to return from iwin instead of to iwin.
While I really wanted a C compiler, the Forth compiler is very usable and was much easier to build. While awk is an unusual choice for a serious language translator, the fact that awk and Forth both share the concept of a word made it an obvious choice for this project.
The way strings are handled is, granted, non-standard. But the syntax is highly usable and it doesn't take much to get used to the new format. Sometimes a small concession can pay big dividends in the ease of implementation.
Forth isn't much in vogue these days with its lack of type safety and other modern features (for example, while there are some Forth packages to address object oriented techniques, none of them are widely accepted as a standard). However, for an embedded system Forth brings a lot to the table. Its simplicity allows highly efficient code and its tight integration to assembly (especially in this implementation) makes it a great fit for embedded systems. The fact that the implementation was very simple is an extra bonus.
The compiler itself should be reasonably straightforward to port to other CPUs. There are just a few machine-specific parts to the compiler. Most of the porting would be in the 1forth.lib file.
Although Forth is satisfying to use (and it is particularly satisfying to write programs on a CPU you designed using a compiler, assembler, monitor, and debugger that you created), it isn't the best answer for a CPU like One-Der. As I mentioned earlier, the true value to the One-Der's architecture is its bus-like structure is a natural for reconfigurable computing. Ideally, a compiler would decide the best instruction set for the program it was compiling and emit a CPU definition as well as object code. While I suppose it would be possible for the Forth compiler to note the operations used in a program and select functional units, it seems as though a higher level abstraction would have more opportunity to exploit this. Forth is fairly close to the machine architecture, so what you write is likely to map to the machine's instruction set anyway.
For an example of a C compiler that works with this type of CPU, look at TCE). This project from the Tampere University of Technology in Finland and allows you to graphically build TTA CPUs with multiple bus flows and then compile C code for the new processor. The tool outputs a VHDL CPU description (unlike One-Der, which is written in Verilog).
Even then, to get the maximum benefit out of a compiler-generated CPU, I expect the language will have to be very high level. The compiler can then exploit the description of what you want to do and use its own heuristics to determine how to do it.