Shi
|
All definitions in Forth must share a certain header which contains
Field | Description | Size [b] |
---|---|---|
Link | Link to previous or next definition | 4 |
Flags | Properties of word (e.g. immediate, inline, ...) | 1 |
Name | Counted string | 1 length + length chars |
Code/data | Code or data | user-defined |
Shi is what's called a direct threaded Forth which means that the execution token of a word equals it's very first assembly instruction. Since the ARMv7-M architecture has certain alignment restrictions and can only execute code from 2-byte aligned addresses there might be a padding byte right after the definitions name.
Dictionary types
Although in practice there is just a single type of dictionary entry it's useful to differ between the data-space a definition resides in and whether it's part of the core dictionary or not. Using this properties we can divide Shi's dictionary into:
Creating the core dictionary
The core dictionary is created by some macro magic heavily inspired by Mecrisp-Stellaris. The macro WORD can be used to automatically create a linked list of assembler functions including flags and a counted string name. The macro parameter label is optional and only necessary if the name of the word contains special characters which are not allowed as assembly labels, otherwise name is also used as label. Since WORD uses the numeric labels 7, 8 and 9 the actual definition may only use 1-6 for its own branches.
Here is an example of the definition of + created with WORD.
Flags
The standard differs between three different properties a word can have. It might have interpretation semantics, compilation semantics and it might be immediate. In theory any combination of those three can occur although some like interpretation semantics and immediate might not make much sense. Shi comes with additional flags for its optimizations and feature to compile to flash. Specially the latter is tricky since variables compiled to it still need to have a cell of ram memory somewhere. For that reason the definition gets marked with the RESERVE_x flag which lets Shi reserve memory cells at the end of data-space at initialization.
Flag | Description | Value |
---|---|---|
FLAG_SKIP | Definition ignored | 0b1111'1111 |
FLAG_INTERPRET | Definition has interpretation semantics | 0b0111'1111 |
FLAG_COMPILE | Definition has compilation semantics | 0b1011'1111 |
FLAG_IMMEDIATE | Definition is immediate (and executes during compilation) | 0b1101'1111 |
FLAG_INLINE | Definition is short enough to get inlined instead of called | 0b1110'1111 |
RESERVE_x | Definition needs to reserve cells of data-space | 0b1111'xx11 |
FOLDS_x | Definition allows constant folding (e.g. 3 4 + is replaced by 7) | 0b1111'11xx |
Search order
As mentioned at page Variables the link to the latest definition in ram is always stored. In case there is no definition in ram yet it still has its initial value which is the start of the core dictionary. Anyhow link provides the start of a singly linked list which iterates through the dictionary in the following order:
In case the user hasn't extended the dictionary so far it looks like this:
The light gray entry is special because it's the very last entry of the core dictionary. It is also the only definition of the core which resides in data and not in text. This is a necessity to allow the very last link of the core dictionary to point to the first entry of the user dictionary in text without recompiling Shi. The address of the user dictionary is simply not known until runtime when it's passed as parameter to the initialization function.
Once the user starts adding definitions in both data-spaces the dictionary might change it's appearance to something like this:
An implication of this search order is that definitions in data are found faster than those in text.
Initialization
To initialize Shi the functions shi::init and shi_init can be used. Both functions take a struct which contains the begin and end addresses of the data-spaces as well as the necessary text alignment for compilation to flash. Passing addresses and alignment for text is completely optional and can simply be set to 0 if not needed.
Besides applying the passed addresses there are three things happening during initialization.