ColorForth mnemonics/syntax are sometimes different from T18. My opinion is that they're better.

There are some tricky things you can do, particularly with or and -.

Registers are:

- R - top of return stack
- A - address
- B - address
- P - program counter
- I - instruction word
- T - top of data stack
- S - second number on data stack

The word ; is Forth syntax to end a definition. Here it doesn't necessarily mean end, but return

- Return from subroutine (return to caller):

; - Computed jump - address in T:

push ;

Useful for a vectored jump into a table

Sometimes called co-routine jump, it returns to caller while saving the current address. This can be repeated to

- Interleave 2 threads

The opcode is not used explicitly. The compiler generates it

The address is in the instruction, either 10, 8 or 3 bits depending on slot

- Tail recursion:

The compiler will turn a call followed by ; into a jump to save time and space - Implement else:

if . . else . . . then - Construct a table of jumps

Often more efficient than conditional jumps

The opcode is not used explicitly. Referencing any defined word generates a call

- Subroutine call:

word . . . ;

word

Discards the address left by for. Very efficient loop since no instruction fetchs required.

- Delay loop:

for unext - Multiply:

for +* unext - Shift:

for 2* unext

for 2/ unext - Move data to/from ports

for @+ !b unext

for @b !+ unext

for @p+ !+ unext

for @+ !p+ unext

For expects loop-count (-1) on stack and is defined as:

push begin

Begin fills the current instruction word with . so that the loop begins in the next word. Leaves address on compiler stack for next to use

- Count-down loop:

for . . . . next

Prefer unext if only 3 instructions in loop - Search for match:

for @+ over or if drop swap next no match then match

Swap is executed at compile time to access the address for next - /mod for begin over over . + -if drop 2* swap next ; then over or or - 2* - next ;

Divide operation: trial subtract and shift in either 0 or 1

If leaves its address on compiler stack for then to complete. Then may abort if address won't fit in slot

- Test for non-zero (true):

if . . . then - Test for unequal:

or if . . . then

- Absolute value:

abs -if - 1 . + then ; - Maximum:

max - over . + - -if drop ; then + ; - Minimum:

min - over . + - -if + ; then drop ;

@ and ! are Forth abbreviations for 'fetch' and 'store'. Fetch pushes the data stack; store pops it

Increment suppressed when executing from port

- Fetch a number:

123

Uses 1 slot plus 1 word - Fetch 4 numbers:

100 200 300 400

Uses 4 slots plus 4 words - Name a constant:

pi 314 ;

Uses 2 slots plus 1 word - Add a number:

1+ 1 . + ;

Uses 4 slots plus 1 word

Increment suppressed when referencing port

- Check-sum memory:

0 63 for @+ . + unext

- Read status:

io b! @b

- Read status:

io a! @

- Send status to port from which you're executing instructions:

@b !p+ - Make a constant (x) into a variable:

x! @p+ drop !p+ ;

x 100 ;

Avoids using an address register

- Fill memory from port:

63 for @b !+ unext - Fill memory executing from port:

63 for @p+ !+ unext

Be careful to distinguish !b from b!

- Set 2 I/O pins

30003 !b - Reset 3 I/O pins

2000a !b

- Set first I/O pin

30000 !

- 4-bit multiply:

. +* . +* . +* . +*

If the multiplicand (in T) was shifted left 4 places, the result is aligned - n-bit multiply:

push . begin +* unext

This construction is required to provide a . for the first +*; unext provides delay for the others - Unsigned integer multiply:

* a! 17 push . begin +* unext drop a ;

18-bit result

- Multiply by 3:

dup 2* . + - Multiply by 5:

dup 2* 2* . + - Multiply by 6:

2* dup 2* . + - Multiply by 7:

dup 2* dup 2* . + . + - Test right-port read-status:

@b 2* -if - Test down-port read-status (after right-port):

2* 2* -if

- Divide by 4:

2/ 2/

- Test for positive:

- -if - Negate:

- 1 . + - Subtract T from S:

- . +

This result is 1 too small. It can be corrected during additional arithmetic - Subtract S from T:

- . + - - Subtract T from S:

push - pop . + - - Construct -1:

dup or -

dup dup - . + - Construct -2:

dup or - 2* - Construct +1:

dup or - 2* -

Same number of slots as literal 1

- Add:

. +

Dot required if stack has just changed. Otherwise carry can propagate only 9 bits

Requires bit 9 of P be set

- Set P9:

200 org arithmetic . . . ;

arithmetic

P9 reset upon return from arithmetic - Add:

. + - Clear and save carry:

dup or . + - Return -1 if carry zero; 0 if carry set. Cleverly adds number to complement:

dup dup - . + - Set carry:

dup or - dup . +

- Mask low-order byte:

ff and - Mask sign bit:

20000 and - Return zero if T was a power of 2:

dup -1 . + and

- One's complement T:

3ffff or

Not useful since it uses 5 slots instead of 1 ( - ) - Change sign bit:

20000 or - Inclusive-or:

over - and or - nip:

over or or

Uses a stack location

- Discard R:

pop drop - nip (discard S):

push drop pop

Uses a return stack location

- construct a 0 (discards T):

dup or - Preserve the stack while using it destructively:

dup dup or - Square a number:

dup * - Cube a number:

dup dup * *

- Retrieve something saved
- Retrieve a loop index:

pop dup push - Discard loop index and exit loop:

pop drop ; - Discard a return address. Return to the caller's caller:

pop drop ;

- Fetch an increment:

over . + - Working copy of two numbers:

over over - Swap T and S (leaving S behind)

- Retrieve something saved
- Read address for decrementing:

a over . +

- Fill unused slots
- Delay:

b! . b! - Delay before add:

. + - Delay loops:

for . unext

for . . unext

for . . . unext

- Set loop count
- Expose deeper stack:

push over - nip:

push drop pop

Uses a return stack location - Decrement non-zero number:

push here 1 + next pop - clip:

push max pop min

Be careful to distinguish b! and !b

- Set b@ b! address

- Set @ ! address
- Save top of stack
- Clean swap:

push a! pop a