The instructions are 16 bit words. Most instructions use a single word, however, some of them use a second word to store an immediate 16-bit value. The general format is as follows: ^Bits ^15-12 ^11-9 ^8-6 ^5-3 ^2-0 ^ ^Contents|Opcode0|Operand A|Opcode1|OPN |Operand B| ^Contents|Opcode0|Operand A|Opcode1|6-bit Immediate || ===== Summary ===== ^Opcode 0\1 ^ 0 ^ 1 ^ 2 ^ 3 ^ 4 ^ 5 ^ 6 ^ 7 ^ ^Addressing mode|[BP+Imm6]|#Imm6 | |[Rs]|Rs,#Imm16,[Addr16], Rs ASR|Rs LSL/LSR|Rs ROL/ROR|[Addr6]| ^ 0 | **ADD**, //JB, JNAE, JCC// || | **ADD** ||||| ^ 1 | **ADC**, //JAE, JNB, JCS// || | **ADC** ||||| ^ 2 | **SUB**, //JGE, JNL, JSC// || | **SUB** ||||| ^ 3 | **SBC**, //JL, JNGE, JSS// || | **SBC** ||||| ^ 4 | **CMP**, //JNE, JNZ// || | **CMP** ||||| ^ 5 | //JE, JZ// || |||||| ^ 6 | **NEG**, //JPL// || | **NEG** ||||| ^ 7 | //JMI// || |||||| ^ 8 | **XOR**, //JBE, JNA// || | **XOR** ||||| ^ 9 | **LD**, //JA, JNBE// ||POP,RETF,RETI| **LD** ||||| ^ A | **OR**, //JLE, JNG// || | **OR** ||||| ^ B | **AND**, //JG, JNLE// || | **AND** ||||| ^ C | **TEST**, //JVC// || | **TEST**||||| ^ D | **ST**, //JVS// ||PUSH | **ST** ||||| ^ E | //JMP// || |||||| ^ F | MUL.us |CALL |MAC.us,//GOTO// | MAC.us |MUL.ss|INT,IRQ,FIR_MOV,BREAK|MAC.ss || * Instructions in bold: uses the addressing mode listed on the first line * Instructions in italics: only if operand A (destination register) is PC ===== Special instructions ===== "Special" instructions are identified by Opcode0 = 0xF ==== Multiplication ==== ^Instruction ^Opcode0^Operand A^Opcode1 ^OPN ^Operand B^ ^MAC (unsigned*signed) | F | Op.A | 2 + (N ≥ 8) | N & 7 | Op.B | ^MAC (signed*signed) | F | Op.A | 6 + (N ≥ 8) | N & 7 | Op.B | ^MUL (unsigned*signed) | F | Op.A | 0 | 1 | Op.B | ^MUL (signed*signed) | F | Op.A | 4 | 1 | Op.B | Note: Operand A and Operand B cannot be 0, 6 or 7 (it is not possible to multiply SP, SR or PC with something). They also can not be 3 or 4 in MAC (MR is used for intermediate results). If the size of the MAC operation is exactly 16, it will be encoded as N=0. ==== CALL and GOTO ==== ^Instruction^Opcode0^Operand A^Opcode1^6-bit Immediate | ^ Second word ^ ^ CALL | F | ? | 1 | CS: value | | PC value | ^ GOTO | F | 7 | 2 | CS: value | | PC value | The target address is formed by the immediate6 value (for CS:) and another word after the instruction (for PC) ==== Interrupts ==== ^Instruction ^Opcode0^Operand A^Opcode1^6-bit Immediate | ^ INT OFF | F | ? | 5 | 00 | ^ INT IRQ | F | ? | 5 | 01 | ^ INT FIQ | F | ? | 5 | 02 | ^ INT IRQ,FIQ | F | ? | 5 | 03 | ^ FIR_MOV ON | F | ? | 5 | 04 | ^ FIR_MOV OFF | F | ? | 5 | 05 | | | | | | | ^ IRQ OFF | F | ? | 5 | 08 | ^ IRQ ON | F | ? | 5 | 09 | | | | | | | ^ FIQ OFF | F | ? | 5 | 0C | | | | | | | ^ FIQ ON | F | ? | 5 | 0E | | | | | | | ^ BREAK | F | ? | 5 | 20 | FIXME probably other instructions (FRACTION, ...) fit in here ===== Jump instructions ===== Jump instructions are identified by Operand A = 7 (makes sense, because they change the PC which is register 7) ^Instruction ^Opcode0^Operand A^Opcode1 ^6-bit Immediate ^Condition | ^ JB, JNAE, JCC | 0 | 7 |Direction| Jump offset | C = 0 | ^ JAE, JNB, JCS | 1 | 7 |Direction| Jump offset | C = 1 | ^ JGE, JNL, JSC | 2 | 7 |Direction| Jump offset | S = 0 | ^ JL, JNGE, JSS | 3 | 7 |Direction| Jump offset | S = 1 | ^ JNE, JNZ | 4 | 7 |Direction| Jump offset | Z = 0 | ^ JE, JZ | 5 | 7 |Direction| Jump offset | Z = 1 | ^ JPL | 6 | 7 |Direction| Jump offset | N = 0 | ^ JMI | 7 | 7 |Direction| Jump offset | N = 1 | ^ JBE, JNA | 8 | 7 |Direction| Jump offset | !(Z=0&C=1) | ^ JA, JNBE | 9 | 7 |Direction| Jump offset | Z=0 & C=1 | ^ JLE, JNG | A | 7 |Direction| Jump offset | !(Z=0&S=0) | ^ JG, JNLE | B | 7 |Direction| Jump offset | Z=0 & S=0 | ^ JVC | C | 7 |Direction| Jump offset | N = S | ^ JVS | D | 7 |Direction| Jump offset | N != S | ^ JMP | E | 7 |Direction| Jump offset | Always | | | F | 7 | Reserved for special instructions || Opcode1 indicates the jump direction, and can be 0 (jump forward) or 1 (jump backward). The offset is counted from the opcode //following// the jump instruction, so an offset of 0 would jump to the next instruction (basically a NOP) while a offset of -1 (1 backwards) would be an infinite loop and a offset of (+1) would skip a single instruction. ===== ALU instructions ===== ^Instruction ^Opcode0^Operand A ^Opcode1 ^OPN ^Operand B^ ^ ADD | 0 |Op. A |Addr Mode|Param | Op. B | ^ ADC | 1 |Op. A |Addr Mode|Param | Op. B | ^ SUB | 2 |Op. A |Addr Mode|Param | Op. B | ^ SBC | 3 |Op. A |Addr Mode|Param | Op. B | ^ CMP | 4 |Op. A |Addr Mode|Param | Op. B | | | | | | | | ^ NEG | 6 |Op. A |Addr Mode|Param | Op. B | | | | | | | | ^ XOR | 8 |Op. A |Addr Mode|Param | Op. B | ^ LD | 9 |Op. A |Addr Mode|Param | Op. B | ^ POP | 9 |First reg - 1|2 |Register count| Stack pointer reg | ^ RETF | 9 |5 (SR) |2 |2 (SR, PC) | 0 (SP) | ^ RETI | 9 |5 (SR) |2 |3 (SR, PC, FR)| 0 (SP) | ^ OR | A |Op. A |Addr Mode|Param | Op. B | ^ AND | B |Op. A |Addr Mode|Param | Op. B | ^ TEST | C |Op. A |Addr Mode|Param | Op. B | ^ ST | D |Op. A |Addr Mode|Param | Op. B | ^ PUSH | D |Last reg -1 | 2 |Register count| Stack pointer reg | | | | | | | | | | F | Reserved for special instructions |||| Depending on opcode1, various addressing modes can be used: ^Addressing mode ^Opcode0^Operand A^Opcode1 ^OPN ^Operand B^ ^Notes ^ ^%% [BP+Imm6] %%| ALU op| Op. A | 0 | 6-bit immediate || | Op. A ≠ PC | ^%% #Imm6 %%| ALU op| Op. A | 1 | 6-bit immediate || | Op. A ≠ PC | | Special (POP, PUSH) | | | 2 | | | ^%% [Rs] %%| ALU op| Op. A | 3 | 0 | Rs | ^%% [Rs--] %%| ALU op| Op. A | 3 | 1 | Rs | ^%% [Rs++] %%| ALU op| Op. A | 3 | 2 | Rs | ^%% [++Rs] %%| ALU op| Op. A | 3 | 3 | Rs | ^%% D:[Rs] %%| ALU op| Op. A | 3 | 4 | Rs | ^%% D:[Rs--] %%| ALU op| Op. A | 3 | 5 | Rs | ^%% D:[Rs++] %%| ALU op| Op. A | 3 | 6 | Rs | ^%% D:[++Rs] %%| ALU op| Op. A | 3 | 7 | Rs | ^%% Rs %%| ALU op| Op. A | 4 | 0 | Rs | ^%% #Imm16 %%| ALU op| Op. A | 4 | 1 | Rs* | |16-bit immediate in next word, Rs is first operand| ^%% From [Addr16] %%| ALU op| Op. A | 4 | 2 | Rs* | |16-bit address in next word, Rs is first operand| ^%% To [Addr16] %%| ALU op| Op. A | 4 | 3 | Rs* | |16-bit address in next word, Rs is first operand| ^%% Rs ASR shift %%| ALU op| Op. A | 4 | 4 + (shift - 1) | Rs | ^%% Rs LSL shift %%| ALU op| Op. A | 5 | shift - 1 | Rs | ^%% Rs LSR shift %%| ALU op| Op. A | 5 | 4 + (shift - 1) | Rs | ^%% Rs ROL shift %%| ALU op| Op. A | 6 | shift - 1 | Rs | ^%% Rs ROR shift %%| ALU op| Op. A | 6 | 4 + (shift - 1) | Rs | ^%% [Addr6] %%| ALU op| Op. A | 7 | 6-bit address || The instructions using Imm16 or Addr16 are 3-operand instructions, for example: ''R3 = R2 + Imm16'' naken_asm syntax: ''ADD R3, R2, #Imm16'' All other forms are 2-operand: operand A is always a register and used as both source and destination. The LD operation uses operand A only as a target. The ST operation uses the second source operand (Rs, address, ...) as the target, and operand A (always a register) as the source. Other operations can use both forms, so the "From [Addr16]" would be something like this: ''R3 = R2 + [Addr16]'' and the "To [Addr16]" corresponds to: ''[Addr16] = R2 + R3'' (so in this case the register encoded in OPA is used as a source, not a destination). The LD and ST operations with the 16-bit addressing mode ignore the value of Rs, they use only Ra and the 16-bit value.