Mecrisp Forth's memory use May 2017

The Blue Pill is a widely available and extremely low-cost STM32F103-based µC board which has an amazing amount of features and plenty of memory onboard: 64K flash and 20K RAM.

In C/C++, the way development works is to run a cross-compiler, as made widely popular with the Arduino IDE. The central development flow is then as follows:

Not so with a self-hosted development environment like Mecrisp Forth, where incremental and on-board development is used: instead of building an application from scratch, and uploading it, you grow your application in small steps and in a bottom-up fashion. Each snippet of code is based on words which have already been defined.

Forth reflects this gradual process in the way it allocates memory:

The above layout is for a USB-connected Blue Pill or other similar low-end board, and uses a build of Mecrisp Forth which assumes 64K flash and 20K RAM (more will simply be ignored).

The core Mecrisp Forth kernel with a serial port as console needs 20 KB of flash memory and some 1,100 bytes of RAM memory (mostly for data & return stacks and the input line buffer).

Adding the USB driver increases flash memory use by 5 KB and RAM use by some 2.5 KB.

The convention is to then load g6u/board.fs, which includes a range of utilities from flib:

As the last step, board.fs, defines the following words:

Next, again by convention, the g6u/core.fs code is loaded - with yet more library definitions:

The above forms a sort of standard base set of words to provide definitions which are expected to be of general use in many projects. The boundary between board, core, and application definitions is quite fuzzy - you can easily set up your own core.fs file and use that instead.

At the time of this writing, the above definitions need 12 KB for board.fs, 10 KB for core.fs, and just over 1 KB of RAM (mostly for an OLED shadow buffer). That leaves 17 KB flash and about 16 KB RAM free for application use, as you can see in this hello call:

hello 64 KB <g6u> 32212433 ram/flash: 16792 17408 free  ok.

Which brings us to “cornerstones”, the foundation which supports such a nested approach:

A cornerstone is a special word which can be defined at any point.
Calling this word at any time will then erase all definitions added after it.

Cornerstones make it very easy to manage flash memory. Note that running such a cornerstone causes a software reset, since Mecrisp needs to reinitialise its RAM to match the new situation. For completeness: there is also a forgetram word, which erases only the definitions in RAM.

By convention, each major section ends with a cornerstone definition - as follows:

So to re-install an updated core.fs, you can enter <<<board>>> and then reload core.fs.

The USB driver re-defines eraseflash, so that it stays resident at all times. Deleting the USB driver would kill the USB connection, i.e. Forth prompt, which is usually not what you want!

Note that these are all just conventions used in the embello Forth codebase - you are absolutely free to use and name cornerstones in any way you like (or not at all).

Each cornerstone will round up flash memory to the next page size, which is 1 KB on F103 µCs with up to 128 KB flash, and 2 KB above that (the L052 has much smaller 128-byte flash pages).

You can define cornerstones in your app (just add a line “cornerstone <<<some-name>>>”), although in practice this is rarely needed. A simpler approach is to place your word definitions in a separate file once they are reasonably stable, and then include it in your copy of core.fs.

By default, Mecrisp Forth compiles new definitions in RAM, growing up from the bottom of free RAM and using up space which might be needed for application data. While this is extremely convenient during development, with non-trivial apps you will eventually run out of RAM. Moving earlier definitions to their own file and including them in core.fs solves this problem.

One final aspect of RAM use to keep in mind, is that the end of free RAM is used for variables and buffers compiled to flash memory: the initial value of each variable is of course stored in flash as part of the definition - it gets copied to high RAM during startup (and after a reset).

Weblog © Jean-Claude Wippler. Generated by Hugo.