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
fully supported.
: 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.
Forth.Execute("5 factorial");
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
variable.
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
Forth.Execute("showoff");
And to fill the screen with white you would issue the following command
Forth.Execute("fillscreen", Color.White);
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.