Glossary¶
Cornerstone¶
A Cornerstone is a special Word. Calling this word will then erase all definitions added after it. The Cornerstone name however will NOT be deleted. An example of this is ‘eraseflash’. Mecrisp-Stellaris does not have a user ‘cornerstone’ word
Marker¶
Marker is the same as ‘Cornerstone’ with the exception that ‘marker’ deletes the name of the marker as well.
Mecrisp-Stellaris does not have a ‘marker’ word either, but you can create one.
Marker Word for 1 KB Flash pages¶
: marker ( name -- )
<builds begin here $3FF and while 0 h, repeat
does> begin dup $3FF and while 2+ repeat
eraseflashfrom ;
Example¶
Enter the “marker” Word into Flash on your system as above
Enter the following, the reply from Mecrisp-Stellaris is indented
words
...
Address: 00003CE6 Link: 00004000 Flags: 0000FFFF Code: 00003D06 Name: --- Flash Dictionary ---
marker corner-a
: testa 2 2 + . cr ;
words
...
Address: 00003CE6 Link: 00004000 Flags: 0000FFFF Code: 00003D06 Name: --- Flash Dictionary ---
Address: 00004000 Link: 0000405C Flags: 00000000 Code: 00004012 Name: marker
Address: 0000405C Link: 00004400 Flags: 00000000 Code: 0000406C Name: corner-a
Address: 00004400 Link: FFFFFFFF Flags: 00000000 Code: 0000440C Name: testa
corner-a
Erase block at 00004404 from Flash
Mecrisp-Stellaris 2.4.5 for TM4C1294 by Matthias Koch
words
...
Address: 00003CE6 Link: 00004000 Flags: 0000FFFF Code: 00003D06 Name: --- Flash Dictionary ---
Warning
Depending on the Flash implementation of the MCU, results may vary from this example.
Imm¶
An immediate value (or simply an immediate or imm) is a piece of data that is stored as part of the instruction itself instead of being in a memory location or a register. Immediate values are typically used in instructions that load a value or performs an arithmetic or a logical operation on a constant.
ARM data processing instructions have 12 bits of space for values in their instruction word. This is arranged as a four-bit rotate value and an eight-bit immediate value.
The 4-bit rotate value stored in bits 11-8 is multiplied by two giving a range of 0-30 in steps of two.
Using this scheme we can express immediate constants such as:
0x000000FF
0x00000FF0
0xFF000000
0xF000000F
But immediate constants such as:
0x000001FE
0xF000F000
0x55550000
…are not possible.
An assembler will convert big values to the rotated form. Impossible values will cause an error.
Some assemblers will use other tricks such as using MVN instead of MOV to form the bitwise complement of the required constant. For example the impossible instruction MOV r0,#0xFFFFFFFF could be assembled as MVN r0,#0. [davespace]
Token¶
Token : sequence of characters having a collective meaning.
<builds does>¶
Or create does>
Michael Ham (https://galileo.phys.virginia.edu/classes/551.jvn.fall01/primer.htm#create) has called the word pair CREATE…DOES>, the “pearl of Forth”. CREATE is a component of the compiler, whose function is to make a new dictionary entry with a given name (the next name in the input stream) and nothing else. DOES> assigns a specific run-time action to a newly CREATEd word.
Folding¶
Constant folding is a well known technique in optimisation. It means that if an operator works on constants the result may be replaced by a constant that is calculated at compile time. In Forth we generalise this to folding. Folding refers to all words that can be replaced by simpler words in case they receive constant data on the stack. [vanderhorst]
“n-foldable” is mostly used on words that take n arguments as input. When the compiler encounters a n-foldable word, it looks back to see if the word is preceded by n literals (or constants), puts them on the stack, calls the word, and compiles the result as a literal.
Inlining¶
Inlining means replacing a Forth word with its constituents. This technique is very important in Forth, more so than in other languages, due to the small size of Forth words. Inlining is always a winner in speed, and mostly even also a winner with regard to space.
Even more important is the fact that inlining allows folding to be applied across constituent words. This applies to high level and low level code alike.
Inlining high level code is trivial. A further inlining stage replaces a high level definition that only calls code words, by a code definition which concatenates the code words. [vanderhorst]
Inlining means taking the code of a word, and putting it in place of a call to this word (saving the cost of a call, usually at the cost of memory)
Inlining Example (Classic Kernel, NON -RA)¶
First the Word “42+” is defined and called by “insert-here” which has to branch to “42+”. No Inlining is used.
: 42+ 42 + ; ok.
see 42+
20000340: B500 push { lr }
20000342: 362A adds r6 #2A
20000344: BD00 pop { pc }
ok
: insert-here 42+ ; ok.
see insert-here
2000035A: B500 push { lr }
2000035C: F7FF bl 20000340 --> 42+
2000035E: FFF0
20000360: BD00 pop { pc }
ok.
Warning
Inlining will fail if there are PC-relative BL opcodes in the definition to be inlined so carefully check the definition(s) in question using the disassembler before specifying INLINE flag or INLINE,
Now Inlining is used, note that “insert-here” now includes the code from “42+” rather than branching to it.
: 42+ 42 + inline ;
see 42+
20000422: B500 push { lr }
20000424: 362A adds r6 #2A
20000426: BD00 pop { pc }
: insert-here 42+ ;
see insert-here
2000043A: B500 push { lr }
2000043C: 362A adds r6 #2A
2000043E: BD00 pop { pc }
Note
Can Inline be used later within “insert-here” instead of in 42+ ?
No, this would only result in “insert-here” being Inlined if called by a later Word.
: 42+ 42 + ;
see 42+
2000044A: B500 push { lr }
2000044C: 362A adds r6 #2A
2000044E: BD00 pop { pc }
: insert-here 42+ inline ;
see insert-here
20000462: B500 push { lr }
20000464: F7FF bl 2000044A --> 42+
20000466: FFF1
20000468: BD00 pop { pc }
See also
Smudge¶
Finishes a definition by flushing all flash buffers and inserts a link into the dictionary chain, making the new definition visible.
Vocabularies¶
July 2017, great news! Manfred Mahlow’s Final Release of VOCs extension for Mecrisp-Stellaris 2.3.6-hook-find (vocs-0.6.2-FR) has arrived for testing. See the new GPIO MODE Demo
Amforth¶
In amforth there is a word that can place newly defined words in wordlists automatically. e.g. a word called foo:bar is placed as bar in wordlist foo. It is like a sibling of a dot (colon)-recognizer that can detect the foo:bar notation and searches bar in foo (only). This word does not affect the definition wordlist or the search order, not even temporarily. [mtrute]
lshift¶
Q: What does the LSHIFT Word do ?
Here are the Dictionary definitions of the SHIFT Words.
exactly ANS, some logical extensions |
||
---|---|---|
arshift |
( x1 u - - x2 ) |
Arithmetric right-shift of u bit-places |
rshift |
( x1 u - - x2 ) |
Logical right-shift of u bit-places |
lshift |
( x1 u - - x2 ) |
Logical left-shift of u bit-places |
Example¶
: gpiob_bsrr_bs9 %1 9 LSHIFT gpiob_bsrr ! ; \ gpiob_bsrr_bs9
GIOB BSRR Register¶
This is a 32 bit register and the picture below is taken from page 159 of the official STM STM32F0xx Reference Manual
Table 8.4.7¶
These bits are write-only. A read to these bits returns the value 0x0000. Note: If both BSx and BRx are set, BSx has priority.
BIT |
0 |
1 |
---|---|---|
BS0 |
No Action |
SETS BIT 0 |
BR0 |
No Action |
RESETS BIT 0 |
How does it work ?¶
There is a “BSRR” register for every GPIO Port on the chip, and this example applies to GPIOB.
Every one of the 16 bits in GPIOB can be SET (1) or RESET (0) by storing a 1 in either its BS or BR Bitfield respectively.
Suppose we want to SET BIT 9 in GPIOB ? What we do is store a “1” to the BS9 position of the GIOB BSRR Register above.
There are many ways to do this, let’s look at some of them.
1) looking at the picture above we can store the binary value of %1000000000 into GIOB_BSRR. The “1” will only set BIT 9 and the “0“‘s will have no effect on the other bits.
%1000000000 GIOB_BSRR !
2) Binary %1000000000 is equal to decimal 512 so we could use that instead, exactly the same thing would happen, BIT 9 would be SET.
512 GIOB_BSRR !
3) Hexadecimal $200 is also equal to %1000000000, so we could use that to set BIT 9
$200 GIOB_BSRR !
Which one do you prefer ? The binary one does relate directly to the BIT in question, but it has a LOT of “0“‘s which are painful to type and painful to check. Decimal or Hex have the same effect but are mentally harder to equate to BIT 9 in Table 8.4.7. above.
Here is a alternative way to look at BIT 9 after it is SET and this is just a table of bits 0 to 31 showing bit 9 is set, and all the others are 0. lines 1 and 2 are the bit number and line 3 is the bit value.
3322222222221111111111
10987654321098765432109876543210
00000000000000000000001000000000
So back to the original question.
The LSHIFT word is a short way to specify BIT 9 and still maintain a easy mental relationship to Table 8.4.7. above. This is how it works.
The LSHIFT Word takes two parameters, the first parameter is the NUMBER TO BE SHIFTED, and the other is how many TIMES TO SHIFT THE NUMBER LEFT.
In our example. “1” is shifted 9 times left using the syntax below.
%1 9 lshift
Which results in the number 1
3322222222221111111111
10987654321098765432109876543210
00000000000000000000000000000001
being shifted into BIT POSITION 9 which is what we want.
3322222222221111111111
10987654321098765432109876543210
00000000000000000000001000000000
We then store that number into GIOB_BSRR like so, which in English reads “shift one, 9 spaces left then store the result into the GPIOB_BSRR register.
%1 9 lshift GPIOB_BSRR !
C Language also Left Shifts¶
Mecrisp-Stellaris Forth isnt the only programming language to left shift bits, look at the following include code by Keil. This code is to define GPIO_MODER_MODE0
#define GPIO_MODER_MODE0_Pos (0U)
#define GPIO_MODER_MODE0_Msk (0x3UL << GPIO_MODER_MODE0_Pos) /*!< 0x00000003 */
#define GPIO_MODER_MODE0 GPIO_MODER_MODE0_Msk
I do it this way in Forth¶
: GPIOC_MODER_MODER0 ( %XX -- ) 0 lshift GPIOC_MODER bis! ; \ GPIOC_MODER_MODER0
%01 constant OUTPUT
OUTPUT GPIOC_MODER_MODER0 \ Configure GPIOC_0 as a OUTPUT
Loop Unrolling¶
Loop unrolling, also known as loop unwinding, is a loop transformation technique that attempts to optimize a program’s execution speed at the expense of its binary size
Postpone¶
(My thanks to rdrop-exit on irc.freenode #forth for helping me understand this.)
postponing has the effect of delaying the normal compile-time action of a word, but what that action normally is depends on whether the word being postponed is immediate or not
Example¶
: THINKING ( -- ) ." I'm deciding... " ;
: NEWIF ( x -- ) postpone THINKING postpone IF ; immediate
: FOO ( x -- ) newif ." yes" else ." no" then ;
1 FOO I'm deciding... yes ok.
0 FOO I'm deciding... no ok
Note
THINKING and FOO are NON-IMMEDIATE Words, IF and NEWIF are IMMEDIATE Words. See Dictionary Flags
Flags: 00000630 Name: if
Flags: 00000000 Name: FOO
Flags: 00000010 Name: NEWIF
Flags: 00000000 Name: THINKING
FLAG Codes¶
Taken from mecrisp-stellaris-2.4.7/mecrisp-stellaris-source/common/datastackandmacros.s
Flag |
Description |
---|---|
0x0000 |
Visible, non-immediate |
0x0010 |
Immediate |
0x0030 |
Immediate+Inline means: Immediate, Compile-Only |
Registerliteral,¶
This is used to generate RELATIVE machine code to use when INLINING.
Registerliteral, generates the shortest possible sequence to get x into given low Register using movs adds lsls sequences. 1. M0: A movs-lsls-adds… sequence 2. M3/M4: movs / movs-mvns / movw / movw-movt
This is used instead of the command “ldr=” which generates ABSOLUTE addressing. A movs adds lsls sequences needs to be used instead to load a literal in a register.
Example¶
: rlit
[
1000 0 registerliteral,
]
;
see rlit
20000654: B500 push { lr }
20000656: 20FA movs r0 #FA
20000658: 0080 lsls r0 r0 #2
2000065A: BD00 pop { pc }