== 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 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 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