Minimal Umbilical code definitions

The file Cortex/MinCortex.fth contains the minimum code definitions required to support Umbilical Forth. If additional words are required, they may be copied to a new file from Cortex/CodeCortex.fth or Common/Kernel62.fth.

Register usage

For Cortex-M3+ the following register usage is the default:


  r15         pc      program counter
  r14         link    link register; bit0=1=Thumb, usually set
  r13         rsp     return stack pointer
  r12         psp     data stack pointer
  r11         up      user area pointer
  r10         --
  r9          lp      locals pointer
  r8          --
  r7          tos     cached top of stack
  r0-r6       scratch

The VFX optimiser reserves R0 and R1 for internal operations. CODE definitions must use R10 as TOS with NOS pointed to by R12 as a full descending stack in ARM terminology. R0..R8 are free for use by CODE definitions and need not be preserved or restored. You should assume that any register can be affected by other words.

Configuration

These equates are set false (zero) if they have not already been defined.

false equ DSQRT?        \ -- flag
Set this non-zero to compile DSQRT.

false equ FastCmove?    \ -- flag
Set this flag true to use a fast but vast (~1kb) version of CMOVE. If your application uses either CMOVE or MOVE in time-critical code, the fast version offers an overall speed up of about four times. The code for the fast but vast version was written by Rowley Associates, whose permission to adapt and publish the code with the MPE cross compiler is much appreciated.

Flow of control

CODE (DO)       \ limit index --
The run time action of DO compiled on the target. INTERNAL.

CODE (?DO)      \ limit index --
The run time action of ?DO compiled on the target. INTERNAL.

CODE EXECUTE    \ xt --
Execute the code described by the XT. This is a Forth equivalent to an assembler JSR/CALL instruction.

Stack operations and maths

CODE NOOP       \ --
A NOOP, null instruction. )

: DROP          \ x --
Lose the top data stack item and promote NOS to TOS.

CODE WITHIN?    \ n1 n2 n3 -- flag
Return TRUE if N1 is within the range N2..N3. This word uses signed arithmetic.

CODE WITHIN     \ n1|u1 n2|u2 n3|u3 -- flag
The ANS version of WITHIN?. This word uses unsigned arithmetic, so that signed compares are treated as existing on a number circle.

Multiplication

: UM*           \ u1 u2 -- ud
Perform unsigned-multiply between two numbers and return double result.

: *             \ n1 n2 -- n3
Standard signed multiply. N3 = n1 * n2.

: m*            \ n1 n2 -- d
Signed multiply yielding double result.

Division

ARM Cortex provides 32/32 division instructions, but no 64/32 ones. Avoid 64/32 division routines if you can where performance matters.

macro: udiv64_step      \ --
Cross compiler macro to perform one step of the unsigned 64 bit by 32 bit division

code um/mod     \ ud1 u2 -- urem uquot
Slow and short - Full 64 by 32 unsigned division subroutine. This routine uses a loop for code size. This version is commented out by default.

code um/mod     \ ud1 u2 -- urem uquot
Fast and big - Full 64 by 32 unsigned division subroutine. Unrolled for speed. This routine uses 660 bytes of code space using the Thumb-2 instruction set, whereas the ARM32 version uses 920 bytes.

macro: udiv63_step      \ --
Cross compiler macro to perform one step of the unsigned 63 bit by 31 bit division

proc Udiv63/31  \ r0:r1/tos ; 63/31 unsigned divide -> tos=quot, r0=rem
Unsigned division primitive - unrolled for speed. Note that this routine does not handle the top bit of the divisor and dividend correctly. Udiv63/31 is used for signed divide operations for which the top bits are always zero.

CODE FM/MOD     \  d1 n2 -- rem quot ; floored division
Perform a signed division of double number D1 by single number N2 and return remainder and quotient using floored division. See the ANS Forth specification for more details of floored division.

CODE SM/REM     \ d1 n2 -- rem quot ; symmetric division
Perform a signed division of double number D1 by single number N2 and return remainder and quotient using symmetric (normal) division.

