Flash Framework
To append a word to a dictionary in amforth32 we need the words c, , dallot to function on the memory backing the dictionary. amforth32 accommodates dictionaries in both RAM and flash, so handles this duality by making c, , dallot deferred words. Depending upon whether the system is targeting RAM or flash the the defer is set to a target word which actually does the work on the memory type targeted. In addition amforth32 needs the word ! for RAM, and !i for non RAM (flash), to write a cell at a given memory address. !i is a defer but ! is not.
Interfacing with a flash controller using the flash framework means writing the set of five defer targets and three support words. The defer targets follow the convention that ^ operates on RAM (usually a higher address) and ~ operates on flash (usually a lower address).
defer c,
: ^c, ( c -- ) dp c! 1 dallot ; \ already written in ccomma.s
: ~c, ( c -- ) ( FC specific ) ; \ needs to be written
defer ,
: ^, ( n -- ) dp ! cell dallot ; \ already written in comma.s
: ~, ( n -- ) ( FC specific ) ; \ needs to be written
defer dallot
: ^dallot ( n -- ) dp + to dp ; \ already written in dallot.s
: ~dallot ( n -- ) ( FC spec. ) ; \ needs to be written
defer !i
: ~!i ( n fa -- ) ( FC spec. ) ; \ needs to be written
defer flash.erase ( fa -- )
: ~flash.erase ( fa -- ) ; \ needs to be written
Implementations for physical flash controllers will also need the following words to support the defer targets above.
: flash.write ( dp -- ) ; \ needs to be written
: flash.unlock ( -- ) ; \ needs to be written
: flash.lock ( -- ) ; \ needs to be written
The default target assignment of the targets to the defers in handled by the build process. If a mcu X has a flash backed dictionary then the above words are expected to be in the file
mcu/X/words/flash.s
This will be chosen in preference to the
core/words/flash.s
which implements the above words for a faux flash controller that uses RAM (see later)
The complexity of the target words depends upon the individual flash controller. From the Forth compiler’s point of view, the ideal controller looks like RAM, though in reality, most do not. Key considerations are
- flash cell size (minimum write size of the FC) is greater than cell
- bit clearing (without erase) is not possible after flash cell write
- flash routines can only execute from RAM
The more yeses, the more complex the target word implementation. In order of increasing complexity, target words for the following controllers have been implemented using the flash framework.
Faux flash
This uses an area of RAM to emulate an ideal flash controller, thus ~ target words are identical to ^ target words. This is used by the QEMU virtual machines.
core/words/flash.s
ch32v307 standard mode flash
flash.cell=2 so flash.cell <= cell. Flash routines can execute from flash.
rv/mcu/ch32v307/words/flash.s
RA4M1 code flash
flash.cell=8 so flash.cell > cell. Flash routines can only execute from ram. flash.cell cannot be modified in any way after a flash write without an erase.
arm/mcu/ra4m1/words/flash.s
Flushing
Unless a flash controller can write a single byte at a byte address, flushing will be needed. This is because the physical write to flash is delayed until the cache is full. Data in the cache is not available for use by the system, so in circumstances where that is not acceptable the cache is automatically flushed using the internal word flash.flush. For for special situations, a manual flush can be executed with the visible word flush. flash.flush uses the framework words and usually does not need to be modified.
Interrupts
Flash controller specifications should be followed, but in general, if interrupts are being used (not currently the case) they should be turned off for the duration of the flash operation.
Multiple cores
Flash controller specifications should be followed.