MSP430 eForth

This eForth is based on the version 2 model and targets the MSP430FR5969 part using FRAM. Specifically for TI's Launchpad board. Because it is FRAM, compilation to the main program memory is simple and natural.

There are a few slight changes/additions:

  1. Uses the hardware multiplier
  2. Adds the words: ['], <BUILDS, DOES>, X@, X!
  3. The main body of eForth code is write protected.

X@ and X! add the ability to read and write the memory above 0xffff. Just like @ and ! except that they take a double word address. Highest half of the address is on the top of stack.

The source code is intended to be compiled using the GNU assembler. Which is something of a moving target. One change blew up my CODE macro but I have changed the code for that. Then another change broke iomacros.h. The 12 July 2016 release fixed that problem.

Included is an intel hex file suitable for programming using the TI MSP430Flasher program. So you don't need an assembler to try it out.

Source and image

Console I/O uses the backchannel UART on the Launchpad board. 9600 bps, 8N1. Code size is a bit less than 6K. (0x4400 - 0x5c00)

All of the machine specific code is in the file system.S. Porting to a different version of MSP430 will require changing that. For non-FRAM parts some minor changes to the main file will also be required to relocate CTOP to SRAM.

14 March 2015

I found a bug in the code for compiling strings (."). The zip file above includes the fix.

LCD Booster Pack

I fiddled with the LCD Booster Pack.

25 April 2015

I now have a couple of ways to build this using the latest TI version of GCC. The first replaces the use of the symbol _link with local symbols. This also requires hand building the first header so that the linked list can be terminated.

        .macro   CODE  lex, name, label
        .word  1b
1:      .byte  \lex
        .ascii   "\name"
        .align 1                ; force 16 bit alignment
\label :

Then the first time this gets used at ?KEY has to be done like this:

          .word   0
1:      .byte   4
        .ascii  "?KEY"
        .align  1

The last couple of details are to delete the initial ".equ _link, 0" and a change at the end of the file to set LASTN: " .set LASTN, 1b"

The other method uses a patch to gas posted on the TI e2e forums that alters the behavior of the -mQ option. Combine that with the --no-relax option to ld and it all goes together

This is handy because the MSP430 support files (headers, linker scripts) for the old mspgcc are no longer being updated. Or at least I haven't seen an update in a long time. Which means that if I want to use a more recent part like the MSP430FR5949, I can.

Mass storage for eForth

I am currently working on code that lets eForth store data on a micro-SD card. The most complicated part of that is initializing the card into SPI mode. The code is written to handle all SD, SDHC, and SDXC cards. So far only tested with an old 2GB micro-SD card that doesn't trigger the V1.0 SD initialization. I might not have anything old enough to trigger that. I need to buy a SDHC card to verify that the high capacity parts work.

I have deliberately limited the block numbers to 16 bits and since 1 bit is used as a dirty flag, only 32MB of space is available as BLOCK storage. I do have plans for the rest but that is more than enough for supporting code development.


Cooperative multi-tasking

Cooperative multi-tasking isn't quite as nice as preemptive multi-tasking but it is a lot simpler. In looking at the multi-tasking implementation for eForth I saw a lot that I liked and used. But one thing I changed is how tasks are started. Instead of a multi-step process, it is all included in one word: FORK.

This is a lot like the Unix fork(). For example:

: TASK  ( -- tid )

When TASK is executed it will create a new task allocating space for the user area and stacks. FORK then returns twice. In the child task it continues on to the BEGIN - AGAIN loop. In the parent task it returns to the caller of TASK with the task ID on the stack.

In the original version there were three steps: allocate space for the task data structures, BUILD the task, and finally ACTIVATE the task.

Also included is a very basic task: IDLE. All this does is put the cpu into LPM0 and PAUSE. The timer and serial interrupts will force an exit from LPM0 so everybody gets a chance to run peridically. Just as a visual indicator, an LED is used to show when the CPU is active.

Feb. 2017

I recently purchased a Teensy 3.6 because it has a micro-SD card socket connected to its high speed SD port. I have started the process of porting this version of eForth to it. It works enough to compile simple words but probably has a lot more bugs lurking. They will probably be revealed as I work on code for the SD card.