Turbo ISA Reference
Architecture Overview
The Turbo ISA (Instruction Set Architecture) defines the interface between software and hardware. It specifies how instructions are encoded, what operations the CPU can perform, and how registers and memory are organized. Both the software simulator and the SystemVerilog hardware processor implement this same specification.
- Word size: 32 bits — all instructions and data are 32-bit values
- Design: RISC (Reduced Instruction Set Computer) — fixed-width instructions, load/store architecture
- Memory model: Harvard — separate instruction and data memories, byte-addressable
- Alignment: LOAD and STORE addresses must be word-aligned (multiples of 4)
- Register file: 16 general-purpose registers (r0–r15)
- Program counter: PC (special register, not directly addressable)
Register Roles
| Register | Role |
|---|---|
r0 | Hardwired zero (reads as 0, writes ignored) |
r1–r4 | Function arguments; r1 is the return register |
r5–r11 | Caller-saved temporaries |
r12–r13 | Callee-saved |
r14 | Stack pointer (SP) |
r15 | Link register (LR) |
Instruction Formats
All instructions are exactly 32 bits.
R-type
[opcode:6][rd:4][rs1:4][rs2:4][funct:6][unused:8]I-type
[opcode:6][rd:4][rs1:4][imm:18]imm is signed 18-bit two's complement (range: −131072 to 131071).
B-type
[opcode:6][rs1:4][rs2:4][offset:18]Branch target: PC + sign_extend(offset) × 4.
J-type
[opcode:6][rd:4][offset:22]Jump target: PC + sign_extend(offset) × 4.
Opcode Map
The architecture defines 28 opcodes.
| Opcode | Mnemonic | Format |
|---|---|---|
0x00 | ADD | R-type |
0x01 | SUB | R-type |
0x02 | MUL | R-type |
0x03 | DIV | R-type |
0x04 | MOD | R-type |
0x05 | ADDI | I-type |
0x06 | SUBI | I-type |
0x07 | AND | R-type |
0x08 | OR | R-type |
0x09 | XOR | R-type |
0x0A | NOT | R-type |
0x0B | SHL | R-type |
0x0C | SHR | R-type |
0x0D | ASHR | R-type |
0x0E | ANDI | I-type |
0x0F | ORI | I-type |
0x10 | LOAD | I-type |
0x11 | STORE | I-type |
0x12 | BEQ | B-type |
0x13 | BNE | B-type |
0x14 | BLT | B-type |
0x15 | BGE | B-type |
0x16 | JMP | J-type |
0x17 | JAL | J-type |
0x18 | JR | R-type |
0x19 | LUI | I-type |
0x1A | HALT | R-type |
0x1B | NOP | R-type |
Instruction Semantics
Arithmetic
ADD ADD rd, rs1, rs2 — rd = rs1 + rs2
ADD r1, r2, r3 ; r2=5, r3=3 → r1=8SUB SUB rd, rs1, rs2 — rd = rs1 − rs2
SUB r1, r2, r3 ; r2=10, r3=4 → r1=6MUL MUL rd, rs1, rs2 — rd = rs1 × rs2
MUL r1, r2, r3 ; r2=7, r3=6 → r1=42DIV DIV rd, rs1, rs2 — rd = rs1 / rs2 (signed, truncated toward zero; div by zero → 0)
DIV r1, r2, r3 ; r2=20, r3=3 → r1=6MOD MOD rd, rs1, rs2 — rd = rs1 % rs2 (signed remainder; mod by zero → 0)
MOD r1, r2, r3 ; r2=20, r3=3 → r1=2ADDI ADDI rd, rs1, imm — rd = rs1 + sign_extend(imm)
ADDI r1, r2, 10 ; r2=5 → r1=15SUBI SUBI rd, rs1, imm — rd = rs1 − sign_extend(imm)
SUBI r1, r2, 3 ; r2=10 → r1=7Logic and Shifts
AND AND rd, rs1, rs2 — Bitwise AND
AND r1, r2, r3 ; r2=0xFF, r3=0x0F → r1=0x0FOR OR rd, rs1, rs2 — Bitwise OR
OR r1, r2, r3 ; r2=0xF0, r3=0x0F → r1=0xFFXOR XOR rd, rs1, rs2 — Bitwise XOR
XOR r1, r2, r3 ; r2=0xFF, r3=0x0F → r1=0xF0NOT NOT rd, rs1 — Bitwise NOT (rs2 must be r0)
NOT r1, r2 ; r2=0x00 → r1=0xFFFFFFFFSHL SHL rd, rs1, rs2 — Logical shift left by rs2 & 0x1F
SHL r1, r2, r3 ; r2=1, r3=4 → r1=16SHR SHR rd, rs1, rs2 — Logical shift right (zero-fill) by rs2 & 0x1F
SHR r1, r2, r3 ; r2=0x80, r3=4 → r1=0x08ASHR ASHR rd, rs1, rs2 — Arithmetic shift right (sign-extends) by rs2 & 0x1F
ASHR r1, r2, r3 ; r2=0xFFFFFF00, r3=4 → r1=0xFFFFFFF0ANDI ANDI rd, rs1, imm — Bitwise AND with sign-extended immediate
ANDI r1, r2, 0xF ; r2=0xFF → r1=0x0FORI ORI rd, rs1, imm — Bitwise OR with sign-extended immediate
ORI r1, r2, 0xF ; r2=0xF0 → r1=0xFFMemory
LOAD LOAD rd, rs1, imm — rd = memory[rs1 + sign_extend(imm)]
LOAD r1, r14, 0 ; load word at SP into r1STORE STORE rs2, rs1, imm — memory[rs1 + sign_extend(imm)] = rs2. STORE uses I-type encoding where the rd field carries the source register.
STORE r1, r14, 0 ; store r1 at address in SPBranch and Jump
BEQ BEQ rs1, rs2, offset — Branch if rs1 == rs2
BEQ r1, r0, done ; if r1 == 0, jump to 'done'BNE BNE rs1, rs2, offset — Branch if rs1 ≠ rs2
BNE r1, r2, loop ; if r1 != r2, jump to 'loop'BLT BLT rs1, rs2, offset — Branch if rs1 < rs2 (signed)
BLT r1, r2, less ; if r1 < r2, jump to 'less'BGE BGE rs1, rs2, offset — Branch if rs1 ≥ rs2 (signed)
BGE r1, r2, skip ; if r1 >= r2, jump to 'skip'JMP JMP offset — Unconditional jump; rd must be r0. PC = PC + sign_extend(offset) × 4
JMP loopJAL JAL rd, offset — rd = PC + 4, then PC = PC + sign_extend(offset) × 4
JAL r15, func ; save return addr, call 'func'JR JR rs1 — PC = rs1 (rs2 should be r0)
JR r15 ; return via link registerSpecial and System
LUI LUI rd, imm — rd = (imm & 0x3FFFF) << 14
LUI r1, 0x10 ; r1 = 0x10 << 14 = 0x00040000HALT HALT — Stop execution. CPU halts, cycle counter freezes.
HALTNOP NOP — No operation. Advance PC by 4.
NOPBehavioral Rules
- Arithmetic overflow wraps in two's complement modulo 232.
r0is hardwired to zero.- Shift amount uses lower 5 bits of
rs2only. - Shifts by values ≥ 32 are undefined at ISA level and masked by implementation convention.
Turbo Binary File Format
A Turbo binary file has this exact layout:
- Magic: 4 bytes —
TURB(0x54 0x55 0x52 0x42) - Version: 4-byte little-endian u32, currently
1 - Instruction count: 4-byte little-endian u32
- Payload:
instruction_countwords, each 4-byte little-endian u32
Header size is 12 bytes (3 words). First instruction starts at byte offset 12. Files must be self-consistent: payload length must be instruction_count × 4.