EMForth for the SAM7.
I have written a version of forth for the atmel SAM7 ARM based micro-controller.
2007 February 2'nd,

This project is continued at Nerdipedia

I am a design chauvinist. I believe that good design is magical and not to be lightly tinkered with. The difference between a great design and a lousy one is in the meshing of the thousand details that either fit or don't, and the spirit of the passionate intellect that has tied them together, or tried. That's why programming---or buying software---on the basis of "lists of features" is a doomed and misguided effort. The features can be thrown together, as in a garbage can, or carefully laid together and interwoven in elegant unification, as in APL, or the Forth language, or the game of chess.

-- Ted Nelson

What is Forth?
The history of EMForth

EMForth and ARM.

Every processor I've ported forth too has been different from every other. ARM has some unique characteristics I had to work with or around. It is pretty much impossible to foresee all the pit falls so my style is to jump in and see how it goes.

All in all the ARM runs forth fairly well. My high level forth compiles to machine code and my comments may not be relevant to indirect threaded compilers.

One of the difference between the ARM and most processors I've used in the lack of a regular subroutine call instruction. The ARM has several ways to call a subroutine but these don't automatically push a return address onto a return stack. If fact the ARM doesn't have a dedicated return stack. By convention (which I stick to) a return stack is implemented using register R13 but it doesn't have to be done that way.
If you call a subroutine using a “branch and link” instruction the return address appears in the link register which is also R14. It is up to the software to stack this address if appropriate (the lowest level subroutines don't need to). The impact of not automatically stacking the address is that constants, variables and similar objects need and extra instruction compared to “normal” processors. The code part of a constant definition is three words long instead of two. Not a huge deal but we do have a lot of constants.

The ARM is the only CPU I've “forthed” that doesn't have and absolute jump or call instruction. You can use absolute addresses but only with multi words instruction sequences. The lack of absolute calls wrecked some ideas I had for compiling rom-able code but also made code relocation pretty easy. As usual my forth can build new versions of itself. In all cases I've compiled the new version into higher memory and then relocated it to where I want it. This is pretty easy on the ARM – some absolute links and literals have to be patched up but the main body of code will run in either location. The code will run when moved to flash, you can't use the variables but you can run it well enough the do the initialization.

The most difficult part has been writing the assembler. The ARM is supposed to be a RISC machine – that what the “R” in ARM stands for. This “Reduced Instruction Set” is more complex than most complex instruction sets I've seen. There aren't many instructions but they are not simple or orthogonal. It has been said that forth can be ported to any processor in a week. I have ported forth to some other processors in a week but not this time. Well over a week went into the assembler.
One of the hassles is ARM has an instruction set which can't load every possible immediate value into registers with some sort of “load immediate” instruction. My assembler works around this by remembering values which couldn't be loaded with a simple MOV, generates a lookup table placed after the code definition and replaces the MOV, with a PC relative load. This only applies to MOV, not other immediate operations such as AND,

Thumb and ARM.

The SAM7 has two different instruction sets. It has the regular 32 bit set and also a reduced 16 bit set which is called the “thumb” mode. I started out using the thumb mode but after getting a 16 bit kernel working decided I really needed to use the 32 bit mode. The main problem was I still ended up needing 32 bits to perform a call so most of the code size reduction I'd hope for wasn't possible. I may have given up to early and 16 bit calls may have been possible but my experiments indicated otherwise.

Hardware.

I am running forth on a olimex header pcb http://www.olimex.com/dev/sam7-h256.html. I also have the sam7-64 version. I bought these online from Dontronics and have found the service there to be quite good. I contacted olimex directly before Don had these in stock and found the response to be very terse. I made a logic to rs232 converter myself using a max202 type chip. Don also sells pre-made converters – both logic level to rs232 and logical level to USB. I use SAM7 com port one for coms not port zero – the reason is port one has power to drive the max202 available on the same connector. The board is powered via the USB cable.

Firmware upload.

I use the build in SAMBA boot loader to upload my firmware via the USB port. The PC side software can be download from the atmel web site. I have had some serious PC crashes and hard drive corruption which seems to be triggered by unplugging and replugging the USB cable too quickly after enabling SAMBA on the SAM7. I don't know if this is a problem on other PCs. To be safe wait five or ten seconds before replugging the cable.

Creating forth.

This is the first forth I've done without cross compiling from another forth based computer. I used the assembler in WinARM to write a tiny forth like kernel.
The vocabulary for this kernel is here. I was interested knowing what is the minimal practical word set for bootstrapping the compiler writing process.
I think 40 is about right but not this 40. Some of the words weren't used, some others like VLIST aren't needed but nice to have. If I did this again (no plan to) I'd add a few more words. In particular I'd add CREATE and probably PUSH , POP and a couple of other words the reduce or eliminate the need for adding machine code as hex digits. The kernel is crude and buggy but basically perfect for it's sole purpose of created an improved version of itself.

I was surprised how little machine code I needed. With “AND” “+” and “–“ predefined I could fudge all the logical operators I needed – the high level definitions for words like “OR” will run very slowly but still fast enough to get the job done.

The only low level conditional code I needed was [IF] – this is used not only by “IF” but also “WHILE” and “REPEAT” constructs.

I'm releasing the code for people who may be interested. It has no practical use unless you want to fork off a different forth (say a full thumb mode version). The code is free for personal use. All code and source here uses a Creative Commons Attribution-Noncommercial 2.5 License

The kernel is derived from startup code found in WinARM and still bears the same name.
This is the source (in WinARM assembler). It starts in ARM mode then switches to thumb mode after initialization. Here is the binary. This should execute on most sam7-256s. If you have the LED on pin 8 of the i/o port it should flash, then the word list is dumped from serial port 1. The serial data is 38.4 KBD, 1 start bit 1 stop bit no parity no handshaking. You need to be running a 18.432 mhz crystal for this to work.

Mature emforth systems use a dedicated serial server to interface to the PC but these early versions just use line delays to allow the micro to keep up and respond. I'm using a 80 millisecond delay. This is crude and slow but even so the 32 bit kernel can rebuild itself in just over four minutes. The bootstrap kernel to 32 bit kernel takes just over six. Crude as it is I think its neat to be able to rebuild forth using nothing more than windows hyperterminal and one text file.

The file needed to build a 32 bit arm mode system is from the thumb kernel is here. Just dump this into a newly booted bootstrap kernel (38.4 Kbaud with line delays) and 6ish minutes later a new kernel should be sitting in ARM ram. The command MIRROR64K can be used to write this to flash so it boots on the next reset. I do not recommend you use this kernel for anything too serious because I have better kernels available.

The tiny thumb boot kernel does not have a compiler or assembler. It take about 450 lines (including comment header) of gibberish and pseudo forth to build the compiler. Then around line 720 it starts to build the cross assembler. “Cross” in the sense that it is running thumb code while assembling ARM code.
Around line 1510 we build a cross complier.
1810 the new kernel build is started.
2880 the new kernel is executed. The CPU is now running ARM code. The new kernel is in high memory.
A lot more stuff is compiled into the new forth.
Around line 3000 the image is moved into the bottom of ram. The line “ ' ABORT LFA>CA OFFSET – EXECUTE “ executes the moved image.

A bunch of absolute addressed get patched and we finish off by compiling the words needed to write the image to flash.

At the end of this we have a new 32 bit forth but this doesn't include an assembler yet. This is not a complete system but is complete enough to rebuild itself again and this is an important milestone.

ARM 32 EMForth release one.

My first release of ARM forth consists of two binaries and one source file.
Mini32.bin is 12K kernel which lacks the assembler. The reason I have it here is for people with sam7-64 systems who want to try to run it. I've run it on my sam7-64. There isn't much ram left after the kernel loads but enough to get an idea of whether you like forth enough to upgrade.

Release1.bin is the one most people will want.

Rebuild1.for is the source file to rebuild a new system. I don't think too many people will want to hack the kernel but the possibility is there. For those with the know how you can see how every bit of the system works.

To do.

This is a work in progress there is still a lot to do.

EMForth is not an ANSI forth. It started out as CMforth written by chuck Moore the inventor of forth and was customized however I wanted it. One notable difference is I don't use “ACCEPT” or “EXPECT” I use “GETLINE” instead. I may try to make it more standard later on.

It is also incomplete there will be words missing – such as KEY

A mature Emforth has client/server serial protocol, multiple dictionary threads, memory management, file management and object extensions. None of this will happen any time soon. I would also like to use the USB for coms instead of the serial port but this looks like a lot of work.

There are currently no interrupts or exception handlers.

There is also no support for thumb mode.
This forth runs in RAM. The bootup code runs in flash then the entire image is copied to RAM. The system is already 20K long and will easily be twice that when complete. It seems likely I will have to look at running at least some of the kernel in flash to free up more RAM.
The is currently no easy way to auto run and application on power up.
This isn't hard to do but ideally there should be an bypass mechanism to boot up in the normal mode – a bit like windows uses the f8 key.

Getting started.

If you managed to get it running. It will flash and come up with this prompt.

EMFORTH for the SAM7 ARM micro controller
E.Matejowsky 2007
>

The default number base is 16 – ie hex.

Now type VLIST – it must be upper case – and the vocabulary will be displayed.

To hex dump memory.

> RAM 100 DUMP
Will dump the first 100 (hex?) bytes of RAM.
Read up on forth, look at my source code and play with it.
If the LED worked on power up you might like the compile a word like this.
: TST 10 0 DO FLASHLED LOOP ;
Then type TST to flash the led 16 times if you were in hex mode when TST was compiled or 10 if you were in decimal.
VLIST to show TST is now in the vocabulary.
Or
' TST 2C DUMP to see how it compiled to RAM.

HERE . prints the address of the free memory.
CONTEXT ? shows the address of the beginning of the dictionary linked list.
.S prints the stack without clearing it and so forth.

There are a lot of ways to crash it. One common one is the do something like this -
1 @
This will kill it because word (ie 32 bit) accesses must be on word boundaries – “0 @” or “4 @ “ is valid and so is “1 C@”

Have fun.

Eddie,


http://www.dontronics-shop.com
http://www.olimex.com

To my micros page.
To Eddiem.com