68xxx code definitions








Register usage

On 68xxx CPUs the following register usage is the default:


  A7 = return stack
  A6 = data stack
  A5 = user pointer
  A4 = locals pointer
  A3 = 0
  A2 = scratch
  A1 = scratch
  A0 = scratch

  D7 = TOS
  D6..D2 = scratch
  D1, D0 = scratch and optimiser temporary

The VFX optimiser reserves D0 and D1 for internal operations. CODE definitions must use D7 as TOS with NOS pointed to by A6 as a full descending stack. D2..D6 and A0..A2 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.




Logical and relational operators

CODE AND        \ x1 x2 -- x3

Perform a logical AND between the top two stack items and retain the result in top of stack.

CODE OR         \ x1 x2 -- x3

Perform a logical OR between the top two stack items and retain the result in top of stack.

CODE XOR        \ x1 x2 -- x3

Perform a logical XOR between the top two stack items and retain the result in top of stack.

CODE INVERT     \ x -- x'

Perform a bitwise NOT on the top stack item and retain result.

CODE MIN        \ n1 n2 -- n1|n2 

Given two data stack items preserve only the smaller.

CODE MAX        \ n1 n2 -- n1|n2

Given two data stack items preserve only the larger.

CODE 0=         \ x -- flag

Compare the top stack item with 0 and return TRUE if equals.

CODE 0<>        \ x -- flag

Compare the top stack item with 0 and return TRUE if not-equal.

CODE 0<         \ x -- flag

Return TRUE if the top of stack is less-than-zero.

CODE 0>         \ x -- flag

Return TRUE if the top of stack is greater-than-zero.

CODE =          \ x1 x2 -- flag

Return TRUE if the two topmost stack items are equal.

CODE <>         \ x1 x2 -- flag

Return TRUE if the two topmost stack items are different.

CODE <          \ x1 x2 -- flag

Return TRUE if n1 is less than n2.

CODE >          \ x1 x2 -- flag

Return TRUE if n1 is greater than n2.

CODE <=         \ x1 x2 -- flag

Return TRUE if n1 is less than or equal to n2.

CODE >=         \ x1 x2 -- flag

Return TRUE if n1 is greater than or equal to n2.

CODE U>         \ u2 u2 -- flag

An UNSIGNED version of >.

CODE U<         \ u1 u2 -- flag

An UNSIGNED version of <.

CODE DU<        \ ud1 ud2 -- flag

Returns true if ud1 (unsigned double) is less than ud2.

CODE D0<        \ d -- flag

Returns true if signed double d is less than zero.

CODE D0=        \ xd -- flag

Returns true if xd is 0.

CODE D=         \ xd1 xd2 -- flag

Return TRUE if the two double numbers are equal.

CODE D<         \ d1 d2 -- flag

Return TRUE if the double number d1 is < the double number d2.

CODE DMAX       \ d1 d2 -- d3 ; d3=max of d1/d2

Return the maximum double number from the two supplied.

CODE DMIN       \ d1 d2 -- d3 ; d3=min of d1/d2

Return the minimum double number from the two supplied.

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.

CODE LSHIFT     \ x1 u -- x1<<u

Logically shift X1 by U bits left.

CODE RSHIFT     \ x1 u -- x1>>u

Logically shift X1 by U bits right.




Control flow

CODE EXECUTE    \ xt --

Execute the code described by the XT. This is a Forth equivalent to an assembler JSR/CALL instruction.

CODE BRANCH     \ --

The run time action of unconditional branches compiled on the target.

CODE ?BRANCH    \ n --

The run time action of conditional branches compiled on the target.

CODE (OF)       \ n1 n2 --  n1|n1 n2

The run time action of OF compiled on the target.

CODE (LOOP)     \ --

The run time action of LOOP compiled on the target.

CODE (+LOOP)    \ n --

The run time action of +LOOP compiled on the target.

CODE (DO)       \ limit index --

The run time action of DO compiled on the target.

CODE (?DO)      \ limit index --

The run time action of ?DO compiled on the target.

CODE LEAVE      \ -- ; N.B. now non-immediate

Remove the current DO..LOOP parameters and jump to the end of the DO..LOOP structure.

CODE ?LEAVE     \ flag -- ; N.B. now non-immediate

If flag is non-zero, remove the current DO..LOOP parameters and jump to the end of the DO..LOOP structure.

CODE I          \ -- n

Return the current index of the inner-most DO..LOOP.

CODE J          \ -- n

Return the current index of the second DO..LOOP.

CODE UNLOOP     \ -- ; R: loop-sys --

Remove the DO..LOOP control parameters from the return stack.




Arithmetic

