Hazard3/doc/sections/instruction_pseudocode.adoc

1220 lines
15 KiB
Plaintext
Raw Normal View History

== Instruction Pseudocode
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.
Syntax:
mulh rd, rs1, rs2
Operation:
// Both operands are sign-extended to 64 bits:
wire [63:0] result_full = {{32{rs1[31]}}, rs1} * {{32{rs2[31]}}, rs2};
rd = result_full[63:32];
==== mulhsu
Multiply signed (32) by unsigned (32), return upper 32 bits of the 64-bit result.
Syntax:
mulhsu rd, rs1, rs2
Operation:
// rs1 is sign-extended, rs2 is zero-extended:
wire [63:0] result_full = {{32{rs1[31}}, rs1} * {32'h00000000, rs2};
rd = result_full[63:32];
==== mulhu
Multiply unsigned (32) by unsigned (32), return upper 32 bits of the 64-bit result.
Syntax:
mulhu rd, rs1, rs2
Operation:
wire [63:0] result_full = {32'h00000000, rs1} * {32'h00000000, rs2};
rd = result_full[63:32];
==== div
Divide (signed).
Syntax:
div rd, rs1, rs2
Operation:
if (rs2 == 32'h0)
rd = 32'hffffffff;
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.
=== Zba: Bit manipulation (address generation)
==== sh1add
Add, with the first addend shifted left by 1.
Syntax:
sh1add rd, rs1, rs2
Operation:
rd = (rs1 << 1) + rs2;
==== sh2add
Add, with the first addend shifted left by 2.
Syntax:
sh2add rd, rs1, rs2
Operation:
rd = (rs1 << 2) + rs2;
==== sh3add
Add, with the first addend shifted left by 3.
Syntax:
sh3add rd, rs1, rs2
Operation:
rd = (rs1 << 3) + rs2;
=== Zbb: Bit manipulation (basic)
==== andn
Bitwise AND with inverted operand.
Syntax:
andn rd, rs1, rs2
Operation:
rd = rs1 & ~rs2;
==== clz
Count leading zeroes (starting from MSB, searching LSB-ward).
Syntax:
clz rd, rs1
Operation:
----
rd = 32; // Default = 32 if no set bits
reg found = 1'b0; // Local variable
for (i = 0; i < 32; i = i + 1) begin
2022-08-03 04:21:44 +08:00
if (rs1[31 - i] && !found) begin
found = 1'b1;
rd = i;
end
end
----
==== cpop
Population count.
Syntax:
cpop rd, rs1
Operation:
rd = 0;
for (i = 0; i < 32; i = i + 1)
rd = rd + rs1[i];
==== ctz
Count trailing zeroes (starting from LSB, searching MSB-ward).
Syntax:
ctz rd, rs1
Operation:
----
rd = 32; // Default = 32 if no set bits
reg found = 1'b0; // Local variable
for (i = 0; i < 32; i = i + 1) begin
2022-08-03 04:21:44 +08:00
if (rs1[i] && !found) begin
found = 1'b1;
rd = i;
end
end
----
==== max
Maximum of two values (signed).
Syntax:
max rd, rs1, rs2
Operation:
if ($signed(rs1) < $signed(rs2))
rd = rs2;
else
rd = rs1;
==== maxu
Maximum of two values (unsigned).
Syntax:
maxu rd, rs1, rs2
Operation:
if (rs1 < rs2)
rd = rs2;
else
rd = rs1;
==== min
Minimum of two values (signed).
Syntax:
min rd, rs1, rs2
Operation:
if ($signed(rs1) < $signed(rs2))
rd = rd1;
else
rd = rs2;
==== minu
Minimum of two values (unsigned).
Syntax:
minu rd, rs1, rs2
Operation:
if (rs1 < rs2)
rd = rs1;
else
rd = rs2;
==== orc.b
Or-combine of bits within each byte.
Syntax:
orc.b rd, rs1
Operation:
rd = {
{8{|rs1[31:24]}},
{8{|rs1[23:16]}},
{8{|rs1[15:8]}},
{8{|rs1[7:0]}}
};
==== orn
Bitwise OR with inverted operand.
Syntax:
orn rd, rs1, rs2
Operation:
rd = rs1 | ~rs2;
==== rev8
Reverse bytes within word.
Syntax:
rev8 rd, rs1
Operation:
rd = {
rs1[7:0],
rs1[15:8],
rs1[23:16],
rs1[31:24]
};
==== rol
Rotate left.
Syntax:
rol rd, rs1, rs2
Operation:
if (rs2[4:0] == 0)
rd = rs1;
else
rd = (rs1 << rs2[4:0]) | (rs1 >> (32 - rs2[4:0]));
==== ror
Rotate right.
Syntax:
ror rd, rs1, rs2
Operation:
if (rs2[4:0] == 0)
rd = rs1;
else
rd = (rs1 >> rs2[4:0]) | (rs1 << (32 - rs2[4:0]));
==== rori
Rotate right, immediate.
Syntax:
ror rd, rs1, imm
Operation:
if (imm[4:0] == 0)
rd = rs1;
else
rd = (rs1 >> imm[4:0]) | (rs1 << (32 - imm[4:0]));
==== sext.b
Sign-extend from byte.
Syntax:
sext.b rd, rs1
Operation:
rd = {
{24{rs1[7]}},
rs1[7:0]
};
==== sext.h
Sign-extend from halfword.
Syntax:
sext.h rd, rs1
Operation:
rd = {
{16{rs1[15]}},
rs1[15:0]
};
==== xnor
Bitwise XOR with inverted operand.
Syntax:
xnor rd, rs1, rs2
Operation:
rd = rs1 ^ ~rs2;
==== zext.h
Zero-extend from halfword.
Syntax:
zext.h rd, rs1
Operation:
rd = {
16'h0000,
rs1[15:0]
};
==== zext.b
Zero-extend from byte.
Syntax:
zext.b rd, rs1
Operation:
// Pseudo-op for RV32I instruction
andi rd, rs1, 0xff
=== Zbc: Bit manipulation (carry-less multiply)
Each of these three instructions returns a 32-bit slice of the following 64-bit result:
----
reg [63:0] clmul_result;
always @ (*) begin
clmul_result = 0;
for (i = 0; i < 32; i = i + 1) begin
if (rs2[i])) begin
clmul_result = clmul_result ^ ({32'h0, rs1} << i);
end
end
end
----
==== clmul
Carry-less multiply, low half.
Syntax:
clmul rd, rs1, rs2
Operation:
rd = cmul_result[31:0];
==== clmulh
Carry-les multiply, high half.
Syntax:
clmulh rd, rs1, rs2
Operation:
rd = clmul_result[63:32];
==== clmulr
Bit-reverse of carry-less multiply of bit-reverse.
Syntax:
clmulr rd, rs1, rs2
Operation:
rd = clmul_result[32:1];
=== Zbs: Bit manipulation (single-bit)
==== bclr
Clear single bit.
Syntax:
bclr rd, rs1, rs2
Operation:
rd = rs1 & ~(32'h1 << rs2[4:0]);
==== bclri
Clear single bit (immediate).
Syntax:
bclri rd, rs1, imm
Operation:
rd = rs1 & ~(32'h1 << imm[4:0]);
==== bext
Extract single bit.
Syntax:
bext rd, rs1, rs2
Operation:
rd = (rs1 >> rs2[4:0]) & 32'h1;
==== bexti
Extract single bit (immediate).
Syntax:
bexti rd, rs1, imm
Operation:
rd = (rs1 >> imm[4:0]) & 32'h1;
==== binv
Invert single bit.
Syntax:
binv rd, rs1, rs2
Operation:
rd = rs1 ^ (32'h1 << rs2[4:0]);
==== binvi
Invert single bit (immediate).
Syntax:
binvi rd, rs1, imm
Operation:
rd = rs1 ^ (32'h1 << imm[4:0]);
==== bset
Set single bit.
Syntax:
bset rd, rs1, rs2
Operation:
rd = rs1 | (32'h1 << rs2[4:0])
==== bseti
Set single bit (immediate).
Syntax:
bseti rd, rs1, imm
Operation:
rd = rs1 | (32'h1 << imm[4:0]);
=== Zbkb: Basic bit manipulation for cryptography
NOTE: Zbkb has a large overlap with Zbb (basic bit manipulation). This section covers only those instruction in Zbkb but not in Zbb.
==== brev8
Bit-reverse within each byte.
Syntax:
brev8 rd, rs1
Operation:
for (i = 0; i < 32; i = i + 8) begin
for (j = 0; j < 8; j = j + 1) begin
rd[i + j] = rs1[i + (7 - j)];
end
end
==== pack
Pack halfwords into word.
Syntax:
pack rd, rs1, rs2
Operation:
rd = {
rs2[15:0],
rs1[15:0]
};
==== packh
Pack bytes into halfword.
Syntax:
packh rd, rs1, rs2
Operation:
rd = {
16'h0000,
rs2[7:0],
rs1[7:0]
};
==== zip
Interleave upper/lower half of register into odd/even bits of result.
Syntax:
zip rd, rs1
Operation:
for (i = 0; i < 32; i = i + 2) begin
rd[i] = rs1[i / 2];
rd[i + 1] = rs1[i / 2 + 16];
end
==== unzip
Deinterleave odd/even bits of register into upper/lower half of result.
Syntax:
unzip rd, rs1
Operation:
for (i = 0; i < 32; i = i + 2) begin
rd[i / 2] = rs1[i];
rd[i / 2 + 16] = rs1[i + 1];
end