This section is a quick reference for the operation of the instructions supported by Hazard3, in Verilog syntax. Conventions used in this section:
* `rs1`, `rs2` and `rd` are 32-bit unsigned vector variables referring to the two register operands and the destination register
* `imm` is a 32-bit unsigned vector referring to the instruction's immediate value
* `pc` is a 32-bit unsigned vector referring to the program counter
* `mem` is an array of 8-bit unsigned vectors, each corresponding to a byte address in memory.
=== RV32I: Register-register
With the exception of the shift instructions, all instructions in this section have an immediate range of -2048 to 2047. Negative immediates can be useful for the bitwise operations too: for example `not rd, rs1` is a pseudo-op for `xori rd, rs1, -1`.
Shift instructions have an immediate range of 0 to 31.
==== add
Add register to register.
Syntax:
add rd, rs1, rs2
Operation:
rd = rs1 + rs2;
==== sub
Subtract register from register.
Syntax:
sub rd, rs1, rs2
Operation:
rd = rs1 - rs2;
==== slt
Set if less than (signed).
Syntax:
slt rd, rs1, rs2
Operation:
rd = $signed(rs1) < $signed(rs2);
==== sltu
Set if less than (unsigned).
Syntax:
sltu rd, rs1, rs
Operation:
rd = rs1 < rs2;
==== and
Bitwise AND.
Syntax:
and rd, rs1, rs2
Operation:
rd = rs1 & rs2;
==== or
Bitwise OR.
Syntax:
or rd, rs1, rs2`
Operation:
rd = rs1 | rs2;
==== xor
Bitwise XOR.
Syntax:
xor rd, rs1, rs2
Operation:
rd = rs1 ^ rs2;
==== sll
Shift left, logical.
Syntax:
sll rd, rs1, rs2
Operation:
rd = rs1 << rs2;
==== srl
Shift right, logical.
Syntax:
srl rd, rs1, rs2
Operation:
rd = rs1 >> rs2;
==== sra
Shift right, arithmetic.
Syntax:
sra rd, rs1, rs2
Operation:
rd = rs1 >>> rs2;
=== RV32I: Register-immediate
==== addi
Add register to immediate.
Syntax:
addi rd, rs1, imm
Operation:
rd = rs1 + imm
==== slti
Set if less than immediate (signed).
Syntax:
slti rd, rs1, imm
Operation:
rd = $signed(rs1) < $signed(imm);
==== sltiu
Set if less than immediate (unsigned).
Syntax:
sltiu rd, rs1, imm
Operation:
rd = rs1 < imm;
==== andi
Bitwise AND with immediate.
Syntax:
andi rd, rs1, imm
Operation:
rd = rs1 & imm;
==== ori
Bitwise OR with immediate.
Syntax:
ori rd, rs1, imm
Operation:
rd = rs1 \| imm;
==== xori
Bitwise XOR with immediate.
Syntax:
xori rd, rs1, imm
Operation:
rd = rs1 ^ imm;
==== slli
Shift left, logical, immediate.
Syntax:
slli rd, rs1, imm
Operation:
rd = rs1 << imm;
==== srli
Shift right, logical, immediate.
Syntax:
srli rd, rs1, imm
Operation:
rd = rs1 >> imm;
==== srai
Shift right, arithmetic, immediate.
Syntax:
srai rd, rs1, imm
Operation:
rd = rs1 >>> imm;
=== RV32I: Large immediate
==== lui
Load upper immediate.
Syntax:
lui rd, imm
Operation:
rd = imm;
(`imm` is a 20-bit value followed by 12 zeroes)
==== auipc
Add upper immediate to program counter.
Syntax:
auipc rd, imm
Operation:
rd = pc + imm;
(`imm` is a 20-bit value followed by 12 zeroes)
=== RV32I: Control transfer
==== jal
Jump and link.
Syntax:
jal rd, label
j label // rd is implicitly x0
Operation:
rd = pc + 4;
pc = label;
NOTE: the 16-bit variant, `c.jal`, writes `pc + 2` to `rd`, rather than `pc + 4`. The `rd` value always points to the sequentially-next instruction.
==== jalr
Jump and link, target is register.
Syntax:
jalr rd, rs1, imm // imm is implicitly 0 if omitted.
jr rs1, imm // rd is implicitly x0. imm is implicitly 0 if omitted.
ret // pseudo-op for jr ra
Operation:
rd = pc + 4;
pc = rs1 + imm;
NOTE: the 16-bit variant, `c.jalr`, writes `pc + 2` to `rd`, rather than `pc + 4`. The `rd` value always points to the sequentially-next instruction.
==== beq
Branch if equal.
Syntax:
beq rs1, rs2, label
Operation:
if (rs1 == rs2)
pc = label;
==== bne
Branch if not equal.
Syntax:
bne rs1, rs2, label
Operation:
if (rs1 != rs2)
pc = label;
==== blt
Branch if less than (signed).
Syntax:
blt rs1, rs2, label
Operation:
if ($signed(rs1) < $signed(rs2))
pc = label;
==== bge
Branch if greater than or equal (signed).
Syntax:
bge rs1, rs2, label
Operation:
if ($signed(rs1) >= $signed(rs2))
pc = label;
==== bltu
Branch if less than (unsigned).
Syntax:
bltu rs1, rs2, label
Operation:
if (rs1 < rs2)
pc = label;
==== bgeu
Branch if less than or equal (unsigned).
Syntax:
bgeu rs1, rs2, label
Operation:
if (rs1 >= rs2)
pc = label;
=== RV32I: Load and Store
==== lw
Load word.
Syntax:
lw rd, imm(rs1)
lw rd, (rs1) // imm is implicitly 0 if omitted.
Operation:
rd = {
mem[rs1 + imm + 3],
mem[rs1 + imm + 2],
mem[rs1 + imm + 1],
mem[rs1 + imm]
};
==== lh
Load halfword (signed).
Syntax:
lh rd, imm(rs1)
lh rd, (rs1) // imm is implicitly 0 if omitted.
Operation:
rd = {
{16{mem[rs1 + imm + 1][7]}}, // Sign-extend
mem[rs1 + imm + 1],
mem[rs1 + imm]
};
==== lhu
Load halfword (unsigned).
Syntax:
lhu rd, imm(rs1)
lhu rd, (rs1) // imm is implicitly 0 if omitted.
Operation:
rd = {
16'h0000, // Zero-extend
mem[rs1 + imm + 1],
mem[rs1 + imm]
};
==== lb
Load byte (signed).
Syntax:
lb rd, imm(rs1)
lb rd, (rs1) // imm is implicitly 0 if omitted.
Operation:
rd = {
{24{mem[rs1 + imm][7]}}, // Sign-extend
mem[rs1 + imm]
};
==== lbu
Load byte (unsigned).
Syntax:
lbu rd, imm(rs1)
lbu rd, (rs1) // imm is implicitly 0 if omitted.
Operation:
rd = {
24'h000000, // Zero-extend
mem[rs1 + imm]
};
==== sw
Store word.
Syntax:
sw rs2, imm(rs1)
sw rs2, (rs1) // imm is implicitly 0 if omitted.
Operation:
mem[rs1 + imm] = rs2[7:0];
mem[rs1 + imm + 1] = rs2[15:8];
mem[rs1 + imm + 2] = rs2[23:16];
mem[rs1 + imm + 3] = rs2[31:24];
==== sh
Store halfword.
Syntax:
sh rs2, imm(rs1)
sh rs2, (rs1) // imm is implicitly 0 if omitted.
Operation:
mem[rs1 + imm] = rs2[7:0];
mem[rs1 + imm + 1] = rs2[15:8];
==== sb
Store byte.
Syntax:
sb rs2, imm(rs1)
sb rs2, (rs1) // imm is implicitly 0 if omitted.
Operation:
mem[rs1 + imm] = rs2[7:0];
=== M Extension
==== mul
Multiply 32 × 32 -> 32.
Syntax:
mul rd, rs1, rs2
Operation:
rd = rs1 * rs2;
==== mulh
Multiply signed (32) by signed (32), return upper 32 bits of the 64-bit result.
else if (rs1 == 32'h80000000 && rs2 == 32'hffffffff) // Signed overflow
rd = 32'h80000000;
else
rd = $signed(rs1) / $signed(rs2);
==== divu
Divide (unsigned).
Syntax:
divu rd, rs1, rs2
Operation:
if (rs2 == 32'h0)
rd = 32'hffffffff;
else
rd = rs1 / rs2;
==== rem
Remainder (signed).
Syntax:
rem rd, rs1, rs2
Operation:
if (rs2 == 32'h0)
rd = rs1;
else
rd = $signed(rs1) % $signed(rs2);
==== remu
Remainder (unsigned).
Syntax:
remu rd, rs1, rs2
Operation:
if (rs2 == 32'h0)
rd = rs1;
else
rd = rs1 % rs2;
=== A Extension
(TODO)
=== C Extension
All C extension instructions are 16-bit aliases of 32-bit instructions from other extensions (in the case of Hazard3, entirely from the RV32I base extension). They behave identically to their 32-bit counterparts.