Difference between revisions of "Colibri Forth"
(30 intermediate revisions by the same user not shown) | |||
Line 1: | Line 1: | ||
− | + | [[Category:Colibri]][[Category:Work in progress]]{{metadesc|Colibri Forth}} | |
− | + | 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 | ||
− | + | = 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. | |
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | : ,c 1 , | + | = 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) | ||
+ | <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