Note that two sets of the words UM* M* and * exist which are selected by the equate CPU32?.

CODE UM*        \ u1 u2 -- ud

Perform unsigned-multiply between two numbers and return double result.

CODE *          \ n1 n2 -- n3

Standard signed multiply. N3 = n1 * n2.

CODE M*         \ n1 n2 -- d3

Signed multiply yielding double result.

CODE UM*        \ u1 u2 -- ud ; MUST preserve D5

The unsigned 32 * 32 -> 64 bit multiply primitive for CPUs without the long multiply instructions.

: *             \ n1 n2 -- n3

Standard signed multiply. N3 = n1 * n2.

CODE M*         \ n1 n2 -- d ; relies on UM* leaving D5 alone

Signed multiply yielding double result.

The division words select different forms according to the setting of CPU32?.

CODE UM/MOD   \ ud u -- urem uquot                                              

Perform unsigned division of double number UD by single number U and return remainder and quotient.

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 ; 6.1.0240

Signed division of N1 by N2 single-precision yielding remainder and quotient.

code /          \ n1 n2 -- quot ; 6.1.0230

Standard signed division operator. n3 = n1/n2.

code mod        \ n1 n2 -- rem ; 6.1.1890

Return remainder of division of N1 by N2. n3 = n1 mod n2.

: */MOD         \ n1 n2 n3 -- rem quot

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.

: MU/MOD        \ d n  --  rem d#quot

Perform an unsigned divide of a double by a single, returning a single remainder and a double quotient.

CODE TNEGATE    \ t1 -- -t1 ; negate value of triple cell number

Negate a triple (3 cell) number.

: M*/           \ d1 n1 +n2 -- d2

Multiply double d1 by single n1 to give a triple precision result, and then divide it by n2 returning the quotient. The point of this operation is to avoid loss of precision.

CODE M+         \ d1|ud1 n -- d2|ud2

Add double d1 to sign extended single n to form double d2.

CODE D+         \ d1 d2 -- d3

Add two double precision integers.

CODE D-         \ d1 d2 -- d3 

Subtract two double precision integers. D3=D1-D2.

CODE 1+         \ n1|u1 -- n2|u2

Add one to top-of stack.

CODE 2+         \ n1|u1 -- n2|u2

Add two to top-of stack.

CODE 4+         \ n1|u1 -- n2|u2

Add four to top-of stack.

CODE 1-         \ n1|u1 -- n2|u2

Subtract one from top-of stack.

CODE 2-         \ n1|u1 -- n2|u2

Subtract two from top-of stack.

CODE 4-         \ n1|u1 -- n2|u2

Subtract four from top-of stack.

CODE 2*         \ x1 -- x2

Signed multiply top of stack by 2.

CODE 4*         \ x1 -- x2

Signed multiply top of stack by 4.

code 2/         \ x1 -- x2

Signed divide top of stack by 2 by arithmetic right shift.

code U2/        \ x1 -- x2

Unsigned divide top of stack by 2 by logical right shift.

code 4/         \ x1 -- x2

Signed divide top of stack by 4 by arithmetic right shift.

code U4/        \ x1 -- x2

Unsigned divide top of stack by 4 by logical right shift.

CODE +          \ n1|u1 n2|u2 -- n3|u3

Add two single precision integer numbers.

CODE -          \ n1|u1 n2|u2 -- n3|u3

Subtract two single precision integer numbers. N3|u3=n1|u1-n2|u2.

CODE NEGATE     \ n1 -- n2

Negate a single precision integer number.

CODE DNEGATE    \ d1 -- d2 

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 D2*        \ xd1 -- xd2

Multiply the given double number by two.

CODE D2/        \ xd1 -- xd2

Divide the given double number by two.




Stack manipulation

CODE NIP        \ x1 x2 -- x2

Dispose of the second item on the data stack.

CODE TUCK       \ x1 x2 -- x2 x1 x2

Insert a copy of the top data stack item underneath the current second item.

CODE PICK       \ xu .. x0 u -- xu .. x0 xu

Get a copy of the Nth data stack item and place on top of stack. 0 PICK is equivalent to DUP.

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.

CODE ROT        \ x1 x2 x3 -- x2 x3 x1

ROTate the positions of the top three stack items such that the current top of stack becomes the second item. See also ROLL.

CODE -ROT       \ x1 x2 x3 -- x3 x1 x2

The inverse of ROT.

CODE >R         \ x -- ; R: -- x

Push the current top item of the data stack onto the top of the return stack.

CODE R>         \ -- x ; R: x --

Pop the top item from the return stack to the data stack.

CODE R@         \ -- x ; R: x -- x 

