Differences
This shows you the differences between two versions of the page.
| Both sides previous revisionPrevious revisionNext revision | Previous revision | ||
| instruction_encoding [2021/03/11 10:00] – pulkomandy | instruction_encoding [2024/07/01 13:29] (current) – [Multiplication] simer | ||
|---|---|---|---|
| Line 7: | Line 7: | ||
| ^Contents|Opcode0|Operand A|Opcode1|6-bit Immediate | ^Contents|Opcode0|Operand A|Opcode1|6-bit Immediate | ||
| + | ===== Summary ===== | ||
| + | |||
| + | ^Opcode 0\1 ^ 0 ^ 1 ^ 2 ^ 3 ^ 4 ^ 5 ^ 6 ^ 7 ^ | ||
| + | ^Addressing mode|[BP+Imm6]|# | ||
| + | ^ | ||
| + | ^ | ||
| + | ^ | ||
| + | ^ | ||
| + | ^ | ||
| + | ^ | ||
| + | ^ | ||
| + | ^ | ||
| + | ^ | ||
| + | ^ | ||
| + | ^ | ||
| + | ^ | ||
| + | ^ | ||
| + | ^ | ||
| + | ^ | ||
| + | ^ | ||
| + | |||
| + | * 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 ===== | ||
| " | " | ||
| - | Opcode1 determines the instruction: | + | ==== Multiplication ==== |
| - | * 0: MUL | + | ^Instruction |
| - | * 1: CALL | + | ^MAC (unsigned*signed) | F | Op.A |
| - | * 2: GOTO | + | ^MAC (signed*signed) |
| - | * 3: ??? | + | ^MUL (unsigned*signed) | F | Op.A |
| - | * 4: MULS | + | ^MUL (signed*signed) |
| - | * 5: INT, NOP | + | |
| - | * 6: ??? | + | |
| - | * 7: ??? | + | |
| - | TODO: BREAK is probably somewhere here. | + | 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 ==== | ||
| - | ==== MUL and MULS ==== | + | ^Instruction^Opcode0^Operand A^Opcode1^6-bit Immediate |
| - | + | ^ CALL | F | ? | |
| - | With OperandN = 1 and OperandA != 7 (other cases are not documented yet?) | + | ^ GOTO |
| - | + | ||
| - | OperandA and OperandB are multiplied together. | + | |
| - | + | ||
| - | ==== CALL and GOTO ==== | + | |
| The target address is formed by the immediate6 value (for CS:) and another word after the instruction (for PC) | The target address is formed by the immediate6 value (for CS:) and another word after the instruction (for PC) | ||
| Line 36: | Line 55: | ||
| ==== Interrupts ==== | ==== Interrupts ==== | ||
| - | OperandA must be 0. | + | ^Instruction |
| + | ^ INT OFF | ||
| + | ^ INT IRQ | ||
| + | ^ INT FIQ | ||
| + | ^ INT IRQ, | ||
| + | ^ FIR_MOV ON | F | ? | ||
| + | ^ FIR_MOV OFF | ||
| + | | | ||
| + | ^ IRQ OFF | ||
| + | ^ IRQ ON | F | ? | ||
| + | | | ||
| + | ^ FIQ OFF | ||
| + | | | ||
| + | ^ FIQ ON | F | ? | ||
| + | | | ||
| + | ^ BREAK | ||
| - | The operation depends on the Immediate6 value: | + | FIXME probably |
| - | + | ||
| - | * 00: INT OFF | + | |
| - | * 01: INT IRQ | + | |
| - | * 02: INT FIQ | + | |
| - | * 03: INT FIQ,IRQ | + | |
| - | * 04: FIR_MOV ON | + | |
| - | * 05: FIR_MOV OFF | + | |
| - | * 06: ??? | + | |
| - | * 07: ??? | + | |
| - | * 08: IRQ OFF | + | |
| - | * 09: IRQ ON | + | |
| - | * 0A: ??? | + | |
| - | * 0B: ??? | + | |
| - | * 0C: FIQ OFF | + | |
| - | * 0D: ??? | + | |
| - | * 0E: FIQ ON | + | |
| - | * 0F: ??? | + | |
| - | * 25: NOP | + | |
| - | * All other values: ??? | + | |
| ===== Jump instructions ===== | ===== Jump instructions ===== | ||
| - | Jump instructions are identified by Operand A = 0 | + | Jump instructions are identified by Operand A = 7 (makes sense, because they change the PC which is register 7) |
| - | The type of jump depends on Opcode0: | + | ^Instruction |
| + | ^ JB, JNAE, JCC | 0 | | ||
| + | ^ JAE, JNB, JCS | 1 | | ||
| + | ^ JGE, JNL, JSC | 2 | | ||
| + | ^ JL, JNGE, JSS | 3 | | ||
| + | ^ JNE, JNZ | 4 | | ||
| + | ^ JE, JZ | 5 | | ||
| + | ^ JPL | ||
| + | ^ JMI | ||
| + | ^ JBE, JNA | 8 | | ||
| + | ^ JA, JNBE | 9 | | ||
| + | ^ JLE, JNG | A | | ||
| + | ^ JG, JNLE | B | | ||
| + | ^ JVC | ||
| + | ^ JVS | ||
| + | ^ JMP | ||
| + | | | ||
| - | * 0: JCC JB JNAE | + | Opcode1 indicates the jump direction, and can be 0 (jump forward) or 1 (jump backward). The offset is counted from the opcode // |
| - | * 1: JCS JNB JAE | + | |
| - | * 2: JSC JGE JNL | + | |
| - | * 3: JSS JNGE JL | + | |
| - | * 4: JNE JNZ | + | |
| - | * 5: JE JZ | + | |
| - | * 6: JPL | + | |
| - | * 7: JMI | + | |
| - | * 8: JBE JNA | + | |
| - | * 9: JNBE JA | + | |
| - | * A: JLE JNG | + | |
| - | * B: JNLE JG | + | |
| - | * C: JVC | + | |
| - | * D: JVS | + | |
| - | * E: JMP | + | |
| - | * F: Reserved for special instructions (see above) | + | |
| - | + | ||
| - | In jump instructions, Opcode1 is 0 to jump forward, and 1 to jump back. The offset is stored as a 6-bit immediate. | + | |
| ===== ALU instructions ===== | ===== ALU instructions ===== | ||
| - | Opcode0 | + | ^Instruction |
| - | + | ^ ADD | |
| - | | + | ^ ADC |
| - | | + | ^ SUB |
| - | | + | ^ SBC |
| - | | + | ^ CMP |
| - | | + | | |
| - | * 5: ??? | + | ^ NEG |
| - | | + | | |
| - | * 7: ??? | + | ^ XOR |
| - | | + | ^ LD | |
| - | | + | ^ POP |
| - | | + | ^ RETF | 9 |5 (SR) |
| - | | + | ^ RETI | 9 |5 (SR) |
| - | | + | ^ OR | A |Op. A |Addr Mode|Param |
| - | | + | ^ AND | B |Op. A |Addr Mode|Param |
| - | | + | ^ TEST | |
| - | | + | ^ ST | |
| - | + | ^ PUSH | D |Last reg -1 | 2 |Register count| Stack pointer reg | | |
| - | TODO: I don't know what the TEST instruction does differently from CMP? | + | | |
| + | | | ||
| - | For these instructions, Opcode1 defines the addressing | + | Depending on opcode1, various |
| - | * 0: [BP+Imm6] | + | ^Addressing mode ^Opcode0^Operand A^Opcode1 |
| - | * 1: #Imm6 | + | ^%% [BP+Imm6] |
| - | | + | ^%% #Imm6 %%| ALU op| Op. A | 1 |
| - | | + | | Special (POP, PUSH) | |
| - | * 4: addressing depends on opN | + | ^%% [Rs] %%| ALU op| Op. A | 3 | 0 | Rs | |
| - | * 5: Rs LSL/LSR OpN | + | ^%% [Rs--] |
| - | | + | ^%% [Rs++] |
| - | | + | ^%% [++Rs] |
| + | ^%% D:[Rs] %%| ALU op| Op. A | 3 | 4 | Rs | | ||
| + | ^%% D:[Rs--] | ||
| + | ^%% D: | ||
| + | ^%% D:[++Rs] %%| ALU op| Op. A | 3 | 7 | Rs | | ||
| + | ^%% Rs %%| ALU op| Op. A | 4 | 0 | Rs | | ||
| + | ^%% # | ||
| + | ^%% From [Addr16] %%| ALU op| Op. A | 4 | 2 | Rs* | |16-bit address in next word, Rs is first operand| | ||
| + | ^%% To [Addr16] | ||
| + | ^%% 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 | ||
| - | When opcode1 is 2: | + | The instructions using Imm16 or Addr16 are 3-operand instructions, |
| - | * LD becomes POP | + | '' |
| - | * ST becomes PUSH | + | |
| - | * Other values of opcode0 are not allowed | + | |
| - | In a POP instruction: | + | naken_asm syntax: |
| - | * OperandA+1 is the first popped register (it is not possible to push R0/SP) | + | '' |
| - | * OperandN is the number of registers to push | + | |
| - | * OperandB is the register to use as a stack pointer | + | |
| - | RETF is a special case of POP with opA=5, opN=2, opB=0 (restores R6 and R7) | + | All other forms are 2-operand: operand A is always |
| - | RETI is a special case of POP with opA=5, opN=3, opB=0 (restores R6, R7, and an extra special register containing interrupt flags) | + | The LD operation uses operand A only as a target. |
| - | In a PUSH instruction: | + | The ST operation uses the second source operand (Rs, address, ...) as the target, and operand A (always |
| - | * OperandA+1 is the last pushed register | + | Other operations can use both forms, so the "From [Addr16]" |
| - | * OperandN is the number of registers to push | + | |
| - | * OperandB is the register to use as a stack pointer | + | |
| - | When opcode1 is 3, operandN defines incrementation and use of DS: | + | '' |
| - | * 0: [Rs] | + | and the " |
| - | * 1: [Rs--] | + | |
| - | * 2: [Rs++] | + | |
| - | * 3: [++Rs] | + | |
| - | * 4: DS:[Rs] | + | |
| - | * 5: DS:[Rs--] | + | |
| - | * 6: DS:[Rs++] | + | |
| - | * 7: DS:[++Rs] | + | |
| - | When opcode1 is 4, operandN defines more addressing modes: | + | '' |
| - | * 0: Rs | + | (so in this case the register encoded in OPA is used as a source, not a destination). |
| - | * 1: 16-bit immediate value | + | |
| - | * 2: Load from memory address | + | |
| - | * 3: Store to memory address | + | |
| - | * 4: Rs ASR 1 | + | |
| - | * 5: Rs ASR 2 | + | |
| - | * 6: Rs ASR 3 | + | |
| - | * 7: Rs ASR 4 | + | |
| - | When opcode1 is 5 or 6, operandN MSB defines the shift direction, | + | The LD and ST operations with the 16-bit addressing mode ignore |
