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

