In the following tables the LIT-field is marked with - and +.
-: The previous instruction has also been an opcode; TOS holds the top-of-stack value.
+: The previous instruction(s) have been literals; TOS holds a "fresh" literal value.
- BRA instructions
LIT |
Stack |
act |
Operation |
Forth operators / phrases |
* |
none |
none |
conditional return from subroutine
When Cond=ZERO or NZERO
Stack -> NOS -> TOS |
EXIT NOP
?EXIT
0=EXIT |
- |
pop |
|
conditional branch to Program[TOS]
Stack -> NOS -> TOS |
absolute_BRANCH
|
+ |
pop |
|
conditional branch to Program[PC+TOS]
Stack -> NOS -> TOS |
relative_BRANCH
|
* |
push |
|
Complex branches, see below |
DUP ?DUP INTERRUPT
IRET
EXCEPTION
?OVL |
- |
both |
pop
push |
conditional call to Program[TOS]
Stack -> NOS -> TOS |
absolute_CALL
DROP |
+ |
both |
pop
push |
conditional call to Program[PC+TOS]
Stack -> NOS -> TOS |
relative_CALL
DROP |
- ALU instructions
Stack |
act |
Operation |
Forth operators / phrases |
none |
none |
Complex math instructions, see below |
SWAP |
pop |
|
Stack -> NOS <op> TOS -> TOS |
+ - AND OR XOR NIP |
push |
|
NOS <op> TOS -> TOS
TOS -> NOS -> Stack |
2DUP_+ OVER |
both |
none |
TOS <uop> -> TOS
Unary math instructions, see below |
0= 2* ROR ROL 2/ u2/ |
- MEM instructions
Stack |
act |
Operation |
Forth operators / phrases |
none |
pop |
Stack -> NOS -> TOS -> Register
LOCAL := Stack -> NOS -> Data[RSP+TOS]
TASK := Stack -> NOS -> Data[TASK+TOS] |
>R, R!
store into local variables
store into task variables |
pop |
|
Stack -> NOS -> Data[TOS+<inc>]
TOS + <inc> -> TOS |
! pre-incrementing data memory or I/O store |
push |
|
Data[TOS+<inc>] -> NOS -> Stack
TOS + <inc> -> TOS |
@ pre-incrementing data memory or I/O fetch |
both |
push |
Register -> TOS -> NOS -> Stack
LOCAL := Data[RSP+TOS] -> NOS -> Stack
TASK := Data[TASK+TOS] -> NOS -> Stack |
R@, R>
fetch from local variables
fetch from task variables |
- USR instructions
By default, the USR instructions perform an immediate call to the following vector address:
vector_addr = instruction(4..0) * usr_vect_width
Therefore, each trap vector has room for usr_vect_width instructions.
Four trap vectors are used by MicroCore itself:
0: Reset
1: ISR: Interrupt Service Routine
2: ESR: Exception Service Routine
3: OSR: Overflow Service Routine
- Complex Branches (BRA PUSH)
DUP |
TOS -> TOS -> NOS -> Stack |
QDUP |
Performs a DUP when TOS is non-zero, otherwise does nothing |
QOVL |
Performs a call to the overflow service routine when the overflow status bit is set |
IRET |
Performs an EXIT and restores the status register from TOS |
THREAD |
Threaded code interpreter.
IF Data[IP] < 0 THEN (most significant bit set)
Program_Address <- Data[IP]
IP <- IP+1
ELSE
PC <- Program_Address - 1
IP <- Data[IP]
Stack <- NOS <- TOS <- IP+1
END IF
The two instruction sequence "THREAD >R" is a tag threaded code interpreter.
When the most significant bit is set, the remaining bits are an address of the code to be executed.
When the most significant bit is not set, it is the address of another threaded code definition.
The sequence "THREAD >R" will be automatically repeated until an executable code sequence is located, pushing return addresses on the return stack appropriately. |
TOKEN |
Token threaded code interpreter.
The two instruction sequence "THREAD TOKEN" is a token threaded code interpreter.
IF IP = address within token table THEN
Program_Address <- Data[IP]
IP <- TOS <- NOS <- Stack
ELSE
>R
END IF |
- Unary Math Instructions (ALU BOTH)
SL |
Shift Left |
0 -> LSB, MSB -> C |
ASR |
Arithmetic Shift Right |
MSB -> MSB-1, LSB -> C |
LSR |
Logical Shift Right |
0 -> MSB, LSB -> C |
ROR |
ROtate Rigth |
C -> MSB, LSB -> C |
ROL |
ROtate Left |
C -> LSB, MSB -> C |
ZEQU |
Zero EQUals |
When TOS=0, true -> TOS, otherwise false -> TOS |
CC |
Complement Carry |
not Carry -> Carry |
- Complex Math (ALU NONE)
When both NOS and TOR are implemented, complex math step instructions are available.
MULTS is a step instruction for an unsigned multiply of two numbers producing a double precision product. The multiplicand must be in NOS, the multiplier must be in TOR and the product builds up in TOS || TOR.
Macro: umultiply ( mult1 mult2 -- prod_l prod_h )
>r 0 #data_width 0 ?DO mults LOOP nip r> ;
generates code for a multi cycle U* instruction, which is independent of the data word width. U* may be interrupted at any time.
0DIVS, UDIVS, LDIVS are step instructions for an unsigned divide of a double precision dividend by a divisor, producing a single precision quotient and the remainder. When the result does not fit into the quotient, the overflow status bit will be set.
Macro: udivide ( div_l div_h divisor -- rem quot )
0divs #data_width 0 ?DO udivs LOOP ldivs nip r> ;
generates code for a multi cycle UM/MOD instruction, which is independent of the data word width. In order to execute the UDIVS instruction, the divisor must be in NOS, div_l must be in TOR and div_h must be in TOS. 0DIVS takes care of this parameter set up clearing the overflow bit as well. Each division step must take into account the most significant bit of the previous step and therefore, a final step LDIVS is needed to produce a valid quotient and to check for overflow. UM/MOD may be interrupted at any time.
- Instruction Mnemonics
NEVER NONE BRA Op: nop ( -- )
ALWAYS NONE BRA Op: exit ( -- )
ZERO NONE BRA Op: z-exit ( flag -- )
NZERO NONE BRA Op: nz-exit ( flag -- )
SIGN NONE BRA Op: s-exit ( -- )
NSIGN NONE BRA Op: ns-exit ( -- )
NOVL NONE BRA Op: no-exit ( -- )
NCARRY NONE BRA Op: nc-exit ( -- )
\ Conditional branches
NEVER POP BRA Op: drop_flag ( flag brn_addr -- brn_addr )
ALWAYS POP BRA Op: branch ( brn_addr -- )
ZERO POP BRA Op: z-branch ( brn_addr -- )
NZERO POP BRA Op: nz-branch ( brn_addr -- )
SIGN POP BRA Op: s-branch ( brn_addr -- )
NSIGN POP BRA Op: ns-branch ( brn_addr -- )
NOVL POP BRA Op: no-branch ( brn_addr -- )
NCARRY POP BRA Op: nc-branch ( brn_addr -- )
\ Conditional calls
NEVER BOTH BRA Op: drop ( n -- )
ALWAYS BOTH BRA Op: call ( brn_addr -- )
ZERO BOTH BRA Op: z-call ( brn_addr -- )
NZERO BOTH BRA Op: nz-call ( brn_addr -- )
SIGN BOTH BRA Op: s-call ( brn_addr -- )
NSIGN BOTH BRA Op: ns-call ( brn_addr -- )
NOVL BOTH BRA Op: no-call ( brn_addr -- )
NCARRY BOTH BRA Op: nc-call ( brn_addr -- )
\ Complex branches
DUP PUSH BRA Op: dup ( n -- n n )
EXC PUSH BRA Op: exc ( -- )
QDUP PUSH BRA Op: ?dup ( n -- n n | 0 )
QOVL PUSH BRA Op: ?ovl ( -- )
INT PUSH BRA Op: int ( -- status )
IRET PUSH BRA Op: iret ( status -- )
THREAD PUSH BRA Op: thread ( -- ip_addr )
TOKEN PUSH BRA Op: token ( ip_addr -- )
\ Binary operators
ADD POP ALU Op: + ( n1 n2 -- n1+n2 )
ADC POP ALU Op: +c ( n1 n2 -- n1+n2+carry )
SUB POP ALU Op: - ( n1 n2 -- n1-n2 )
SSUB POP ALU Op: swap- ( n1 n2 -- n2-n1 )
AND POP ALU Op: and ( n1 n2 -- n1_and_n2 )
OR POP ALU Op: or ( n1 n2 -- n1_or_n2 )
XOR POP ALU Op: xor ( n1 n2 -- n1_xor_n2 )
NOS POP ALU Op: nip ( n1 n2 -- n2 )
ADD PUSH ALU Op: 2dup + ( n1 n2 -- n1 n2 n1+n2 )
ADC PUSH ALU Op: 2dup +c ( n1 n2 -- n1 n2 n1+n2+carry )
SUB PUSH ALU Op: 2dup - ( n1 n2 -- n1 n2 n1-n2 )
SSUB PUSH ALU Op: 2dup swap- ( n1 n2 -- n1 n2 n2-n1 )
AND PUSH ALU Op: 2dup and ( n1 n2 -- n1 n2 n1_and_n2 )
OR PUSH ALU Op: 2dup or ( n1 n2 -- n1 n2 n1_or_n2 )
XOR PUSH ALU Op: 2dup xor ( n1 n2 -- n1 n2 n1_xor_n2 )
NOS PUSH ALU Op: over ( n1 n2 -- n1 n2 n1 )
\ Unary Operators
NOT BOTH ALU Op: invert ( n1 -- n2 )
SL BOTH ALU Op: 2* ( n1 -- n2 )
ASR BOTH ALU Op: 2/ ( n1 -- n2 )
LSR BOTH ALU Op: u2/ ( n1 -- n2 )
ROR BOTH ALU Op: ror ( n1 -- n2 )
ROL BOTH ALU Op: rol ( n1 -- n2 )
ZEQU BOTH ALU Op: 0= ( n1 -- flag )
CC BOTH ALU Op: cc ( -- )
\ Complex Math Steps
MULTS NONE ALU Op: mults ( u1 u2 -- u1 u3 )
0DIVS NONE ALU Op: 0divs ( ud1 u2 -- u2 u3 )
UDIVS NONE ALU Op: udivs ( u2 u3 -- u2 u3' )
LDIVS NONE ALU Op: ldivs ( u2 u3 -- u2 u3' )
SWAPS NONE ALU Op: swap ( n1 n2 -- n2 n1 )
\ Data Memory access
N PUSH MEM Op: +ld ( addr -- n addr+n )
N POP MEM Op: +st ( n addr -- addr+n )
\ Internal Register access
STATUS BOTH MEM Op: status@ ( -- status )
TOR BOTH MEM Op: r@ ( -- n )
RSTACK BOTH MEM Op: r> ( -- n )
LOCAL BOTH MEM Op: +lld ( index -- n rstack+index )
RSP BOTH MEM Op: rsp@ ( -- rstack_addr )
DSP BOTH MEM Op: dsp@ ( -- dstack_addr )
TASK BOTH MEM Op: +tld ( index -- n task+index )
IP BOTH MEM Op: ip@ ( -- addr )
STATUS NONE MEM Op: status! ( status -- )
TOR NONE MEM Op: r! ( n -- )
RSTACK NONE MEM Op: >r ( n -- )
LOCAL NONE MEM Op: +lst ( n index -- rstack+index )
RSP NONE MEM Op: rsp! ( rstack_addr -- )
DSP NONE MEM Op: dsp! ( dstack_addr -- ? )
TASK NONE MEM Op: +tst ( n index -- task+index )
IP NONE MEM Op: ip! ( addr -- )