Rabbit gForth Extensions
Loading Source Files
I use a Python terminal to help load Forth code on the ATmega. The same approach can be used on the Rabbit. Here is the Python loader modified for gForth.
Loading Source Files - alternates
Serial downloads of source files can be limited by the Forth compiler speed.
For now, I'm using a LOAD-READ mechanism that is similar to the one I used with eForth.
To load a source file:
1. type LOAD <enter>
2. use your terminal emulator to send the ASCII file.
type ^Z when the transfer is complete.
3. type READ <enter>
READ first eliminates the '\' comment
to end of line and replaces those characters with spaces.
Then it does an EVALUATE on the input
buffer, which compiles the un-commented source.
Note that the buffer size is 0x2000 bytes.
I use Kermit as my terminal emulator. It runs on most hosts and is very
flexible.
The ^Z to terminate LOAD can be added
automatically if you use:
set transmit eof \26
and then to do the file transfer use:
transmit /nowait filename
finally use READ to compile from the
buffer.
To use Kermit with FILE:
set transmit prompt 46
set transmit timeout 30
and then transfer using:
transmit filename
this compiles line by line as they are transferred.
Changing Baud Rate and CPU Clock Rate
CPU Clock is controlled by GCR at 0x00
0x08 is the default (no divide)
0x04 divides the CPU by 8, with no divide for peripherals
Clock Doubler is controlled by 0x0F
0x5B use doubler (default).
0x00 no doubler
Baud rate for Serial A is controlled by counter A4 at 0xA9
at 22MHz default, 19,200 baud is 0x23 (35). 38,400 baud is 0x11 (17),
57,600 baud is 0x0B (11). 115,200 is 0x05.
To change the baud rate to 115,200:
HEX
5 A9 p!
Loading a New gForth Image
You can force a new gForth image to load into an existing FS2 file system by
compiling the loader and new gForth binary to the Rabbit, then reset the Rabbit
to boot gForth and type the RESTORE command. Recall that RESTORE copies
the image from flash into the filesystem (where the working image is stored).
This will be complicated if the new image uses a different serial port!
I've successfully typed RESTORE at the old serial port, then switched to the new serial port to type Y to complete the write to flash. A better approach is to reformat the file system using this Dynamic-C program to format the file system and the binary to load with RFU.
Coding Words in Assembly
Assembly code can be included by wrapping the position independent opcodes with the code for a colon definition header and ending. For small routines use the "," word to compile opcodes into code space. Note that the Rabbit is little endian. : NEWDUP [ here dup cell - cell - dp ! , 0 , ] [ 00c5 , ] [ eb00 , 235e , 2356 , fdeb , dd7d , 00e4 , 20e9 , ] ; This creates a word NEWDUP that duplicates the existing word DUP. The words on the first line convert the colon (Forth) definition into a code (assembly) definition. Note that HERE is defined as DP @, so the first part of the first line adjusts the value of the variable DP (the dictionary pointer. Brodie pg 213). The next two lines stick the opcodes into successive memory locations. The last of those two lines is next, with a nop pre-pended. DUP in assembly is shown in Listing 1. 0 : C5 PUSH BC 1 : ; next , MACRO 1 : EB EX HL,DE 2 : 5E LD E,(HL) 3 : 23 INC HL 4 : 56 LD D,(HL) 5 : 23 INC HL 6 : EB EX HL,DE 7 : FD 7D LD IY,HL 9 : DD E4 00 LD HL,(HL+0) C : E9 JP (HL) D : ; ENDM Listing 1
Loading Assembly Words
For larger assembly routines, first load hexloader.fs.
This file is Forth source. Use the LOAD-READ described above.
Then use hexload to load a hex file produced by AS, a free, portable macro cross
assembler.
The assembly source for mydup is in hextest2.asm.
Use the '-cpu z180 ' switch for as.exe
Use the '-F Intel16' switch for the p2hex.exe utility that creates the hex file.
The Rabbit 2000 is similar to the Z180.
Use DB to place opcodes for new instructions and be careful to not use deleted
or changed instructions.
You can load new assembly words as an Intel hex file:
First load hexload.fs (load, read)
Then load hextest2.hex (just load, no
read)
Then follow these steps:
create mydup ok here dup ok hexload ok ' mydup ! ok ' mydup 20 dump 4D66: 6A 4D 00 00 C5 1A 6F 13 - 1A 67 13 FD 7D DD E4 00 jM....o..g..}... 4D76: E9 00 9B DB BE BB F4 90 - 9A 18 37 02 5C 06 F0 11 ..........7.\... ok ' dup 20 dump 42C: 30 04 00 00 C5 1A 6F 13 - 1A 67 13 FD 7D DD E4 00 0.....o..g..}... 43C: E9 20 26 04 84 32 64 75 - 70 20 4A 04 00 00 E1 E5 . &..2dup J..... ok
Note that HERE still points to ' mydup 4 + You'll want to ALLOT the number of bytes in hextest2.hex to avoid over-writing mydup.
Interrupt Service Routines
gForth doesn't provide access to the EIR or IIR registers that provide the upper byte of the reset vector. I've coded Forth words for internal interrupts IIR! and IIR@. The interrupt vector table must locate vectors in 16 byte fields. If all are used, 256 bytes are needed for the vector table and this table must start at an address that has zero in the low byte (i.e. address mod 256 = 0). The most efficient place to put the vector table and allocate space for the service routine(s) and shared variables (the address of the variable must be know to both the service routine and Forth code) is in high memory. Here is a Dynamic-C program that uses an assembly Timer-B interrupt service routine to toggle the pins on Port-E at 1 Hz. Here is a gForth program that does the same thing with the assembly source and hex. LOAD hexload.fs READ LOAD iir_code_words.fs READ LOAD r2k_int.hex DC02 hexload LOAD timerB_int.fs READ
Then inspecting DC00 should show the count changing.
Running blink will toggle Port-E at 1 Hz.
Porting to other Processors
It may take less time to port gForth to different processors if an existing
cross assembler
(e.g. AS) is used to code the primitives. A Perl script can be run to create
prims.fs
from the assembler list file. This is primarily an advantage in embedded systems
where the
Forth assembler probably won't be used on the target due to memory limitations.