Let me apologize upfront for the long post…
While I have not been around much lately, mostly due to a hectic travel schedule, I have also been busy working on something that
I am really excited about. And now it is ready to start share a little information and some demo code.
I have been building an interface that makes integrating fast “near native” code routines into your .NETMF projects much easier
and without having to leave Visual Studio at all or install various tool chains etc.
After a number of prototypes and tests of almost complete solutions I settled on implementing a Forth compiler that runs on the
device directly. Other prototypes have included a partial C scripting compiler and a nearly complete Pascal compiler.
So why Forth?
Learn more about Forth
I first learned Forth in the mid 80’s and have had a passion for the language ever since. Forth is unique in that it can run
interactively ie. interpret your commands and execute them directly while at the same time you can compile a snippet of code that
when executed will run with improved performance all in the same session without leaving the environment.
It is this dual nature that has always drawn me to Forth, the goal is to have code as part of the VS project deployed to the
board and at the sametime connect to the board via the serial port and using a terminal to test out a few things before having it
compiled into your code. The testing does not need the board to be in any special state it can be running code from the VS
project and at the same time you can be initiating commands via the serial port.
Here is a simple example of a factorial routine written in Forth. This implementation is not using recursion, but recursion is
: factorial ( +n1 -- +n2 ) dup 2 < if drop 1 exit then dup begin dup 2 > while 1- swap over * swap repeat drop ;
This code will define a new Forth word called factorial, when a word is defined like this it is immediately compiled so when you
execute the word it does not need to be interpreted therefore providing significant speed advantages.
The most direct way to execute this code in .NETMF would be to use the Forth.Execute method which is a .NETMF method which calls
into the Forth VM.
This will push the number 5 onto the stack and execute factorial the result 120 will be left on the stack to be picked up by the
next code to excute or you can use the Forth.Peek()/Forth.Pop() functions to pull the result off of the stack into a .NETMF
Here is a more visual example
First we have some code that defines a few constants, the word ‘hex’ tells the environment to interpret all number from this
point on as hex numbers, decimal puts the environment into decimal parsing mode (octal and binary are also supported)
hex 500000 constant LCD_BASE_REG LCD_BASE_REG @ constant LCD_BUFFER_ADDR decimal 320 constant SCREEN_WIDTH 240 constant SCREEN_HEIGHT SCREEN_WIDTH 2* constant SCREEN_WIDTH_BYTES SCREEN_WIDTH_BYTES SCREEN_HEIGHT * constant SCREEN_TOTAL_BYTES
Next we define some new words in the language
1 fillscreen : takes the number off the top of the stack and fill the screen with that color
2 setpixel : set the pixel at the location and color defined by the three number on the stack
3 showoff : calls fillscreen in a loop to demonstrate the speed of the code
: fillscreen ( color -- ) SCREEN_TOTAL_BYTES 0 do dup LCD_BUFFER_ADDR i + w! 2 +loop drop ; : setpixel ( color x y -- ) SCREEN_WIDTH * + 2* LCD_BUFFER_ADDR + w! ; hex : showoff ( -- ) 10 0 do 001f fillscreen 0fc0 fillscreen f800 fillscreen loop ;
To run ‘showoff’ for example you would just issue the following command on the .NETMF side
And to fill the screen with white you would issue the following command
This overload of Execute will push the additional arguments onto the stack before executing the ‘fillscreen’ word.
You can push a .NETMF byte array onto the stack and have the FORTH code populate the array, when Forth.Execute returns the manged
array will be filled with data from the the routine.
Everything is still a little rough and ready, it is currently prototyped using RLP and has really 0 optimizations at the moment.
If this proves useful, I would like to do two things
Have a custom firmware which contains the support for using FORTH to write the code that needs more speed
Provide a custom DL40 based module which can be programmed using FORTH via the UART or through the DaisyLink interface to have
custom code running on the device.
Here is a video showing the ‘showoff’ word being executed.