CODE /MOD       \ n1 n2 -- rem quot
Signed symmetric division of N1 by N2 single-precision returning remainder and quotient.

: /             \ n1 n2  -- n3
Standard signed division operator. n3 = n1/n2.

: MOD           \ n1 n2 -- n3
Return remainder of division of N1 by N2. n3 = n1 mod n2.

: */MOD         \ n1 n2 n3 -- n4 n4
Multiply n1 by n2 to give a double precision result, and then divide it by n3 returning the remainder and quotient. The point of this operation is to avoid loss of precision.

: */            \ n1 n2 n3 -- n4
Multiply n1 by n2 to give a double precision result, and then divide it by n3 returning the quotient. The point of this operation is to avoid loss of precision.

: M/            \ d n1 -- n2
Signed divide of a double by a single integer.

Miscellaneous math

CODE D+         \ d1 d2 -- d3
Add two double precision integers.

CODE D-         \ d1 d2 -- d3
Subtract two double precision integers. D3=D1-D2.

CODE DNEGATE    \ d1 -- -d1
Negate a double number.

CODE ?NEGATE    \ n1 flag -- n1|n2
If flag is negative, then negate n1.

CODE ?DNEGATE   \ d1 flag -- d1|d2
If flag is negative, then negate d1.

CODE ABS        \ n -- u
If n is negative, return its positive equivalent (absolute value).

CODE DABS       \ d -- ud
If d is negative, return its positive equivalent (absolute value).

CODE ROLL       \ xu xu-1 .. x0 u -- xu-1 .. x0 xu
Rotate the order of the top N stack items by one place such that the current top of stack becomes the second item and the Nth item becomes TOS. See also ROT.

Strings

code cmove      \ asrc adest len --
Copy len bytes of memory forwards from asrc to adest. If the performance of CMOVE is important in your application, set the equate FastCmove? non-zero and a much faster (four to five times) but much larger (~900 bytes) version will be compiled. See Cortex\fcmove.fth for the details.

CODE CMOVE>     \ c-addr1 c-addr2 u --
As CMOVE but working in the opposite direction, copying the last character in the string first.

CODE FILL       \ c-addr u char --
Fill LEN bytes of memory starting at ADDR with the byte information specified as CHAR.

: erase         \ c-addr u -- ; wipe memory
Set U bytes of memory starting at C-ADDR with zeros.

CODE S=         \ c-addr1 c-addr2 u -- flag
Compare two same-length strings/memory blocks, returning TRUE if they are identical.

CODE (")        \ -- a-addr ; return address of string, skip over it
Return the address of a counted string that is inline after the CALLING word, and adjust the CALLING word's return address to step over the inline string. The adjusted return address will be at a four byte boundary. See the definition of (.") for an example.

: (C")          \ -- c-addr
The run time action compiled by C".

: (S")          \ -- c-addr u
The run time action compiled by S".

Umbilical versions of defining words

here is-action-of constant
The runtime code for a CONSTANT.

here is-action-of variable
The runtime action for a VARIABLE.

here is-action-of value
The runtime action of a VALUE.

here is-action-of user
The runtime action of a USER variable.

: u#            \ "<name>"-- u
An INTERPRETER word that returns the index of the USER variable whose name follows, e.g.

  u# S0

: CRASH         \ --  ; used as action of DEFER
The default action of a DEFERed word. A NOOP.

here is-action-of DEFER \ Comp: "<spaces>name" -- ; Run: i*x -- j*x
The runtime action of a DEFERred word.

Display words

: SPACE         \ --
Output a blank space (ASCII 32) character.

: SPACES        \ n --
Output 'n' spaces, where 'n' > 0. If 'n' < 0, no action is taken.

: .nibble       \ n --
Convert a nibble to a hex ASCII digit and display it.

: .BYTE         \ b --
Display the byte b as a 2 digit hex number.

: .WORD         \ w --
Display w as a 4 digit unsigned hexadecimal number.

: .dword        \ x --
Display x as an 8 digit unsigned hexadecimal number.

: .lword        \ x --
A synonym for .DWORD above.