Difference between revisions of "Colibri Forth"

From Stm32World Wiki
Jump to navigation Jump to search
 
(33 intermediate revisions by the same user not shown)
Line 1: Line 1:
Colibri Forth is derived from [https://github.com/zevv/zForth zForth]. [https://en.wikipedia.org/wiki/Forth_(programming_language) Forth] is a tiny programming language that is very suitable for embedded systems as it is easy to adapt, extend and tailor for any environment and doesn't depend on POSIX or other large libraries or operating systems. There is a Forth standard, called ANS Forth, which strives to unify the vocabulary used in sea of Forth implementations (there is a rumor of "there are more Forth implementations than Forth applications"). This unification work have led to a fairly large footprint of ANS Forth, and we don't have such luxury. And zForth is not following the ANS Forth standard,
+
[[Category:Colibri]][[Category:Work in progress]]{{metadesc|Colibri Forth}}
  
= Colibri Vocabulary =
+
Colibri Forth is built upon MECRISP (https://mecrisp.sourceforge.net, written by Matthias Koch), the Stellaris variant, an advanced Forth, that compiles to machine code on the target itself, for optimal performance. Additional work/inspiration has been source from Peter Schmid's Mecrisp-Cube project (https://github.com/spyren/Mecrisp-Cube).
(to be defined)
 
  
= zForth Vocabulary =  
+
= Architecture =
 +
Forth is a stack-oriented language that has 2 stacks, one for data and one call stack for with return addresses. It has very simple syntactic rules;
  
== Primitives ==
+
1. Everything is a "word" which must be surrounded by whitespace. All non-whitespace bytes are allowed in word.
The primitives are words that are implemented in C. All other vocabulary words are built from these.
+
1. Backslash is start of comment, and everything will be filtered out until parser reaches new line.
 +
1. Everything between a pair of parentheses " ( xyz ) " is a comment. They can be stretching multiple lines. Nested parentheses are not supported.
 +
1. Thereafter, try to locate word in dictionary. If found, "use" (depends on whether compiling or executing) it.
 +
1. If word is not found in dictionary, try to parse it as a number. If successful, push number on stack.
 +
1. All words operate on the stacks. Typically manipulating the Top-Of-Stack (TOS), by popping value(s) off the top and pushing the result back on top.
 +
1. Forth is NOT a unified/standardized language and except for a small number of core words, there is no consensus of what the base vocabulary is. Many
 +
think that the nearest a standard (ANS Forth) is too bloated and not suitable for all the target devices that a more lean Forth can run on. This means
 +
that many libraries won't work out-of-the-box and will require tweaking by the user.
  
  exit
 
  lit
 
  <0
 
  :
 
  _;
 
  +
 
  -
 
  *
 
  /
 
  %
 
  drop
 
  dup
 
  pickr
 
  _immediate
 
  @@
 
  !!
 
  swap
 
  rot
 
  jmp
 
  jmp0
 
  '
 
  _(
 
  >r
 
  r>
 
  =
 
  sys
 
  pick
 
  ,,
 
  key
 
  lits
 
  ##
 
  &
 
  |
 
  ^
 
  <<
 
  >>
 
  
== Core ==
+
Colon ":" is the word to define other words, and the definition ends with semicolon ";". Example
  
  ( system calls )
+
   : add4 4 + ;  \ adds 4 to the value on TOS.
   : emit    0 sys ;
 
  : .      1 sys ;
 
  : tell    2 sys ;
 
  : quit    128 sys ;
 
  : sin    129 sys ;
 
  : include 130 sys ;
 
  : save    131 sys ;
 
 
 
  ( dictionary access. These are shortcuts through the primitive operations are !!, @@ and ,, )
 
  : !    0 !! ;
 
  : @    0 @@ ;
 
  : ,    0 ,, ;
 
  : #    0 ## ;
 
 
 
  ( compiler state )
 
  : [ 0 compiling ! ; immediate
 
  : ] 1 compiling ! ;
 
  : postpone 1 _postpone ! ; immediate
 
 
 
  ( some operators and shortcuts )
 
  : 1+ 1 + ;
 
  : 1- 1 - ;
 
  : over 1 pick ;
 
  : +!  dup @ rot + swap ! ;
 
  : inc  1 swap +! ;
 
  : dec  -1 swap +! ;
 
  : <    - <0 ;
 
  : >    swap < ;
 
  : <=  over over >r >r < r> r> = + ;
 
  : >=  swap <= ;
 
  : =0  0 = ;
 
  : not =0 ;
 
  : !=  = not ;
 
  : cr  10 emit ;
 
  : br 32 emit ;
 
  : ..  dup . ;
 
  : here h @ ;
 
 
 
  ( memory management )
 
  : allot  h +!  ;
 
  : var : ' lit , here 5 allot here swap ! 5 allot postpone ; ;
 
  : const : ' lit , , postpone ; ;
 
 
 
  ( 'begin' gets the current address, a jump or conditional jump back is generated
 
    by 'again', 'until' )
 
  : begin  here ; immediate
 
  : again  ' jmp , , ; immediate
 
  : until  ' jmp0 , , ; immediate
 
 
 
  ( '{ ... ... ... n x}' repeat n times definition - eg. : 5hello { ." hello " 5 x} ; )
 
  : { ( -- ) ' lit , 0 , ' >r , here ; immediate
 
  : x} ( -- ) ' r> , ' 1+ , ' dup , ' >r , ' = , postpone until ' r> , ' drop , ; immediate
 
 
 
  ( vectored execution - execute XT eg. ' hello exe )
 
  : exe ( XT -- ) ' lit , here dup , ' >r , ' >r , ' exit , here swap ! ; immediate
 
 
 
  ( execute XT n times  e.g. ' hello 3 times )
 
  : times ( XT n -- ) { >r dup >r exe r> r> dup x} drop drop ;
 
 
 
  ( 'if' prepares conditional jump, address will be filled in by 'else' or 'fi' )
 
  : if      ' jmp0 , here 999 , ; immediate
 
  : unless  ' not , postpone if ; immediate
 
  : else    ' jmp , here 999 , swap here swap ! ; immediate
 
  : fi      here swap ! ; immediate
 
 
 
  ( forth style 'do' and 'loop', including loop iterators 'i' and 'j' )
 
  : i ' lit , 0 , ' pickr , ; immediate
 
  : j ' lit , 2 , ' pickr , ; immediate
 
  : do ' swap , ' >r , ' >r , here ; immediate
 
  : loop+ ' r> , ' + , ' dup , ' >r , ' lit , 1 , ' pickr , ' > , ' jmp0 , , ' r> , ' drop , ' r> , ' drop , ; immediate
 
  : loop ' lit , 1 , postpone loop+ ;  immediate
 
 
 
  ( Create string literal, puts length and address on the stack )
 
  : s" compiling @ if ' lits , here 0 , fi here begin key dup 34 = if drop
 
      compiling @ if here swap - swap ! else dup here swap - fi exit else , fi
 
      again ; immediate
 
 
 
  ( Print string literal )
 
  : ." compiling @ if postpone s" ' tell , else begin key dup 34 = if drop exit else emit fi again
 
      fi ; immediate
 
 
 
  : max  over over < if swap fi drop ;
 
  : min  over over > if swap fi drop ;
 
  
== Dictionary ==
+
It is common to put the stack manipulation info as a comment after the defined word. Example
Words for handling the dictionary
 
  
  ( 'next' increases the given dictionary address by the size of the cell
+
   : add4 ( n -- n+4 ) 4 + ;
    located at that address )
 
  : next dup # + ;
 
 
 
  ( 'words' generates a list of all define words )
 
  : name dup @ 31 & swap next dup next rot tell @ ;
 
  : words latest @ begin name br dup 0 = until cr drop ;
 
  : prim? ( w -- bool ) @ 32 & ;
 
  : a->xt ( w -- xt ) dup dup @ 31 & swap next next + swap prim? if @ fi ;
 
  : xt->a ( xt -- w ) latest @ begin dup a->xt 2 pick = if swap drop exit fi next @ dup 0 = until swap drop ;
 
  : lit?jmp? ( a -- a boolean ) dup @ dup 1 = swap dup 18 = swap 19 = + + ;
 
   : disas ( a -- a ) dup dup . br br @ xt->a name drop lit?jmp? if br next dup @ . fi cr ;
 
 
 
  ( 'see' needs starting address on stack: e.g. ' words see )
 
  : see ( xt -- ) dup xt->a name cr drop begin disas next dup @ =0 until drop ;
 
 
 
  ( 'dump' memory make hex dump len bytes from addr )
 
  : hex_t ' lit ,  here dup , s" 0123456789abcdef" allot swap ! ; immediate
 
  : *hex_t hex_t ;
 
  : .hex *hex_t + @ emit ;
 
  : >nib ( n -- low high ) dup 15 & swap -16 & 16 / ;
 
  : ffemit ( n -- ) >nib .hex .hex ;
 
  : ffffemit ( n -- ) >nib >nib >nib { .hex 4 x} ;
 
  : @LSB ( addr -- LSB ) 2 @@ 255 & ;
 
  : between? ( n low_lim high_lim -- bool ) 2 pick > rot rot > & ;
 
  : 8hex ( a -- a_new ) { dup @LSB ffemit 32 emit 1+ 8 x} 32 emit ;
 
  : 16ascii ( a -- a_new ) 124 emit { dup @LSB dup 31 127 between? if emit else drop 46 emit fi 1+ 16 x} 124 emit ;
 
  : .addr ( a -- ) ffffemit ."    " ;
 
  : 16line ( a -- a_new ) dup .addr dup { 8hex 2 x} drop 16ascii cr ;
 
  : dump ( addr len -- ) over + swap begin 16line over over < until drop drop ;
 
  
=== Memory Access ===
+
It is the same thing, just human-readable comment to hint at what the word does.
  : !c 1 !! ;
 
  : !u8 2 !! ;
 
  : !u16 3 !! ;
 
  : !u32 4 !! ;
 
  : !s8 5 !! ;
 
  : !s16 6 !! ;
 
  : !s32 7 !! ;
 
  
  : @c 1 @@ ;
+
The '''Full Documentation''' of Mecrisp is written by Terry Porter and published at https://mecrisp-stellaris-folkdoc.sourceforge.io/
  : @u8 2 @@ ;
 
  : @u16 3 @@ ;
 
  : @u32 4 @@ ;
 
  : @s8 5 @@ ;
 
  : @s16 6 @@ ;
 
  : @s32 7 @@ ;
 
  
   : ,c 1 ,, ;
+
Mecrisp and Colibri Forth are '''not case-sensitive''', but many other Forth variants are.
  : ,u8 2 ,, ;
+
 
  : ,u16 3 ,, ;
+
= Interactivity =
   : ,u32 4 ,, ;
+
Forth is an interactive language, which is awesome for embedded development. One can simply hook up a serial terminal and do development on the target itself. One can interactively work with the MCU registers and peripherals to figure out the proper configuration/operation without doing a full erase+write cycle to the flash memory. We can execute code directly from RAM and not commit it to Flash until we have worked out the details.
   : ,s8 5 ,, ;  
+
 
   : ,s16 6 ,, ;
+
= Cookbook =
   : ,s32 7 ,, ;
+
We are going to assemble useful snippets and words that will be useful, but not common enough to be included in the standard vocabulary. We call this the [[Colibri Forth Cookbook]] and will be a slowly growing document of Forth for the Colibri family.
 +
 
 +
= Resources =
 +
https://mecrisp-stellaris-folkdoc.sourceforge.io/
 +
https://www.spyr.ch/twiki/bin/view/MecrispCube
 +
 
 +
= Default Word List =
 +
(Courtesy Matthias Koch, https://mecrisp.sourceforge.net/glossary.htm)
 +
 
 +
== Terminal-IO ==
 +
(exactly ANS, some logical extensions)
 +
<pre>
 +
        emit?          ( -- Flag ) Ready to send a character ?
 +
        key?            ( -- Flag ) Checks if a key is waiting
 +
        key            ( -- Char ) Waits for and fetches the pressed key
 +
        emit            ( Char -- ) Emits a character.
 +
 
 +
        hook-emit?      ( -- a-addr ) Hooks for redirecting
 +
        hook-key?      ( -- a-addr )   terminal IO
 +
        hook-key        ( -- a-addr )    on the fly
 +
        hook-emit      ( -- a-addr )
 +
 
 +
        serial-emit?    ( -- Flag )  Serial interface
 +
        serial-key?    ( -- Flag )    terminal routines
 +
        serial-key      ( -- Char )      as default communications
 +
        serial-emit    ( Char -- )
 +
 
 +
        hook-pause      ( -- a-addr ) Hook for a multitasker
 +
        pause          ( -- )        Task switch, none for default
 +
</pre>
 +
 
 +
== Stack Jugglers ==
 +
(exactly ANS, some logical extensions)
 +
 
 +
=== Single-Jugglers ===
 +
<pre>
 +
        depth          ( -- +n ) Gives number of single-cell stack items.
 +
        nip            ( x1 x2 -- x2 )
 +
        drop            ( x -- )
 +
        rot            ( x1 x2 x3 -- x2 x3 x1 )
 +
        -rot            ( x1 x2 x3 -- x3 x1 x2 )
 +
        swap            ( x1 x2 -- x2 x1 )
 +
        tuck            ( x1 x2 -- x2 x1 x2 )
 +
        over            ( x1 x2 -- x1 x2 x1 )
 +
        ?dup            ( x -- 0 | x x )
 +
        dup            ( x -- x x )
 +
        pick            ( ... xi+1 xi ... x1 x0 i -- ... x1 x0 xi )
 +
                                  Picks one element from deep below
 +
 
 +
        >r              ( x -- ) (R: -- x )
 +
        r>              ( -- x ) (R: x -- )
 +
        r@              ( -- x ) (R: x -- x )
 +
        rdrop          (  --  ) (R: x -- )
 +
        rdepth          ( -- +n ) Gives number of return stack items.
 +
        rpick          ( i -- xi ) R: ( ... xi ... x0 -- ... xi ... x0 )
 +
</pre>
 +
 
 +
=== Double-Jugglers ===
 +
They perform the same for double numbers.
 +
<pre>
 +
        2nip            ( x1 x2 x3 x4 -- x3 x4 )
 +
        2drop          ( x1 x2 -- )
 +
        2rot            ( x1 x2 x3 x4 x5 x6 -- x3 x4 x5 x6 x1 x2 )
 +
        2-rot          ( x1 x2 x3 x4 x5 x6 -- x5 x6 x1 x2 x3 x4 )
 +
        2swap          ( x1 x2 x3 x4 -- x3 x4 x1 x2 )
 +
        2tuck          ( x1 x2 x3 x4 -- x3 x4 x1 x2 x3 x4 )
 +
        2over          ( x1 x2 x3 x4 -- x1 x2 x3 x4 x1 x2 )
 +
        2dup            ( x1 x2 -- x1 x2 x1 x2 )
 +
 
 +
        2>r            ( x1 x2 -- ) (R: -- x1 x2 )
 +
        2r>            ( -- x1 x2 ) (R: x1 x2 -- )
 +
        2r@            ( -- x1 x2 ) (R: x1 x2 -- x1 x2 )
 +
        2rdrop          ( -- )      (R: x1 x2 -- )
 +
</pre>
 +
 
 +
=== Stack pointers ===
 +
<pre>
 +
        sp@            ( -- a-addr )  Fetch  data stack pointer
 +
        sp!            ( a-addr -- )  Store  data stack pointer
 +
        rp@            ( -- a-addr )  Fetch return stack pointer
 +
        rp!            ( a-addr -- )  Store return stack pointer
 +
</pre>
 +
 
 +
== Logic ==
 +
(exactly ANS, some logical extensions)
 +
<pre>
 +
        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
 +
        shr            ( x1 -- x2 )  Logical right-shift of one bit-place
 +
        shl            ( x1 -- x2 )  Logical  left-shift of one bit-place
 +
        ror            ( x1 -- x2 )  Logical right-rotation of one bit-place
 +
        rol            ( x1 -- x2 )  Logical  left-rotation of one bit-place
 +
        bic            ( x1 x2 -- x3 ) Bit clear, identical to "not and"
 +
        not            ( x1 -- x2 )  Invert all bits
 +
        xor            ( x1 x2 -- x3 ) Bitwise Exclusive-OR
 +
        or              ( x1 x2 -- x3 ) Bitwise OR
 +
        and            ( x1 x2 -- x3 ) Bitwise AND
 +
        false          ( --  0 ) False-Flag
 +
        true            ( -- -1 ) True-Flag
 +
        clz            ( x1 -- u ) Count leading zeros
 +
</pre>
 +
 
 +
== Calculus for single numbers ==
 +
(exactly ANS, some logical extensions)
 +
<pre>
 +
        u/mod          ( u1 u2 -- u3 u4 ) u1/u2 = u4 rem u3 Division
 +
        /mod            ( n1 n2 -- n3 n4 ) n1 / n2 = n4 rem n3
 +
        mod            ( n1 n2 -- n3 ) n1 / n2 = remainder n3
 +
        /              ( n1 n2 -- n3 ) n1 / n2 = n3
 +
        *              ( u1|n1 u2|n2 -- u3|n3 ) Single Multiplication
 +
        min            ( n1 n2 -- n1|n2 ) Keeps smaller of top two items
 +
        max            ( n1 n2 -- n1|n2 ) Keeps greater of top two items
 +
        umin            ( u1 u2 -- u1|u2 ) Keeps unsigned smaller
 +
        umax            ( u1 u2 -- u1|u2 ) Keeps unsigned greater
 +
        2-              ( u1|n1 -- u2|n2 ) Subtracts two, optimized
 +
        1-              ( u1|n1 -- u2|n2 ) Subtracts one, optimized
 +
        2+              ( u1|n1 -- u2|n2 ) Adds two, optimized
 +
        1+              ( u1|n1 -- u2|n2 ) Adds one, optimized
 +
        even            ( u1|n1 -- u2|n2 ) Makes even. Adds one if uneven.
 +
        2*              ( n1 -- n2 ) Arithmetric  left-shift
 +
        2/              ( n1 -- n2 ) Arithmetric right-shift
 +
        abs            ( n -- u ) Absolute value
 +
        negate          ( n1 -- n2 ) Negate
 +
        -              ( u1|n1 u2|n2 -- u3|n3 ) Subtraction
 +
        +              ( u1|n1 u2|n2 -- u3|n3 ) Addition
 +
</pre>
 +
 
 +
== Calculus involving double numbers ==
 +
(exactly ANS, some logical extensions)
 +
<pre>
 +
        um*            ( u1 u2 -- ud )                u1 * u2 = ud
 +
        udm*            ( ud1 ud2 -- ud3-Low ud4-High ) ud1 * ud2 = ud3-Low ud4-High
 +
 
 +
        um/mod          ( ud u1 -- u2 u3 )              ud / u1 = u3 remainder u2
 +
        ud/mod          ( ud1 ud2 -- ud3 ud4 )          ud1/ud2 = ud4 rem ud3
 +
 
 +
        m*              ( n1 n2 -- d )                  n1 * n2 = d
 +
        m/mod          ( d  n1 -- n2 n3 )              d  / n1 = n3 remainder r2
 +
 
 +
        */              ( n1 n2 n3 -- n4 )              n1 * n2 / n3 = n4
 +
        u*/            ( u1 u2 u3 -- u4 )              u1 * u2 / u3 = u4
 +
        */mod          ( n1 n2 n3 -- n4 n5 )          n1 * n2 / n3 = n5 remainder n4
 +
 
 +
        d2*            ( d1 -- d2 )                    Arithmetric  left-shift
 +
        d2/            ( d1 -- d2 )                    Arithmetric right-shift
 +
        dshl            ( ud1 -- ud2 )                  Logical left-shift, same as d2*
 +
        dshr            ( ud1 -- ud2 )                  Logical right-shift (shifts in a zero in left-most bit)
 +
 
 +
        dabs            ( d -- ud )                    Absolute value
 +
        dnegate        ( d1 -- d2 )                    Negate
 +
        d-              ( ud1|d1 ud2|d2 -- ud3|d3 )    Subtraction
 +
        d+              ( ud1|d1 ud2|d2 -- ud3|d3 )    Addition
 +
        s>d            ( n -- d )                      Makes a signed single number double length
 +
</pre>
 +
 
 +
== Comparisions ==
 +
(exactly ANS, some logical extensions)
 +
 
 +
=== Single-Comparisons ===
 +
<pre>
 +
        u<=            ( u1 u2 -- flag )  Unsigned comparisons, u1 <= u2
 +
        u>=            ( u1 u2 -- flag )
 +
        u>              ( u1 u2 -- flag )
 +
        u<              ( u1 u2 -- flag )
 +
        <=              ( n1 n2 -- flag )  Signed comparisons
 +
        >=              ( n1 n2 -- flag )
 +
        >              ( n1 n2 -- flag )
 +
        <              ( n1 n2 -- flag )
 +
        0<              ( n - flag )      Negative ?
 +
        0<>            ( x -- flag )      Not 0
 +
        0=              ( x -- flag )      Zero?
 +
        <>              ( x1 x2 -- flag )
 +
        =              ( x1 x2 -- flag )
 +
</pre>
 +
 
 +
=== Double-Comparisons ===
 +
They perform the same for double numbers.
 +
<pre>
 +
        du>            ( ud1 ud2 -- flag )
 +
        du<            ( ud1 ud2 -- flag )
 +
        d>              ( d1 d2 -- flag )
 +
        d<              ( d1 d2 -- flag )
 +
        d0<            ( d -- flag )
 +
        d0=            ( d -- flag )
 +
        d<>            ( d1 d2 -- flag )
 +
        d=              ( d1 d2 -- flag )
 +
</pre>
 +
 
 +
== Tools ==
 +
(not only) for double fixed point numbers (specialty!)
 +
 
 +
Fixpoint numbers are stored ( n-comma n-whole ) and can be handled
 +
like signed double numbers.
 +
 
 +
<pre>
 +
        f/              ( df1 df2 -- df3 )        Division of two fixpoint numbers
 +
        f*              ( df1 df2 -- df3 )        Multiplication
 +
 
 +
        hold<          ( char -- )              Adds character to pictured number output buffer from behind.
 +
        f#S            ( n-comma1 -- n-comma2 )  Adds all comma-digits to number output
 +
        f#              ( n-comma1 -- n-comma2 )  Adds one comma-digit to number output
 +
        f.              ( df -- )                Prints a fixpoint number with all fractional digits
 +
        f.n            ( df n -- )              Prints a fixpoint number with n fractional digits
 +
 
 +
        number          ( c-addr length -- 0 )
 +
                                        -- n 1 )
 +
                                        -- n-low n-high 2 )
 +
                        Tries to convert a string to a number.
 +
</pre>
 +
 
 +
== Number base ==
 +
(exactly ANS)
 +
<pre>
 +
        binary          ( -- )        Sets base to 2
 +
        decimal        ( -- )        Sets base to 10
 +
        hex            ( -- )        Sets base to 16
 +
        base            ( -- a-addr ) Base variable address
 +
</pre>
 +
 
 +
== Memory access ==
 +
(subtle differences to ANS, special cpu-specific extensions)
 +
 
 +
<pre>
 +
        move            ( c-addr1 c-addr2 u -- ) Moves u Bytes in Memory
 +
        fill            ( c-addr u c )          Fill u Bytes of Memory with value c
 +
 
 +
        cbit@          ( mask c-addr -- flag )  Test BIts in byte-location
 +
        bit@            ( mask a-addr -- flag )  Test BIts in word-location
 +
 
 +
        cxor!          ( mask c-addr -- )      Toggle bits in byte-location
 +
        xor!            ( mask a-addr -- )      Toggle bits in word-location
 +
 
 +
        cbic!          ( mask c-addr -- )      Clear Bits in byte-location
 +
        bic!            ( mask a-addr -- )      Clear Bits in word-location
 +
 
 +
        cbis!          ( mask c-addr -- )      Set Bits in byte-location
 +
        bis!            ( mask a-addr -- )      Set Bits in word-location
 +
 
 +
        2constant name  ( ud|d -- )              Makes a double constant.
 +
        constant  name  ( u|n -- )              Makes a single constant.
 +
        2variable name  ( ud|d -- )              Makes an initialized double variable
 +
        variable  name  ( n|n -- )              Makes an initialized single variable
 +
        nvariable name  ( n1*u|n n1 -- )        Makes an initialized variable with specified size of n1 words. Maximum is 15 words
 +
 
 +
        buffer: name    ( u -- )                Creates a buffer in RAM with u bytes length
 +
 
 +
        2@              ( a-addr -- ud|d )      Fetches double number from memory
 +
        2!              ( ud|d a-addr -- )      Stores double number in memory
 +
 
 +
        @              ( a-addr -- u|n )        Fetches single number from memory
 +
        !              ( u|n a-addr -- )        Stores single number in memory
 +
        +!              ( u|n a-addr -- )        Add to memory location
 +
 
 +
        c@              ( c-addr -- char )      Fetches byte from memory
 +
        c!              ( char c-addr )          Stores byte in memory
 +
        c+!            ( u|n a-addr -- )        Add to byte memory location
 +
</pre>
 +
 
 +
== Strings and beautiful output ==
 +
(exactly ANS, some logical extensions)
 +
 
 +
=== String routines ===
 +
<pre>
 +
        type            ( c-addr length -- )                    Prints a counted string.
 +
        s" Hello"      ( -- c-addr length )                    Compiles a string and gives back its address and length when executed.
 +
        ." Hello"      ( -- )                                  Compiles a string and prints it when executed.
 +
        cr              ( -- )                                  Emits line feed
 +
        bl              ( -- 32 )                                ASCII code for Space
 +
        space          ( -- )                                  Emits space
 +
        spaces          ( n -- )                                Emits n spaces if n is positive
 +
 
 +
        compare        ( caddr-1 len-1 c-addr-2 len-2 -- flag ) Compares two strings
 +
 
 +
        accept          ( c-addr maxlength -- length )          Read input into a string.
 +
</pre>
 +
 
 +
=== Counted string routines ===
 +
<pre>
 +
        ctype          ( cstr-addr -- )                        Prints a counted string.
 +
        c" Hello"      ( -- cstr-addr )                        Compiles a counted string and gives back its address when executed.
 +
        cexpect        ( cstr-addr maxlength -- )              Read input into a counted string.
 +
        count          ( cstr-addr -- c-addr length )          Convert counted string into addr-length string
 +
        skipstring      ( cstr-addr -- a-addr )                  Increases the pointer to the aligned end of the string.
 +
</pre>
 +
 
 +
=== Pictured numerical output ===
 +
<pre>
 +
        .digit          ( u -- char )              Converts a digit to a char
 +
        digit          ( char -- u true | false ) Converts a char to a digit
 +
        [char] *                                  Compiles code of following char ( -- char ) when executed
 +
 
 +
        char *          ( -- char )                Gives code of following char
 +
        hold            ( char -- )                Adds character to pictured number output buffer from the front.
 +
        sign            ( n -- )                  Add a minus sign to pictured number output buffer, if n is negative
 +
 
 +
        #S              ( ud1|d1 -- 0 0 )          Add all remaining digits from the double length number to output buffer
 +
        #              ( ud1|d1 -- ud2|d2 )      Add one digit from the double length number to output buffer
 +
        #>              ( ud|d -- c-addr len )    Drops double-length number and finishes pictured numeric output ready for type
 +
        <#              ( -- )                    Prepare pictured number output buffer
 +
        u.              ( u -- )                  Print unsigned single number
 +
        .              ( n -- )                  Print single number
 +
        ud.            ( ud -- )                  Print unsigned double number
 +
        d.              ( d -- )                  Print double number
 +
</pre>
 +
 
 +
=== Deep insights ===
 +
<pre>
 +
        words          ( -- )          Prints list of defined words.
 +
        .s              ( many -- many ) Prints stack contents, signed
 +
        u.s            ( many -- many ) Prints stack contents, unsigned
 +
        h.s            ( many -- many ) Prints stack contents, unsigned, hex
 +
        hex.            ( u -- )        Prints unsigned single number in hex base, needs emit only. This is independent of number subsystem.
 +
</pre>
 +
 
 +
== User input and its interpretation ==
 +
(exactly ANS, some logical extensions)
 +
 
 +
<pre>
 +
        query          ( -- )                      Fetches user input to input buffer
 +
        tib            ( -- cstr-addr )            Input buffer
 +
 
 +
        current-source  ( -- addr )                Double-Variable which contains source
 +
        setsource      ( c-addr len -- )          Change source
 +
        source          ( -- c-addr len )          Current source
 +
        >in            ( -- addr )                Variable with current offset into source
 +
 
 +
        token          ( -- c-addr len )          Cuts one token out of input buffer
 +
        parse          ( char -- c-addr len )      Cuts anything delimited by char out of input buffer
 +
 
 +
        evaluate        ( any addr len -- any )    Interpret given string
 +
        interpret      ( any -- any )              Execute, compile, fold, optimize...
 +
        quit            ( many -- ) (R: many -- )   Resets Stacks
 +
        hook-quit      ( -- a-addr )              Hook for changing the inner quit loop
 +
</pre>
 +
 
 +
== Dictionary expansion ==
 +
(exactly ANS, some logical extensions)
 +
<pre>
 +
        align          ( -- ) Aligns dictionary pointer
 +
        aligned        ( c-addr -- a-addr ) Advances to next aligned address
 +
        cell+          ( x -- x+4 ) Add size of one cell
 +
        cells          ( n -- 4*n ) Calculate size of n cells
 +
 
 +
        allot          ( n -- ) Tries to advance Dictionary Pointer by n bytes
 +
                                Aborts, if not enough space available
 +
        here            ( -- a-addr|c-addr )
 +
                        Gives current position in Dictionary
 +
 
 +
        ,               ( u|n -- ) Appends a single number to dictionary
 +
 
 +
        compiletoram?  ( -- ? ) Currently compiling into ram ?
 +
        compiletoram    ( -- ) Makes ram   the target for compiling
 +
        compiletoflash  ( -- ) Makes flash the target for compiling
 +
</pre>
 +
 
 +
== Flags and inventory ==
 +
(speciality!)
 +
 
 +
<pre>
 +
        smudge          ( -- ) Makes current definition visible, burns
 +
                              collected flags to flash and
 +
                              takes care of proper ending
 +
        inline          ( -- ) Makes current definition inlineable.
 +
                              For flash, place it inside your definition !
 +
        immediate      ( -- ) Makes current definition immediate.
 +
                              For flash, place it inside your definition !
 +
        compileonly    ( -- ) Makes current definition compileonly.
 +
                              For flash, place it inside your definition !
 +
        setflags        ( char -- ) Sets Flags with a mask. This isn't immediate,
 +
                              but for flash, place it inside your definition !
 +
        (create) name  ( -- ) Creates and links a new invisible dictionary
 +
                              header that does nothing.
 +
                              Use FIG-style <builds .. does> !
 +
        find            ( c-addr len -- a-addr flags )
 +
                              Searches for a String in Dictionary.
 +
                              Gives back flags, which are different to ANS !
 +
 
 +
        0-foldable      ( -- ) Current word becomes foldable with zero constants
 +
        1-foldable      ( -- ) Current word becomes foldable with one constants
 +
        2-foldable      ( -- ) Current word becomes foldable with two constants
 +
        3-foldable      ( -- ) Current word becomes foldable with 3  constants
 +
            ...
 +
        7-foldable      ( -- ) Current word becomes foldable with 7  constants
 +
</pre>
 +
 
 +
== Compiler essentials ==
 +
(subtle differences to ANS)
 +
 
 +
<pre>
 +
        execute        ( a-addr -- )              Calls subroutine
 +
        recurse        ( -- )                    Lets the current definition call itself
 +
        ' name          ( -- a-addr )              Tries to find name in dictionary gives back executable address
 +
        ['] name        ( -- a-addr)              Tick that compiles the executable address of found word as literal
 +
        postpone name  ( -- )                    Helps compiling immediate words.
 +
        does>          ( -- ) executes: ( -- a-addr )    Gives address to where you have stored data.
 +
        <builds        ( -- )                    Makes Dictionary header and reserves space for special call.
 +
        create name    ( -- )                    Create a definition with default action which cannot be changed later. Use <builds does> instead.
 +
                                                  Equivalent to : create <builds does> ;
 +
 
 +
        state          ( -- a-addr )              Address of state variable
 +
        ]              ( -- )                    Switch to compile state
 +
        [              ( -- )                    Switch to execute state
 +
        ;               ( -- )                    Finishes new definition
 +
        : name          ( -- )                    Opens new definition
 +
</pre>
 +
 
 +
== Control structures ==
 +
(exactly ANS)
 +
Internally, they have complicated compile-time stack effects.
 +
 
 +
=== if/else/then ===
 +
 
 +
<pre>
 +
flag if ... then
 +
flag if ... else ... then
 +
 
 +
        then            ( -- )          This is the common
 +
        else            ( -- )          flag if ... [else ...] then
 +
        if              ( flag -- )      structure.
 +
</pre>
 +
 
 +
=== case ===
 +
<pre>
 +
n case
 +
    m1   of ... endof
 +
    m2  .. ... .....
 +
  flag  ?of ... endof
 +
    all others
 +
  endcase
 +
 
 +
        case            ( n -- n )      Begins case structure
 +
        of              ( m -- )        Compares m with n, choose this if n=m
 +
        ?of            ( flag -- )      Flag-of, for custom comparisions
 +
        endof          ( -- )          End of one possibility
 +
        endcase        ( n -- )        Ends case structure, discards n
 +
</pre>
 +
 
 +
=== Indefinite Loops ===
 +
<pre>
 +
begin ... again
 +
begin ... flag until
 +
begin ... flag while ... repeat
 +
 
 +
        repeat          ( -- )        Finish of a middle-flag-checking loop.
 +
        while          ( flag -- )    Check a flag in the middle of a loop
 +
 
 +
        begin          ( -- )
 +
        until          ( flag -- )    begin ... flag until    loops as long flag is true
 +
        again          ( -- )        begin ... again        is an endless loop
 +
 
 +
</pre>
 +
 
 +
=== Definite Loops ===
 +
<pre>
 +
limit index   do ... [one or more leave(s)] ... loop
 +
            ?do ... [one or more leave(s)] ... loop
 +
              do ... [one or more leave(s)] ... n +loop
 +
            ?do ... [one or more leave(s)] ... n +loop
 +
 
 +
 
 +
        k              ( -- u|n ) Gives third  loop index
 +
        j              ( -- u|n ) Gives second loop index
 +
        i              ( -- u|n ) Gives innermost loop index
 +
 
 +
 
 +
        unloop          (R: old-limit old-index -- )
 +
                        Drops innermost loop structure,
 +
                        pops back old loop structures to loop registers
 +
 
 +
        exit            ( -- ) Returns from current definition.
 +
                              Compiles a ret opcode.
 +
 
 +
        leave          ( -- ) (R: old-limit old-index -- )
 +
                        Leaves current innermost loop promptly
 +
 
 +
        +loop          ( u|n -- )
 +
                        (R: unchanged | old-limit old-index -- )
 +
                        Adds number to current loop index register
 +
                        and checks whether to continue or not
 +
 
 +
        loop            ( -- )
 +
                        (R: unchanged | old-limit old-index -- )
 +
                        Increments current loop index register by one
 +
                        and checks whether to continue or not.
 +
 
 +
        ?do            ( Limit Index -- )
 +
                        (R: unchanged | -- old-limit old-index )
 +
                        Begins a loop if limit and index are not equal
 +
 
 +
        do              ( Limit Index -- )
 +
                        (R: -- old-limit old-index )
 +
                        Begins a loop
 +
</pre>
 +
 
 +
== Common Hardware access ==
 +
(speciality!)
 +
<pre>
 +
        reset          ( -- ) Reset on hardware level
 +
        dint            ( -- ) Disables Interrupts
 +
        eint            ( -- ) Enables  Interrupts
 +
        eint?          ( -- ) Are Interrupts enabled ?
 +
        nop            ( -- ) No Operation. Hook for unused handlers !
 +
</pre>
 +
 
 +
= FreeRTOS integration =
 +
<pre>
 +
/osThreadAttr
 +
thName+
 +
thAttrBits+
 +
thCbMem+
 +
thCbSize+
 +
thStackMem+
 +
thStackSize+
 +
thPriority+
 +
thTzModule+
 +
/osEventFlagsAttr
 +
/osMessageQueueAttr
 +
/osMutexAttr
 +
/osSemaphoreAttr
 +
osKernelGetTickCount
 +
osKernelGetTickFreq
 +
osKernelGetSysTimerCount
 +
osKernelGetSysTimerFreq
 +
osDelay
 +
osDelayUntil
 +
osThreadNew
 +
osThreadGetId
 +
osThreadGetState
 +
osThreadGetName
 +
osThreadSetPriority
 +
osThreadGetPriority
 +
osThreadYield
 +
osThreadSuspend
 +
osThreadResume
 +
osThreadExit
 +
osThreadTerminate
 +
osThreadGetStackSpace
 +
osThreadGetCount
 +
osThreadEnumerate
 +
xPortGetFreeHeapSize
 +
pvPortMalloc
 +
vPortFree
 +
vTaskSetThreadLocalStoragePointer
 +
pvTaskGetThreadLocalStoragePointer
 +
osThreadFlagsSet
 +
osThreadFlagsClear
 +
osThreadFlagsGet
 +
osThreadFlagsWait
 +
osTimerNew
 +
osTimerGetName
 +
osTimerStart
 +
osTimerStop
 +
osTimerIsRunning
 +
osTimerDelete
 +
osEventFlagsNew
 +
osEventFlagsSet
 +
osEventFlagsClear
 +
osEventFlagsGet
 +
osEventFlagsWait
 +
osEventFlagsDelete
 +
osMutexNew
 +
osMutexAcquire
 +
osMutexRelease
 +
osMutexGetOwner
 +
osMutexDelete
 +
osSemaphoreNew
 +
osSemaphoreAcquire
 +
osSemaphoreRelease
 +
osSemaphoreGetCount
 +
osSemaphoreDelete
 +
osMessageQueueNew
 +
osMessageQueuePut
 +
osMessageQueueGet
 +
osMessageQueueGetCapacity
 +
osMessageQueueGetMsgSize
 +
osMessageQueueGetCount
 +
osMessageQueueGetSpace
 +
osMessageQueueReset
 +
osMessageQueueDelete
 +
</pre>
 +
 
 +
= Pre-loaded for Colibri MCU1 =
 +
<pre>
 +
sm7391-pressure
 +
sm7391-rd
 +
sm7391-raw
 +
sm7391-init
 +
SM7391.ADDR
 +
ring>
 +
>ring
 +
ring?
 +
ring#
 +
ring-step
 +
c++@
 +
init-ring
 +
crc16
 +
crc16h
 +
crc16@
 +
crc16-table
 +
buffer.
 +
buffer-cpy
 +
stack>buffer
 +
spi!ssel
 +
fix-ssel
 +
spiN>
 +
>spiN
 +
spi2>
 +
>spi2
 +
spi-push0
 +
spi-push
 +
spi-rxdrop
 +
spi-rxrdy
 +
spi-txrdy
 +
spi1>dr
 +
>spi
 +
spi>
 +
>spi>
 +
-spi
 +
+spi
 +
spi?
 +
SPI1-DR
 +
SPI1-SR
 +
SPI1-CR2
 +
SPI1-CR1
 +
SPI1
 +
ssel.bit
 +
ssel.addr
 +
MOSI
 +
MISO
 +
SCLK
 +
ssel
 +
i2c-inspect
 +
i2c-xfer
 +
i2c-rd
 +
i2c-wr
 +
i2c-setn
 +
i2c-stop
 +
i2c-start
 +
i2c>h
 +
i2c>
 +
>i2c
 +
i2c++
 +
i2c-addr
 +
i2c-reset
 +
i2c.ptr
 +
i2c.buf
 +
i2c.
 +
I2C2-TXDR
 +
I2C2-RXDR
 +
I2C2-ICR
 +
I2C2-ISR
 +
I2C2-TIMINGR
 +
I2C2-CR2
 +
I2C2-CR1
 +
I2C2
 +
SDA
 +
SCL
 +
PA15
 +
PA14
 +
PA13
 +
PB12
 +
PA12
 +
PA11
 +
PA10
 +
PA9
 +
PA8
 +
PB7
 +
PA7
 +
PB6
 +
PA6
 +
PB5
 +
PA5
 +
PB4
 +
PA4
 +
PB3
 +
PA3
 +
PB2
 +
PA2
 +
PA1
 +
PA0
 +
io.
 +
io-mode!
 +
io-config
 +
OMODE-FAST
 +
OMODE-SLOW
 +
OMODE-WEAK
 +
OMODE-OD
 +
OMODE-PP
 +
OMODE-AF-OD
 +
OMODE-AF-PP
 +
IMODE-ADC
 +
IMODE-LOW
 +
IMODE-HIGH
 +
IMODE-FLOAT
 +
iox!
 +
io!
 +
ioc!
 +
ios!
 +
io@
 +
io-base
 +
io-port
 +
io-mask
 +
io#
 +
io
 +
bit!
 +
bit
 +
GPIO.AFRH
 +
GPIO.AFRL
 +
GPIO.BSRR
 +
GPIO.ODR
 +
GPIO.IDR
 +
GPIO.PUPDR
 +
GPIO.OSPEEDR
 +
GPIO.OTYPER
 +
GPIO.MODER
 +
GPIO-BASE
 +
dump
 +
dump16
 +
hexdump
 +
hex.empty
 +
h.2
 +
h.4
 +
u.2
 +
u.4
 +
.v
 +
[ifndef]
 +
[ifdef]
 +
[if]
 +
[then]
 +
[else]
 +
[else-match]
 +
nexttoken
 +
</pre>

Latest revision as of 12:12, 22 August 2023


Colibri Forth is built upon MECRISP (https://mecrisp.sourceforge.net, written by Matthias Koch), the Stellaris variant, an advanced Forth, that compiles to machine code on the target itself, for optimal performance. Additional work/inspiration has been source from Peter Schmid's Mecrisp-Cube project (https://github.com/spyren/Mecrisp-Cube).

Architecture

Forth is a stack-oriented language that has 2 stacks, one for data and one call stack for with return addresses. It has very simple syntactic rules;

1. Everything is a "word" which must be surrounded by whitespace. All non-whitespace bytes are allowed in word. 1. Backslash is start of comment, and everything will be filtered out until parser reaches new line. 1. Everything between a pair of parentheses " ( xyz ) " is a comment. They can be stretching multiple lines. Nested parentheses are not supported. 1. Thereafter, try to locate word in dictionary. If found, "use" (depends on whether compiling or executing) it. 1. If word is not found in dictionary, try to parse it as a number. If successful, push number on stack. 1. All words operate on the stacks. Typically manipulating the Top-Of-Stack (TOS), by popping value(s) off the top and pushing the result back on top. 1. Forth is NOT a unified/standardized language and except for a small number of core words, there is no consensus of what the base vocabulary is. Many think that the nearest a standard (ANS Forth) is too bloated and not suitable for all the target devices that a more lean Forth can run on. This means that many libraries won't work out-of-the-box and will require tweaking by the user.


Colon ":" is the word to define other words, and the definition ends with semicolon ";". Example

 : add4 4 + ;  \ adds 4 to the value on TOS.

It is common to put the stack manipulation info as a comment after the defined word. Example

 : add4 ( n -- n+4 ) 4 + ;

It is the same thing, just human-readable comment to hint at what the word does.

The Full Documentation of Mecrisp is written by Terry Porter and published at https://mecrisp-stellaris-folkdoc.sourceforge.io/

Mecrisp and Colibri Forth are not case-sensitive, but many other Forth variants are.

Interactivity

Forth is an interactive language, which is awesome for embedded development. One can simply hook up a serial terminal and do development on the target itself. One can interactively work with the MCU registers and peripherals to figure out the proper configuration/operation without doing a full erase+write cycle to the flash memory. We can execute code directly from RAM and not commit it to Flash until we have worked out the details.

Cookbook

We are going to assemble useful snippets and words that will be useful, but not common enough to be included in the standard vocabulary. We call this the Colibri Forth Cookbook and will be a slowly growing document of Forth for the Colibri family.

Resources

https://mecrisp-stellaris-folkdoc.sourceforge.io/ https://www.spyr.ch/twiki/bin/view/MecrispCube

Default Word List

(Courtesy Matthias Koch, https://mecrisp.sourceforge.net/glossary.htm)

Terminal-IO

(exactly ANS, some logical extensions)

        emit?           ( -- Flag ) Ready to send a character ?
        key?            ( -- Flag ) Checks if a key is waiting
        key             ( -- Char ) Waits for and fetches the pressed key
        emit            ( Char -- ) Emits a character.

        hook-emit?      ( -- a-addr ) Hooks for redirecting
        hook-key?       ( -- a-addr )   terminal IO
        hook-key        ( -- a-addr )     on the fly
        hook-emit       ( -- a-addr )

        serial-emit?    ( -- Flag )  Serial interface
        serial-key?     ( -- Flag )    terminal routines
        serial-key      ( -- Char )      as default communications
        serial-emit     ( Char -- )

        hook-pause      ( -- a-addr ) Hook for a multitasker
        pause           ( -- )        Task switch, none for default

Stack Jugglers

(exactly ANS, some logical extensions)

Single-Jugglers

        depth           ( -- +n ) Gives number of single-cell stack items.
        nip             ( x1 x2 -- x2 )
        drop            ( x -- )
        rot             ( x1 x2 x3 -- x2 x3 x1 )
        -rot            ( x1 x2 x3 -- x3 x1 x2 )
        swap            ( x1 x2 -- x2 x1 )
        tuck            ( x1 x2 -- x2 x1 x2 )
        over            ( x1 x2 -- x1 x2 x1 )
        ?dup            ( x -- 0 | x x )
        dup             ( x -- x x )
        pick            ( ... xi+1 xi ... x1 x0 i -- ... x1 x0 xi )
                                  Picks one element from deep below

        >r              ( x -- ) (R: -- x )
        r>              ( -- x ) (R: x -- )
        r@              ( -- x ) (R: x -- x )
        rdrop           (  --  ) (R: x -- )
        rdepth          ( -- +n ) Gives number of return stack items.
        rpick           ( i -- xi ) R: ( ... xi ... x0 -- ... xi ... x0 )

Double-Jugglers

They perform the same for double numbers.

        2nip            ( x1 x2 x3 x4 -- x3 x4 )
        2drop           ( x1 x2 -- )
        2rot            ( x1 x2 x3 x4 x5 x6 -- x3 x4 x5 x6 x1 x2 )
        2-rot           ( x1 x2 x3 x4 x5 x6 -- x5 x6 x1 x2 x3 x4 )
        2swap           ( x1 x2 x3 x4 -- x3 x4 x1 x2 )
        2tuck           ( x1 x2 x3 x4 -- x3 x4 x1 x2 x3 x4 )
        2over           ( x1 x2 x3 x4 -- x1 x2 x3 x4 x1 x2 )
        2dup            ( x1 x2 -- x1 x2 x1 x2 )

        2>r             ( x1 x2 -- ) (R: -- x1 x2 )
        2r>             ( -- x1 x2 ) (R: x1 x2 -- )
        2r@             ( -- x1 x2 ) (R: x1 x2 -- x1 x2 )
        2rdrop          ( -- )       (R: x1 x2 -- )

Stack pointers

        sp@             ( -- a-addr )  Fetch  data stack pointer
        sp!             ( a-addr -- )  Store  data stack pointer
        rp@             ( -- a-addr )  Fetch return stack pointer
        rp!             ( a-addr -- )  Store return stack pointer

Logic

(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
        shr             ( x1 -- x2 )   Logical right-shift of one bit-place
        shl             ( x1 -- x2 )   Logical  left-shift of one bit-place
        ror             ( x1 -- x2 )   Logical right-rotation of one bit-place
        rol             ( x1 -- x2 )   Logical  left-rotation of one bit-place
        bic             ( x1 x2 -- x3 ) Bit clear, identical to "not and"
        not             ( x1 -- x2 )   Invert all bits
        xor             ( x1 x2 -- x3 ) Bitwise Exclusive-OR
        or              ( x1 x2 -- x3 ) Bitwise OR
        and             ( x1 x2 -- x3 ) Bitwise AND
        false           ( --  0 ) False-Flag
        true            ( -- -1 ) True-Flag
        clz             ( x1 -- u ) Count leading zeros

Calculus for single numbers

(exactly ANS, some logical extensions)

        u/mod           ( u1 u2 -- u3 u4 ) u1/u2 = u4 rem u3 Division
        /mod            ( n1 n2 -- n3 n4 ) n1 / n2 = n4 rem n3
        mod             ( n1 n2 -- n3 ) n1 / n2 = remainder n3
        /               ( n1 n2 -- n3 ) n1 / n2 = n3
        *               ( u1|n1 u2|n2 -- u3|n3 ) Single Multiplication
        min             ( n1 n2 -- n1|n2 ) Keeps smaller of top two items
        max             ( n1 n2 -- n1|n2 ) Keeps greater of top two items
        umin            ( u1 u2 -- u1|u2 ) Keeps unsigned smaller
        umax            ( u1 u2 -- u1|u2 ) Keeps unsigned greater
        2-              ( u1|n1 -- u2|n2 ) Subtracts two, optimized
        1-              ( u1|n1 -- u2|n2 ) Subtracts one, optimized
        2+              ( u1|n1 -- u2|n2 ) Adds two, optimized
        1+              ( u1|n1 -- u2|n2 ) Adds one, optimized
        even            ( u1|n1 -- u2|n2 ) Makes even. Adds one if uneven.
        2*              ( n1 -- n2 ) Arithmetric  left-shift
        2/              ( n1 -- n2 ) Arithmetric right-shift
        abs             ( n -- u ) Absolute value
        negate          ( n1 -- n2 ) Negate
        -               ( u1|n1 u2|n2 -- u3|n3 ) Subtraction
        +               ( u1|n1 u2|n2 -- u3|n3 ) Addition

Calculus involving double numbers

(exactly ANS, some logical extensions)

        um*             ( u1 u2 -- ud )                 u1 * u2 = ud
        udm*            ( ud1 ud2 -- ud3-Low ud4-High ) ud1 * ud2 = ud3-Low ud4-High

        um/mod          ( ud u1 -- u2 u3 )              ud / u1 = u3 remainder u2
        ud/mod          ( ud1 ud2 -- ud3 ud4 )          ud1/ud2 = ud4 rem ud3

        m*              ( n1 n2 -- d )                  n1 * n2 = d
        m/mod           ( d  n1 -- n2 n3 )              d  / n1 = n3 remainder r2

        */              ( n1 n2 n3 -- n4 )              n1 * n2 / n3 = n4
        u*/             ( u1 u2 u3 -- u4 )              u1 * u2 / u3 = u4
        */mod           ( n1 n2 n3 -- n4 n5 )           n1 * n2 / n3 = n5 remainder n4

        d2*             ( d1 -- d2 )                    Arithmetric  left-shift
        d2/             ( d1 -- d2 )                    Arithmetric right-shift
        dshl            ( ud1 -- ud2 )                  Logical left-shift, same as d2*
        dshr            ( ud1 -- ud2 )                  Logical right-shift (shifts in a zero in left-most bit)

        dabs            ( d -- ud )                     Absolute value
        dnegate         ( d1 -- d2 )                    Negate
        d-              ( ud1|d1 ud2|d2 -- ud3|d3 )     Subtraction
        d+              ( ud1|d1 ud2|d2 -- ud3|d3 )     Addition
        s>d             ( n -- d )                      Makes a signed single number double length

Comparisions

(exactly ANS, some logical extensions)

Single-Comparisons

        u<=             ( u1 u2 -- flag )  Unsigned comparisons, u1 <= u2
        u>=             ( u1 u2 -- flag )
        u>              ( u1 u2 -- flag )
        u<              ( u1 u2 -- flag )
        <=              ( n1 n2 -- flag )  Signed comparisons
        >=              ( n1 n2 -- flag )
        >               ( n1 n2 -- flag )
        <               ( n1 n2 -- flag )
        0<              ( n - flag )       Negative ?
        0<>             ( x -- flag )      Not 0
        0=              ( x -- flag )      Zero?
        <>              ( x1 x2 -- flag )
        =               ( x1 x2 -- flag )

Double-Comparisons

They perform the same for double numbers.

        du>             ( ud1 ud2 -- flag )
        du<             ( ud1 ud2 -- flag )
        d>              ( d1 d2 -- flag )
        d<              ( d1 d2 -- flag )
        d0<             ( d -- flag )
        d0=             ( d -- flag )
        d<>             ( d1 d2 -- flag )
        d=              ( d1 d2 -- flag )

Tools

(not only) for double fixed point numbers (specialty!)

Fixpoint numbers are stored ( n-comma n-whole ) and can be handled like signed double numbers.

        f/              ( df1 df2 -- df3 )        Division of two fixpoint numbers
        f*              ( df1 df2 -- df3 )        Multiplication

        hold<           ( char -- )               Adds character to pictured number output buffer from behind.
        f#S             ( n-comma1 -- n-comma2 )  Adds all comma-digits to number output
        f#              ( n-comma1 -- n-comma2 )  Adds one comma-digit to number output
        f.              ( df -- )                 Prints a fixpoint number with all fractional digits
        f.n             ( df n -- )               Prints a fixpoint number with n fractional digits

        number          ( c-addr length -- 0 )
                                        -- n 1 )
                                        -- n-low n-high 2 )
                        Tries to convert a string to a number.

Number base

(exactly ANS)

        binary          ( -- )        Sets base to 2
        decimal         ( -- )        Sets base to 10
        hex             ( -- )        Sets base to 16
        base            ( -- a-addr ) Base variable address

Memory access

(subtle differences to ANS, special cpu-specific extensions)

        move            ( c-addr1 c-addr2 u -- ) Moves u Bytes in Memory
        fill            ( c-addr u c )           Fill u Bytes of Memory with value c

        cbit@           ( mask c-addr -- flag )  Test BIts in byte-location
        bit@            ( mask a-addr -- flag )  Test BIts in word-location

        cxor!           ( mask c-addr -- )       Toggle bits in byte-location
        xor!            ( mask a-addr -- )       Toggle bits in word-location

        cbic!           ( mask c-addr -- )       Clear Bits in byte-location
        bic!            ( mask a-addr -- )       Clear Bits in word-location

        cbis!           ( mask c-addr -- )       Set Bits in byte-location
        bis!            ( mask a-addr -- )       Set Bits in word-location

        2constant name  ( ud|d -- )              Makes a double constant.
        constant  name  ( u|n -- )               Makes a single constant.
        2variable name  ( ud|d -- )              Makes an initialized double variable
        variable  name  ( n|n -- )               Makes an initialized single variable
        nvariable name  ( n1*u|n n1 -- )         Makes an initialized variable with specified size of n1 words. Maximum is 15 words

        buffer: name    ( u -- )                 Creates a buffer in RAM with u bytes length

        2@              ( a-addr -- ud|d )       Fetches double number from memory
        2!              ( ud|d a-addr -- )       Stores double number in memory

        @               ( a-addr -- u|n )        Fetches single number from memory
        !               ( u|n a-addr -- )        Stores single number in memory
        +!              ( u|n a-addr -- )        Add to memory location

        c@              ( c-addr -- char )       Fetches byte from memory
        c!              ( char c-addr )          Stores byte in memory
        c+!             ( u|n a-addr -- )        Add to byte memory location

Strings and beautiful output

(exactly ANS, some logical extensions)

String routines

        type            ( c-addr length -- )                     Prints a counted string.
        s" Hello"       ( -- c-addr length )                     Compiles a string and gives back its address and length when executed.
        ." Hello"       ( -- )                                   Compiles a string and prints it when executed.
        cr              ( -- )                                   Emits line feed
        bl              ( -- 32 )                                ASCII code for Space
        space           ( -- )                                   Emits space
        spaces          ( n -- )                                 Emits n spaces if n is positive

        compare         ( caddr-1 len-1 c-addr-2 len-2 -- flag ) Compares two strings

        accept          ( c-addr maxlength -- length )           Read input into a string.

Counted string routines

        ctype           ( cstr-addr -- )                         Prints a counted string.
        c" Hello"       ( -- cstr-addr )                         Compiles a counted string and gives back its address when executed.
        cexpect         ( cstr-addr maxlength -- )               Read input into a counted string.
        count           ( cstr-addr -- c-addr length )           Convert counted string into addr-length string
        skipstring      ( cstr-addr -- a-addr )                  Increases the pointer to the aligned end of the string.

Pictured numerical output

        .digit          ( u -- char )              Converts a digit to a char
        digit           ( char -- u true | false ) Converts a char to a digit
        [char] *                                   Compiles code of following char ( -- char ) when executed

        char *          ( -- char )                Gives code of following char
        hold            ( char -- )                Adds character to pictured number output buffer from the front.
        sign            ( n -- )                   Add a minus sign to pictured number output buffer, if n is negative

        #S              ( ud1|d1 -- 0 0 )          Add all remaining digits from the double length number to output buffer
        #               ( ud1|d1 -- ud2|d2 )       Add one digit from the double length number to output buffer
        #>              ( ud|d -- c-addr len )     Drops double-length number and finishes pictured numeric output ready for type
        <#              ( -- )                     Prepare pictured number output buffer
        u.              ( u -- )                   Print unsigned single number
        .               ( n -- )                   Print single number
        ud.             ( ud -- )                  Print unsigned double number
        d.              ( d -- )                   Print double number

Deep insights

        words           ( -- )           Prints list of defined words.
        .s              ( many -- many ) Prints stack contents, signed
        u.s             ( many -- many ) Prints stack contents, unsigned
        h.s             ( many -- many ) Prints stack contents, unsigned, hex
        hex.            ( u -- )         Prints unsigned single number in hex base, needs emit only. This is independent of number subsystem.

User input and its interpretation

(exactly ANS, some logical extensions)

        query           ( -- )                      Fetches user input to input buffer
        tib             ( -- cstr-addr )            Input buffer

        current-source  ( -- addr )                 Double-Variable which contains source
        setsource       ( c-addr len -- )           Change source
        source          ( -- c-addr len )           Current source
        >in             ( -- addr )                 Variable with current offset into source

        token           ( -- c-addr len )           Cuts one token out of input buffer
        parse           ( char -- c-addr len )      Cuts anything delimited by char out of input buffer

        evaluate        ( any addr len -- any )     Interpret given string
        interpret       ( any -- any )              Execute, compile, fold, optimize...
        quit            ( many -- ) (R: many -- )   Resets Stacks
        hook-quit       ( -- a-addr )               Hook for changing the inner quit loop

Dictionary expansion

(exactly ANS, some logical extensions)

        align           ( -- ) Aligns dictionary pointer
        aligned         ( c-addr -- a-addr ) Advances to next aligned address
        cell+           ( x -- x+4 ) Add size of one cell
        cells           ( n -- 4*n ) Calculate size of n cells

        allot           ( n -- ) Tries to advance Dictionary Pointer by n bytes
                                 Aborts, if not enough space available
        here            ( -- a-addr|c-addr )
                        Gives current position in Dictionary

        ,               ( u|n -- ) Appends a single number to dictionary

        compiletoram?   ( -- ? ) Currently compiling into ram ?
        compiletoram    ( -- ) Makes ram   the target for compiling
        compiletoflash  ( -- ) Makes flash the target for compiling

Flags and inventory

(speciality!)

        smudge          ( -- ) Makes current definition visible, burns
                               collected flags to flash and
                               takes care of proper ending
        inline          ( -- ) Makes current definition inlineable.
                               For flash, place it inside your definition !
        immediate       ( -- ) Makes current definition immediate.
                               For flash, place it inside your definition !
        compileonly     ( -- ) Makes current definition compileonly.
                               For flash, place it inside your definition !
        setflags        ( char -- ) Sets Flags with a mask. This isn't immediate,
                               but for flash, place it inside your definition !
        (create) name   ( -- ) Creates and links a new invisible dictionary
                               header that does nothing.
                               Use FIG-style <builds .. does> !
        find            ( c-addr len -- a-addr flags )
                               Searches for a String in Dictionary.
                               Gives back flags, which are different to ANS !

        0-foldable      ( -- ) Current word becomes foldable with zero constants
        1-foldable      ( -- ) Current word becomes foldable with one constants
        2-foldable      ( -- ) Current word becomes foldable with two constants
        3-foldable      ( -- ) Current word becomes foldable with 3   constants
            ...
        7-foldable      ( -- ) Current word becomes foldable with 7   constants

Compiler essentials

(subtle differences to ANS)

        execute         ( a-addr -- )              Calls subroutine
        recurse         ( -- )                     Lets the current definition call itself
        ' name          ( -- a-addr )              Tries to find name in dictionary gives back executable address
        ['] name        ( -- a-addr)               Tick that compiles the executable address of found word as literal
        postpone name   ( -- )                     Helps compiling immediate words.
        does>           ( -- ) executes: ( -- a-addr )    Gives address to where you have stored data.
        <builds         ( -- )                     Makes Dictionary header and reserves space for special call.
        create name     ( -- )                     Create a definition with default action which cannot be changed later. Use <builds does> instead.
                                                   Equivalent to : create <builds does> ;

        state           ( -- a-addr )              Address of state variable
        ]               ( -- )                     Switch to compile state
        [               ( -- )                     Switch to execute state
        ;               ( -- )                     Finishes new definition
        : name          ( -- )                     Opens new definition

Control structures

(exactly ANS) Internally, they have complicated compile-time stack effects.

if/else/then

flag if ... then
flag if ... else ... then

        then            ( -- )           This is the common
        else            ( -- )           flag if ... [else ...] then
        if              ( flag -- )      structure.

case

n case
     m1   of ... endof
     m2   .. ... .....
   flag  ?of ... endof
    all others
  endcase

        case            ( n -- n )       Begins case structure
        of              ( m -- )         Compares m with n, choose this if n=m
        ?of             ( flag -- )      Flag-of, for custom comparisions
        endof           ( -- )           End of one possibility
        endcase         ( n -- )         Ends case structure, discards n

Indefinite Loops

begin ... again
begin ... flag until
begin ... flag while ... repeat

        repeat          ( -- )         Finish of a middle-flag-checking loop.
        while           ( flag -- )    Check a flag in the middle of a loop

        begin           ( -- )
        until           ( flag -- )    begin ... flag until    loops as long flag is true
        again           ( -- )         begin ... again         is an endless loop

Definite Loops

limit index   do ... [one or more leave(s)] ... loop
             ?do ... [one or more leave(s)] ... loop
              do ... [one or more leave(s)] ... n +loop
             ?do ... [one or more leave(s)] ... n +loop


        k               ( -- u|n ) Gives third  loop index
        j               ( -- u|n ) Gives second loop index
        i               ( -- u|n ) Gives innermost loop index


        unloop          (R: old-limit old-index -- )
                        Drops innermost loop structure,
                        pops back old loop structures to loop registers

        exit            ( -- ) Returns from current definition.
                               Compiles a ret opcode.

        leave           ( -- ) (R: old-limit old-index -- )
                        Leaves current innermost loop promptly

        +loop           ( u|n -- )
                        (R: unchanged | old-limit old-index -- )
                        Adds number to current loop index register
                        and checks whether to continue or not

        loop            ( -- )
                        (R: unchanged | old-limit old-index -- )
                        Increments current loop index register by one
                        and checks whether to continue or not.

        ?do             ( Limit Index -- )
                        (R: unchanged | -- old-limit old-index )
                        Begins a loop if limit and index are not equal

        do              ( Limit Index -- )
                        (R: -- old-limit old-index )
                        Begins a loop

Common Hardware access

(speciality!)

        reset           ( -- ) Reset on hardware level
        dint            ( -- ) Disables Interrupts
        eint            ( -- ) Enables  Interrupts
        eint?           ( -- ) Are Interrupts enabled ?
        nop             ( -- ) No Operation. Hook for unused handlers !

FreeRTOS integration

/osThreadAttr
thName+
thAttrBits+
thCbMem+
thCbSize+
thStackMem+
thStackSize+
thPriority+
thTzModule+
/osEventFlagsAttr
/osMessageQueueAttr
/osMutexAttr
/osSemaphoreAttr
osKernelGetTickCount
osKernelGetTickFreq
osKernelGetSysTimerCount
osKernelGetSysTimerFreq
osDelay
osDelayUntil
osThreadNew
osThreadGetId
osThreadGetState
osThreadGetName
osThreadSetPriority
osThreadGetPriority
osThreadYield
osThreadSuspend
osThreadResume
osThreadExit
osThreadTerminate
osThreadGetStackSpace
osThreadGetCount
osThreadEnumerate
xPortGetFreeHeapSize
pvPortMalloc
vPortFree
vTaskSetThreadLocalStoragePointer
pvTaskGetThreadLocalStoragePointer
osThreadFlagsSet
osThreadFlagsClear
osThreadFlagsGet
osThreadFlagsWait
osTimerNew
osTimerGetName
osTimerStart
osTimerStop
osTimerIsRunning
osTimerDelete
osEventFlagsNew
osEventFlagsSet
osEventFlagsClear
osEventFlagsGet
osEventFlagsWait
osEventFlagsDelete
osMutexNew
osMutexAcquire
osMutexRelease
osMutexGetOwner
osMutexDelete
osSemaphoreNew
osSemaphoreAcquire
osSemaphoreRelease
osSemaphoreGetCount
osSemaphoreDelete
osMessageQueueNew
osMessageQueuePut
osMessageQueueGet
osMessageQueueGetCapacity
osMessageQueueGetMsgSize
osMessageQueueGetCount
osMessageQueueGetSpace
osMessageQueueReset
osMessageQueueDelete

Pre-loaded for Colibri MCU1

sm7391-pressure
sm7391-rd
sm7391-raw
sm7391-init
SM7391.ADDR
ring>
>ring
ring?
ring#
ring-step
c++@
init-ring
crc16
crc16h
crc16@
crc16-table
buffer.
buffer-cpy
stack>buffer
spi!ssel
fix-ssel
spiN>
>spiN
spi2>
>spi2
spi-push0
spi-push
spi-rxdrop
spi-rxrdy
spi-txrdy
spi1>dr
>spi
spi>
>spi>
-spi
+spi
spi?
SPI1-DR
SPI1-SR
SPI1-CR2
SPI1-CR1
SPI1
ssel.bit
ssel.addr
MOSI
MISO
SCLK
ssel
i2c-inspect
i2c-xfer
i2c-rd
i2c-wr
i2c-setn
i2c-stop
i2c-start
i2c>h
i2c>
>i2c
i2c++
i2c-addr
i2c-reset
i2c.ptr
i2c.buf
i2c.
I2C2-TXDR
I2C2-RXDR
I2C2-ICR
I2C2-ISR
I2C2-TIMINGR
I2C2-CR2
I2C2-CR1
I2C2
SDA
SCL
PA15
PA14
PA13
PB12
PA12
PA11
PA10
PA9
PA8
PB7
PA7
PB6
PA6
PB5
PA5
PB4
PA4
PB3
PA3
PB2
PA2
PA1
PA0
io.
io-mode!
io-config
OMODE-FAST
OMODE-SLOW
OMODE-WEAK
OMODE-OD
OMODE-PP
OMODE-AF-OD
OMODE-AF-PP
IMODE-ADC
IMODE-LOW
IMODE-HIGH
IMODE-FLOAT
iox!
io!
ioc!
ios!
io@
io-base
io-port
io-mask
io#
io
bit!
bit
GPIO.AFRH
GPIO.AFRL
GPIO.BSRR
GPIO.ODR
GPIO.IDR
GPIO.PUPDR
GPIO.OSPEEDR
GPIO.OTYPER
GPIO.MODER
GPIO-BASE
dump
dump16
hexdump
hex.empty
h.2
h.4
u.2
u.4
.v
[ifndef]
[ifdef]
[if]
[then]
[else]
[else-match]
nexttoken