Copy the top item from the return stack to the data stack.

CODE 2>R        \ x1 x2 -- ; R: -- x1 x2

Transfer the two top data stack items to the return stack.

CODE 2R>        \ -- x1 x2 ; R: x1 x2 --

Transfer the top two return stack items to the data stack.

CODE 2R@        \ -- x1 x2 ; R: x1 x2 -- x1 x2

Copy the top two return stack items to the data stack.

CODE 2ROT       \ x1 x2 x3 x4 x5 x6 -- x3 x4 x5 x6 x1 x2

Perform ROT operation on three double numbers.

CODE DROP       \ x --

Lose the top data stack item and promote NOS to TOS.

CODE 2DROP      \ x1 x2 --

Discard the top two data stack items.

CODE SWAP       \ x1 x2 -- x2 x1

Exchange the top two data stack items.

CODE 2SWAP      \ x1 x2 x3 x4 -- x3 x4 x1 x2

Exchange the top two cell-pairs on the data stack.

CODE DUP        \ x -- x x

DUPlicate the top stack item.

CODE ?DUP       \ x -- | x

DUPplicate the top stack item only if it non-zero.

CODE 2DUP       \ x1 x2 -- x1 x2 x1 x2

DUPlicate the top cell-pair on the data stack.

CODE OVER       \ x1 x2 -- x1 x2 x1

Copy NOS to a new top-of-stack item.

CODE 2OVER      \ x1 x2 x3 x4 -- x1 x2 x3 x4 x1 x2

Similar to OVER but works with cell-pairs rather than cell items.

CODE SP@        \ -- x

Get the current address value of the data-stack pointer.

CODE SP!        \ x --

Set the current address value of the data-stack pointer.

CODE RP@        \ -- x

Get the current address value of the return-stack pointer.

CODE RP!        \ x --

Set the current address value of the return-stack pointer.




Strings

CODE COUNT      \ c-addr1 -- c-addr2' u

Given the address of a counted string in memory this word will return the address of the first character and the length in characters of the string.

CODE /STRING    \ c-addr1 u1 n -- c-addr2 u2

Modify a string address and length to remove the first N characters from the string.

CODE SKIP       \ c-addr1 u1 char -- c-addr2 u2

Modify the string description by skipping over leading occurrences of 'char'.

CODE SCAN       \ c-addr1 u1 char -- c-addr2 u2

Look for first occurrence of CHAR in string and return new string. C-addr2/u2 describe the string with CHAR as the first character.

CODE S=         \ c-addr1 c-addr2 u -- flag

Compare two same-length strings/memory blocks, returning TRUE if they are identical.

CODE COMPARE    \ c-addr1 len1 c-addr2 len2 -- n

Compare two strings. The return result is 0 for a match or can be -ve/+ve indicating string differences. If the two strings are identical, n is zero. If the two strings are identical up to the length of the shorter string, n is minus-one (-1) if u1 is less than u2 and one (1) otherwise. If the two strings are not identical up to the length of the shorter string, n is minus-one (-1) if the first non-matching character in the string specified by c-addr1 u1 has a lesser numeric value than the corresponding character in the string specified by c-addr2 u2 and one (1) otherwise.

: SEARCH        \ c-addr1 u1 c-addr2 u2  --  c-addr3 u3 flag

Search the string c-addr1/u1 for the string c-addr2/u2. If a match is found return c-addr3/u3, the address of the start of the match and the number of characters remaining in c-addr1/u1, plus flag f set to true. If no match was found return c-addr1/u1 and f=0.

CODE CMOVE      \ c-addr1 c-addr2 u --

Copy U bytes of memory forwards from C-ADDR1 to C-ADDR2.

CODE CMOVE>     \ c-addr1 c-addr2 u --

As CMOVE but working in the opposite direction, copying the last character in the string first.

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. See the definition of (.") for an example.

CODE UPPER      \ c-addr u --

Convert the ASCII string described to upper-case. This operation happens in place.




Memory operators

CODE ON         \ a-addr --

Given the address of a CELL this will set its contents to TRUE (-1).

CODE OFF        \ a-addr --

Given the address of a CELL this will set its contents to FALSE (0).

CODE +!         \ n|u a-addr --

Add N to the CELL at memory address ADDR.

CODE c+!        \ b addr --                                                     

Add N to the character (byte) at memory address ADDR.

CODE INCR       \ a-addr --

Increment the data cell at a-addr by one.

CODE DECR       \ a-addr --

Decrement the data cell at a-addr by one.

CODE 2@         \ a-addr -- x1 x2

Fetch and return the two CELLS from memory ADDR and ADDR+sizeof(CELL). The cell at the lower address is on the top of the stack.

CODE @          \ a-addr -- x

Fetch and return the CELL at memory ADDR.

CODE W@         \ a-addr -- w

Fetch and 0 extend the word (16 bit) at memory ADDR.

CODE C@         \ c-addr -- char

Fetch and 0 extend the character at memory ADDR and return.

CODE 2!         \ x1 x2 a-addr --

Store the two CELLS x1 and x2 at memory ADDR. X2 is stored at ADDR and X1 is stored at ADDR+CELL.

CODE !          \ x a-addr --

Store the CELL quantity N at memory ADDR.

CODE W!         \ w a-addr --

Store the word (16 bit) quantity w at memory ADDR.

CODE C!         \ char c-addr --

Store the character CHAR at memory C-ADDR.

CODE FILL       \ c-addr u char --

Fill LEN bytes of memory starting at ADDR with the byte information specified as CHAR.

CODE TEST-BIT   \ u c-addr -- flag

AND the mask with the contents of addr and return the result. Byte operation.

CODE SET-BIT    \ u c-addr --

Apply the mask ORred with the contents of c-addr. Byte operation.

CODE RESET-BIT  \ u c-addr --

Apply the mask inverted and ANDed with the contents of c-addr. Byte operation.

CODE TOGGLE-BIT \ u c-addr --

Invert the bits at c-addr specified by the mask. Byte operation.




Miscellaneous words

: SEARCH-WORDLIST       ( c-addr u wid  --  0|xt 1|xt -1  )

Search the given wordlist for a definition. If the definition is not found then 0 is returned, otherwise the XT of the definition is returned along with a non-zero code. A -ve code indicates a "normal" definition and a +ve code indicates an IMMEDIATE word.

CODE NAME>      \ nfa -- xt

Move a pointer from an NFA to the CFA or "XT" in ANS parlance.

CODE >NAME      \ xt -- nfa

Move a pointer from an XT back to the NFA or name-pointer. If the original pointer was not an XT or if the definition in question has no name header in the dictionary the returned pointer will be useless. Care should be taken when manipulating or scanning the Forth dictionary in this way.

: >BODY         \ xt -- a-addr

Move a pointer from a CFA or "XT" to the definition BODY. This should only be used with children of CREATE. E.g. if FOOBAR is defined with CREATE foobar, then the phrase ' foobar >body would yield the same result as executing foobar.

CODE DIGIT      \ char n -- 0|n true

If the ascii value CHAR can be treated as a digit for a number within the radix N then return the digit and a TRUE flag, otherwise return FALSE.

CODE UPC        \ char -- char'

Convert a character to upper case.

CODE S>D        \ n -- d

Convert a single number to a double one.

CODE D>S        \ d -- n

Convert a double number to a single.

CODE NOOP       \ -- 

A NOOP, null instruction. )




Portability helpers

Using these words will make code easier to port between 16, 32 and 64 bit targets.

CODE ALIGNED    \ addr -- a-addr  

Given an address pointer this word will return the next ALIGNED address subject to system wide alignment restrictions. Note that this definition is only necessary in the code file for CPUs that require alignment, but do not require alignment to a cell boundary.

CODE CELL+      \ a-addr1 -- a-addr2

Add the size of a CELL to the top-of stack.

CODE CELLS      \ n1 -- n2

Return the size in address units of N1 cells in memory.

CODE CELL-      \ a-addr1 -- a-addr2

Decrement an address by the size of a cell.

CODE CELL       \ -- n

Return the size in address units of one CELL.

CODE CHAR+      \ c-addr1 -- c-addr2

Increment an address by the size of a character.

CODE CHARS      \ n1 -- n2

Return size in address units of N1 characters.




Runtime for VALUE

CODE VAL!       \ n -- ; store value address in-line

Store n at the inline address following this word.

CODE VAL@       \ -- n ; read value data address in-line

Read n from the inline address following this word.




Defining words and runtime support

: COMPILE,      \ xt -- ; compile call to xt - may be optimised

Compile the word specified by xt into the current definition.

: CONSTANT      \ x "<spaces>name" -- ; Exec: --  x

Create a new CONSTANT called "name" which has the value "x". When "NAME" is executed the value is returned on the top-of-stack.7

: VARIABLE      \ "<spaces>name" -- ; Exec: -- a-addr

Create a new variable called "name". When "Name" is executed the address of the data-cell is returned for use with @ and ! operators.

: USER          \ u "<spaces>name" -- ; Exec: -- addr

Create a new USER variable called "name". The 'u' parameter specifies the index into the user-area table at which to place the data. USER variables are located in a separate area of memory for each task or interrupt. Use in the form: "$400 USER TaskData".

: :             \ C: "<spaces>name" -- colon-sys ; Exec: i*x -- j*x ; R: -- nest-sys 

Begin a new definition called "name".

: :NONAME       \ C: -- colon-sys ; Exec: i*x -- i*x ; R: -- nest-sys

Begin a new code definition which does not have a name. After the definition is complete the semi-colon operator returns the XT of newly compiled code on the stack.

: (;CODE)       \ -- ; R: a-addr --

Performed at compile time by ;CODE and DOES>. Patch the last word defined (by CREATE) to have the run time actions that follows immediately after (;CODE).

: DOES>         \ C: colon-sys1 -- colon-sys2 ; Run: -- ; R: nest-sys --

Begin definition of the runtime-action of a child of a defining word. You should not use RECURSE after DOES>.

: DOCREATE,     \ --

Compile the run time action of CREATE.

: CRASH         \ -- ; used as action of DEFER

The default action of a DEFERed word. This will simply THROW a code back to the system.

: DEFER         \ Comp: "<spaces>name" -- ; Run: i*x -- j*x

Creates a new DEFERed word. A default action, CRASH, is automatically assigned.

: 2CONSTANT     \ Comp: x1 x2 "<spaces>name" -- ; Run: -- x1 x2

A two-cell equivalent to CONSTANT.

: 2VARIABLE     \ Comp: "<spaces>name" -- ; Run: -- a-addr

A two-cell equivalent to VARIABLE.

: FIELD         \ size x "<spaces>name" -- size+x ; Exec: addr -- addr+x

Create a new field within a structure definition of size n bytes.




Structure compilation

These words define high level branches. They are used by the structure words such as IF and AGAIN.

: >mark         \ -- addr ; mark start of forward branch

Mark the start of a forward branch. HIGH LEVEL CONSTRUCTS ONLY.

: >resolve      \ addr -- ; resolve absolute target of forward branch

Resolve absolute target of forward branch. HIGH LEVEL CONSTRUCTS ONLY.

: <mark         \ -- addr ; mark start (destination) of backward branch

Mark the start (destination) of a backward branch. HIGH LEVEL CONSTRUCTS ONLY.

: <resolve      \ addr ; resolve (at branch point) backward branch

Mark the start (destination) of a backward branch. HIGH LEVEL CONSTRUCTS ONLY.

synonym >c_res_branch >resolve  \ addr -- ; fix up forward referenced branch

See >RESOLVE.

synonym c_mrk_branch< >mark     \ -- addr ; mark destination of backward branch

See >MARK




Branch constructors

Used when compiling code on the target.

: c_branch<     \ addr -- ; lay BRANCH instructions

Lay the code for BRANCH.

: c_?branch<    \ addr -- ; lay ?BRANCH instructions

Lay the code for ?BRANCH.

: c_branch>     \ -- addr ; forward referenced branch

Lay the code for a forward referenced unconditional branch.

: c_?branch>    \ -- addr ; forward referenced branch

Lay the code for a forward referenced conditional branch.




Main structure compilers

: DOCOLON,      \ --

Compile the runtime entry code required by colon definitions.

: c_lit         \ lit --

Compile the code for a LITERAL.

: c_drop        \ --

Compile the code for DROP.

: c_exit        \ --

Compile the code for EXIT.

: c_do          \ C: -- do-sys ; Run: n1|u1 n2|u2 -- ; R: -- loop-sys 

Compile the code for DO.

: c_?DO         \ C: -- do-sys ; Run: n1|u1 n2|u2 -- ; R: -- | loop-sys

Compile the code for ?DO.

: c_LOOP        \ C: do-sys -- ; Run: -- ; R: loop-sys1 -- | loop-sys2

Compile the code for LOOP.

: c_+LOOP       \ C: do-sys -- ; Run: -- ; R: loop-sys1 -- | loop-sys2

Compile the code for +LOOP.

: c_case        \ -- addr

Compile the code for CASE.

: c_OF          \ C: -- of-sys ; Run: x1 x2 -- | x1

Compile the code for OF.

: c_?OF         \ C: -- of-sys ; Run: flag --

Compile the code for ?OF.

: c_ENDOF       \ C: case-sys1 of-sys -- case-sys2 ; Run: --

Compile the code for ENDOF.

: FIX-EXITS     \ n1..nn --

Compile the code to resolve the forward branches at the end of a CASE structure.

: c_ENDCASE     \ C: case-sys -- ; Run: x --

Compile the code for ENDCASE.

: c_END-CASE    \ C: case-sys -- ; Run: x --

Compile the code for END-CASE.