[bitmanip] Add ZBB Instruction Group

This commit implements the Bit Manipulation Extension ZBB instruction
group: clz, ctz, pcnt, slo, sro, rol, ror, rev, rev8, orcb, pack
packu, packh, min, max, andn, orn, and xnor.

* Bit counting instructions clz, ctz and pcnt can be implemented to
        share much of the architecture:

        clz: Count Leading Zeros. Counts the number of 0 bits at the
                MSB end of the argument.
        ctz: Count Trailing Zeros. Counts the number of 0 bits at the
                LSB end of the argument.
        pcnt: Counts the number of set bits of the argument.

        The implementation uses:

        - 32 one bit adders, counting the set bits of a signal
                bitcnt_bits, starting from the LSB end.

        - For pcnt the argument is fed directly into bitcnt_bits.

        - For clz, the operand is reversed such that leading zeros are
                located at the LSB end of bitcnt_bits.

        - For ctz and clz: counter enable signal for 1-bit counter i
                is high, if the previous enable signal, and
                its corresponting bitcnt_bit was high.

* Instructions sll[i], srl[i],slo[i], sro[i], rol, ror[i], rev, rev8
        and orc.b are summarized as shifting instructions and related:

        The following instructions are slight variations of the
        existing base spec's sll, srl and sra instructions.

        - slo[i] and sro[i]: shift left/right ones: similar to
                shift-logical operations from base spec, but shifting
                in ones instead of zeros.

        - rol and ror[i]: rotate left/right ones: circular shift
                operations. shifting in values from the oposite end
                of the operand instead of zeros.

        Those instructions can be implemented, sharing the base spec's
        shifting structure. In order to support rotate operations, a
        64-bit shifting structure is needed.

        In the existing ALU, hardware is described only for right
        shifts. For left shifts the operand is initially reversed,
        right shifted and the result is reversed back. This gives rise
        to an additional resource sharing oportunity for some more
        zbb operations:

        - rev: bitwise reversal.

        - rev8: byte-order swap.

        - orc.b: byte-wise reverse and or-combine.

* Instructions min, max:
        For the B-extension's min/max instructions, we can share the
        existing comparison operations. The result is obtained by
        activating the comparison structure accordingly and
        multiplexing the operands using the comparison result.

* Logic-with-negate instructions andn, orn, xnor:
        For the B-extension's logic-with-negate instructions we can
        share the structures of the base spec's logic structures
        already present for 'xnor', 'or' and 'and' instructions as
        well as the conditionally negated b operand generated for
        subtraction operations.

* Instructions pack, packu, packh:
        For the pack, packh and packu instructions I don't see any
        opportunities for resource sharing. However, the architecture
        is quite simple.

        - pack: pack the lower halves of rs1 and rs2 into rd, with rs1
                in the lower half and rs2 in the upper half.

        - packu: pack the upper halves of rs1 and rs2 into rd, with
                rs1 in the lower half and rs2 in the upper half.

        - packh: pack the LSB bytes of rs1 and rs2 into rd, with rs1
                in the lower half and rs2 in the upper half.

Signed-off-by: ganoam <gnoam@live.com>
This commit is contained in:
ganoam 2020-03-10 09:41:16 +01:00 committed by Pirmin Vogel
parent 158e9b9714
commit 8a26111f40
11 changed files with 448 additions and 79 deletions

View file

@ -64,6 +64,11 @@ Other blocks use the ALU for the following tasks:
* It computes memory addresses for loads and stores with a Reg + Imm calculation
* The LSU uses it to increment addresses when performing two accesses to handle an unaligned access
Support for the RISC-V Bitmanipulation Extension is enabled via the parameter ``RV32B``.
This feature is *EXPERIMENTAL* and the details of its impact are not yet documented here.
Currently only the Zbb base extension is implemented.
All instructions are carried out in a single clock cycle.
.. _mult-div:
Multiplier/Divider Block (MULT/DIV)

View file

@ -19,6 +19,7 @@ Instantiation Template
.MHPMCounterWidth ( 40 ),
.RV32E ( 0 ),
.RV32M ( 1 ),
.RV32B ( 0 ),
.MultiplierImplementation ( "fast" ),
.ICache ( 0 ),
.ICacheECC ( 0 ),
@ -89,6 +90,9 @@ Parameters
+------------------------------+-------------+------------+-----------------------------------------------------------------+
| ``RV32M`` | bit | 1 | M(ultiply) extension enable |
+------------------------------+-------------+------------+-----------------------------------------------------------------+
| ``RV32B`` | bit | 0 | *EXPERIMENTAL* - B(itmanipulation) extension enable: |
| | | | Currently supported Z-extensions: Zbb (base) |
+------------------------------+-------------+------------+-----------------------------------------------------------------+
| ``BranchTargetALU`` | bit | 0 | *EXPERIMENTAL* - Enables branch target ALU removing a stall |
| | | | cycle from taken branches |
+------------------------------+-------------+------------+-----------------------------------------------------------------+

View file

@ -30,9 +30,13 @@ lint_off -rule DECLFILENAME -file "*/rtl/ibex_register_file_fpga.sv"
// cleaner to write all bits even if not all are used
lint_off -rule UNUSED -file "*/rtl/ibex_if_stage.sv" -match "*'fetch_addr_n'[0]*"
// Bits of signal are not used: shift_right_result_ext[32]
// cleaner to write all bits even if not all are used
lint_off -rule UNUSED -file "*/rtl/ibex_alu.sv" -match "*'shift_right_result_ext'[32]*"
// Signal is not used, if RVB == 0: shift_result_ext_rvb
// Needed if RVB == 1.
lint_off -rule UNUSED -file "*/rtl/ibex_alu.sv" -match "*'shift_result_ext_rvb'*"
// Signal is not used, if RVB == 1: shift_result_ext
// Needed if RVB == 0.
lint_off -rule UNUSED -file "*/rtl/ibex_alu.sv" -match "*'shift_result_ext'*"
// Bits of signal are not used: alu_adder_ext_i[0]
// Bottom bit is round, not needed

View file

@ -6,7 +6,9 @@
/**
* Arithmetic logic unit
*/
module ibex_alu (
module ibex_alu #(
parameter bit RV32B = 1'b0
) (
input ibex_pkg::alu_op_e operator_i,
input logic [31:0] operand_a_i,
input logic [31:0] operand_b_i,
@ -43,7 +45,6 @@ module ibex_alu (
always_comb begin
adder_op_b_negate = 1'b0;
unique case (operator_i)
// Adder OPs
ALU_SUB,
@ -52,7 +53,16 @@ module ibex_alu (
ALU_EQ, ALU_NE,
ALU_GE, ALU_GEU,
ALU_LT, ALU_LTU,
ALU_SLT, ALU_SLTU: adder_op_b_negate = 1'b1;
ALU_SLT, ALU_SLTU,
// MinMax OPs (RV32B Ops)
ALU_MIN, ALU_MINU,
ALU_MAX, ALU_MAXU,
// Logic-with-negate OPs (RV32B Ops)
ALU_XNOR,
ALU_ORN,
ALU_ANDN: adder_op_b_negate = 1'b1;
default:;
endcase
@ -63,7 +73,7 @@ module ibex_alu (
// prepare operand b
assign operand_b_neg = {operand_b_i,1'b0} ^ {33{adder_op_b_negate}};
assign adder_in_b = multdiv_sel_i ? multdiv_operand_b_i : operand_b_neg ;
assign adder_in_b = multdiv_sel_i ? multdiv_operand_b_i : operand_b_neg;
// actual adder
assign adder_result_ext_o = $unsigned(adder_in_a) + $unsigned(adder_in_b);
@ -76,43 +86,93 @@ module ibex_alu (
// Shift //
///////////
logic shift_left; // should we shift left
logic shift_arithmetic;
logic shift_left;
logic shift_ones;
logic shift_arith;
logic shift_rot;
logic shift_none;
logic shift_op_rev;
logic shift_op_rev8;
logic shift_op_orc_b;
logic [4:0] shift_amt;
assign shift_amt = operand_b_i[4:0];
assign shift_left = RV32B ? (operator_i == ALU_ROL) || (operator_i == ALU_SLO) ||
(operator_i == ALU_SLL) :
(operator_i == ALU_SLL);
assign shift_ones = RV32B ? (operator_i == ALU_SLO) || (operator_i == ALU_SRO) : 1'b0;
assign shift_arith = (operator_i == ALU_SRA);
assign shift_rot = RV32B ? (operator_i == ALU_ROL) || (operator_i == ALU_ROR) : 1'b0;
assign shift_none = RV32B ? (operator_i == ALU_REV) || (operator_i == ALU_REV8) ||
(operator_i == ALU_ORCB) :
1'b0;
assign shift_op_rev = RV32B ? (operator_i == ALU_REV) : 1'b0;
assign shift_op_rev8 = RV32B ? (operator_i == ALU_REV8) : 1'b0;
assign shift_op_orc_b = RV32B ? (operator_i == ALU_ORCB) : 1'b0;
logic [4:0] shift_amt; // amount of shift, to the right
logic [31:0] shift_op_a; // input of the shifter
logic [31:0] shift_result;
logic [31:0] shift_right_result;
logic [31:0] shift_left_result;
logic [31:0] shift_extension_rvb;
logic shift_extension;
logic [32:0] shift_result_ext;
logic [63:0] shift_result_ext_rvb;
assign shift_amt = operand_b_i[4:0];
assign shift_left = (operator_i == ALU_SLL);
always_comb begin
shift_result = operand_a_i;
assign shift_arithmetic = (operator_i == ALU_SRA);
// select bit reversed or normal input
if (shift_op_rev || shift_left) begin
shift_result = operand_a_rev;
end
// choose the bit reversed or the normal input for shift operand a
assign shift_op_a = shift_left ? operand_a_rev : operand_a_i;
if (RV32B) begin
// rotation: extend with a copy of the operand
// shift-ones: extend with ones
// arithmetic shift: sign-extend.
// else: zero-extend.
shift_extension_rvb = shift_rot ?
shift_result :
{32{shift_ones || (shift_arith && operand_a_i[31])}};
// right shifts, we let the synthesizer optimize this
logic [32:0] shift_op_a_32;
assign shift_op_a_32 = {shift_arithmetic & shift_op_a[31], shift_op_a};
shift_result_ext_rvb = {shift_extension_rvb, shift_result} >> shift_amt;
end else begin
shift_extension = (shift_arith && shift_result[31]);
shift_result_ext = $signed({shift_extension, shift_result}) >>> shift_amt;
end
// The MSB of shift_right_result_ext can safely be ignored. We just extend the input to always
// do arithmetic shifts.
logic signed [32:0] shift_right_result_signed;
logic [32:0] shift_right_result_ext;
assign shift_right_result_signed = $signed(shift_op_a_32) >>> shift_amt[4:0];
assign shift_right_result_ext = $unsigned(shift_right_result_signed);
assign shift_right_result = shift_right_result_ext[31:0];
// shift, if this is a shift operation
if (!shift_none) begin
shift_result = RV32B ? shift_result_ext_rvb[31:0] : shift_result_ext[31:0];
end
// bit reverse the shift_right_result for left shifts
for (genvar j = 0; j < 32; j++) begin : gen_rev_shift_right_result
assign shift_left_result[j] = shift_right_result[31-j];
// shift left: bytewise reverse. (orcomnine with '0)
// orc_b: bytewise reverse and orcombine.
if (shift_op_orc_b || shift_left) begin
shift_result = (shift_op_orc_b ? shift_result : 32'h 0) |
((shift_result & 32'h 55555555) << 1) |
((shift_result & 32'h AAAAAAAA) >> 1);
shift_result = (shift_op_orc_b ? shift_result : 32'h 0) |
((shift_result & 32'h 33333333) << 2) |
((shift_result & 32'h CCCCCCCC) >> 2);
shift_result = (shift_op_orc_b ? shift_result : 32'h 0) |
((shift_result & 32'h 0F0F0F0F) << 4) |
((shift_result & 32'h F0F0F0F0) >> 4);
end
// byte-swap
if (shift_op_rev8 || shift_left) begin
shift_result = ((shift_result & 32'h 00FF00FF) << 8) |
((shift_result & 32'h FF00FF00) >> 8);
shift_result = ((shift_result & 32'h 0000FFFF) << 16) |
((shift_result & 32'h FFFF0000) >> 16);
end
end
assign shift_result = shift_left ? shift_left_result : shift_right_result;
////////////////
// Comparison //
////////////////
@ -123,13 +183,13 @@ module ibex_alu (
always_comb begin
cmp_signed = 1'b0;
unique case (operator_i)
ALU_GE,
ALU_LT,
ALU_SLT: begin
cmp_signed = 1'b1;
end
ALU_SLT,
// RV32B only
ALU_MIN,
ALU_MAX: cmp_signed = 1'b1;
default:;
endcase
@ -164,13 +224,14 @@ module ibex_alu (
always_comb begin
cmp_result = is_equal;
unique case (operator_i)
ALU_EQ: cmp_result = is_equal;
ALU_NE: cmp_result = ~is_equal;
ALU_GE, ALU_GEU: cmp_result = is_greater_equal;
ALU_LT, ALU_LTU,
ALU_SLT, ALU_SLTU: cmp_result = ~is_greater_equal;
ALU_EQ: cmp_result = is_equal;
ALU_NE: cmp_result = ~is_equal;
ALU_GE, ALU_GEU,
ALU_MAX, ALU_MAXU: cmp_result = is_greater_equal; // RV32B only
ALU_LT, ALU_LTU,
ALU_MIN, ALU_MINU, //RV32B only
ALU_SLT, ALU_SLTU: cmp_result = ~is_greater_equal;
default:;
endcase
@ -178,6 +239,88 @@ module ibex_alu (
assign comparison_result_o = cmp_result;
logic [31:0] minmax_result;
logic [5:0] bitcnt_result;
logic [31:0] bwlogic_result;
logic [31:0] pack_result;
///////////////////
// Bitwise Logic //
///////////////////
logic bwlogic_or;
logic bwlogic_and;
logic [31:0] bwlogic_operand_b;
assign bwlogic_or = (operator_i == ALU_OR) || (operator_i == ALU_ORN);
assign bwlogic_and = (operator_i == ALU_AND) || (operator_i == ALU_ANDN);
assign bwlogic_operand_b = RV32B ? operand_b_neg[32:1] : operand_b_i;
always_comb begin
unique case (1'b1)
bwlogic_or: bwlogic_result = operand_a_i | bwlogic_operand_b;
bwlogic_and: bwlogic_result = operand_a_i & bwlogic_operand_b;
default: bwlogic_result = operand_a_i ^ bwlogic_operand_b;
endcase
end
if (RV32B) begin : g_alu_rvb
///////////////
// Min / Max //
///////////////
assign minmax_result = (cmp_result ? operand_a_i : operand_b_i);
/////////////////
// Bitcounting //
/////////////////
logic bitcnt_ctz;
logic bitcnt_pcnt;
logic [31:0] bitcnt_bits;
logic [32:0] bitcnt_bit_enable;
assign bitcnt_ctz = (operator_i == ALU_CTZ);
assign bitcnt_pcnt = (operator_i == ALU_PCNT);
assign bitcnt_bits = bitcnt_pcnt ? operand_a_i : (bitcnt_ctz ? ~operand_a_i : ~operand_a_rev);
always_comb begin
bitcnt_result = '0;
bitcnt_bit_enable = {32'b0, 1'b1}; // bit 32 unused.
for (int unsigned i=0; i<32; i++) begin : gen_bitcnt_adder
// keep counting if all previous bits are 1
bitcnt_bit_enable[i+1] = bitcnt_pcnt || (bitcnt_bit_enable[i] && bitcnt_bits[i]);
if (bitcnt_bit_enable[i]) begin
bitcnt_result[5:0] = bitcnt_result[5:0] + {5'h0, bitcnt_bits[i]};
end
end
end
//////////
// Pack //
//////////
logic packu;
logic packh;
assign packu = (operator_i == ALU_PACKU);
assign packh = (operator_i == ALU_PACKH);
always_comb begin
unique case (1'b1)
packu: pack_result = {operand_b_i[31:16], operand_a_i[31:16]};
packh: pack_result = {16'h0, operand_b_i[7:0], operand_a_i[7:0]};
default: pack_result = {operand_b_i[15:0], operand_a_i[15:0]};
endcase
end
end else begin : g_no_alu_rvb
// Rvb result signals
assign minmax_result = '0;
assign bitcnt_result = '0;
assign pack_result = '0;
end
////////////////
// Result mux //
////////////////
@ -186,17 +329,22 @@ module ibex_alu (
result_o = '0;
unique case (operator_i)
// Standard Operations
ALU_AND: result_o = operand_a_i & operand_b_i;
ALU_OR: result_o = operand_a_i | operand_b_i;
ALU_XOR: result_o = operand_a_i ^ operand_b_i;
// Bitwise Logic Operations (negate: RV32B Ops)
ALU_XOR, ALU_XNOR,
ALU_OR, ALU_ORN,
ALU_AND, ALU_ANDN: result_o = bwlogic_result;
// Adder Operations
ALU_ADD, ALU_SUB: result_o = adder_result;
// Shift Operations
ALU_SLL,
ALU_SRL, ALU_SRA: result_o = shift_result;
ALU_SLL, ALU_SRL,
ALU_SRA,
// RV32B Ops
ALU_SLO, ALU_SRO,
ALU_ROL, ALU_ROR,
ALU_REV, ALU_REV8,
ALU_ORCB: result_o = shift_result;
// Comparison Operations
ALU_EQ, ALU_NE,
@ -204,7 +352,19 @@ module ibex_alu (
ALU_LT, ALU_LTU,
ALU_SLT, ALU_SLTU: result_o = {31'h0,cmp_result};
default:;
// MinMax Operations (RV32B Ops)
ALU_MIN, ALU_MAX,
ALU_MINU, ALU_MAXU: result_o = minmax_result;
// Bitcount Operations (RV32B Ops)
ALU_CLZ, ALU_CTZ,
ALU_PCNT: result_o = {26'h0, bitcnt_result};
// Pack Operations (RV32B Ops)
ALU_PACK, ALU_PACKH,
ALU_PACKU: result_o = pack_result;
default: ;
endcase
end

View file

@ -18,6 +18,7 @@ module ibex_core #(
parameter int unsigned MHPMCounterWidth = 40,
parameter bit RV32E = 1'b0,
parameter bit RV32M = 1'b1,
parameter bit RV32B = 1'b0,
parameter bit BranchTargetALU = 1'b0,
parameter bit WritebackStage = 1'b0,
parameter MultiplierImplementation = "fast",
@ -415,6 +416,7 @@ module ibex_core #(
ibex_id_stage #(
.RV32E ( RV32E ),
.RV32M ( RV32M ),
.RV32B ( RV32B ),
.BranchTargetALU ( BranchTargetALU ),
.WritebackStage ( WritebackStage )
) id_stage_i (
@ -559,12 +561,12 @@ module ibex_core #(
ibex_ex_block #(
.RV32M ( RV32M ),
.RV32B ( RV32B ),
.BranchTargetALU ( BranchTargetALU ),
.MultiplierImplementation ( MultiplierImplementation )
) ex_block_i (
.clk_i ( clk ),
.rst_ni ( rst_ni ),
// ALU signal from ID stage
.alu_operator_i ( alu_operator_ex ),
.alu_operand_a_i ( alu_operand_a_ex ),

View file

@ -20,6 +20,7 @@
module ibex_decoder #(
parameter bit RV32E = 0,
parameter bit RV32M = 1,
parameter bit RV32B = 0,
parameter bit BranchTargetALU = 0
) (
input logic clk_i,
@ -273,9 +274,9 @@ module ibex_decoder #(
// store size
unique case (instr[13:12])
2'b00: data_type_o = 2'b10; // SB
2'b01: data_type_o = 2'b01; // SH
2'b10: data_type_o = 2'b00; // SW
2'b00: data_type_o = 2'b10; // sb
2'b01: data_type_o = 2'b01; // sh
2'b10: data_type_o = 2'b00; // sw
default: illegal_insn = 1'b1;
endcase
end
@ -290,12 +291,12 @@ module ibex_decoder #(
// load size
unique case (instr[13:12])
2'b00: data_type_o = 2'b10; // LB(U)
2'b01: data_type_o = 2'b01; // LH(U)
2'b00: data_type_o = 2'b10; // lb(u)
2'b01: data_type_o = 2'b01; // lh(u)
2'b10: begin
data_type_o = 2'b00; // LW
data_type_o = 2'b00; // lw
if (instr[14]) begin
illegal_insn = 1'b1; // LWU does not exist
illegal_insn = 1'b1; // lwu does not exist
end
end
default: begin
@ -329,24 +330,43 @@ module ibex_decoder #(
3'b111: illegal_insn = 1'b0;
3'b001: begin
if (instr[31:25] != 7'b0) begin
illegal_insn = 1'b1;
end
unique case (instr[31:25])
7'b000_0000: illegal_insn = 1'b0; // slli
7'b001_0000: illegal_insn = RV32B ? 1'b0 : 1'b1; // sloi
7'b011_0000: begin
unique case(instr[24:20])
5'b00000, // clz
5'b00001, // ctz
5'b00010: illegal_insn = RV32B ? 1'b0 : 1'b1; // pcnt
default: illegal_insn = 1'b1;
endcase
end
default : illegal_insn = 1'b1;
endcase
end
3'b101: begin
if (instr[31:25] == 7'b0) begin
illegal_insn = 1'b0;
end else if (instr[31:25] == 7'b010_0000) begin
illegal_insn = 1'b0;
end else begin
illegal_insn = 1'b1;
end
unique case (instr[31:25])
7'b000_0000, // srli
7'b010_0000: illegal_insn = 1'b0; // srai
7'b001_0000, // sroi
7'b011_0000: illegal_insn = RV32B ? 1'b0 : 1'b1; // rori
7'b011_0100: begin
unique case(instr[24:20])
5'b11111, // rev
5'b11000, // rev8
5'b00111: illegal_insn = RV32B ? 1'b0 : 1'b1; // orc.b
default: illegal_insn = 1'b1;
endcase
end
default: illegal_insn = 1'b1;
endcase
end
default: begin
illegal_insn = 1'b1;
end
default: illegal_insn = 1'b1;
endcase
end
@ -371,6 +391,22 @@ module ibex_decoder #(
{6'b00_0000, 3'b101},
{6'b10_0000, 3'b101}: illegal_insn = 1'b0;
// supported RV32B instructions (zbb)
{6'b10_0000, 3'b111}, // andn
{6'b10_0000, 3'b110}, // orn
{6'b10_0000, 3'b100}, // xnor
{6'b01_0000, 3'b001}, // slo
{6'b01_0000, 3'b101}, // sro
{6'b11_0000, 3'b001}, // rol
{6'b11_0000, 3'b101}, // ror
{6'b00_0101, 3'b100}, // min
{6'b00_0101, 3'b101}, // max
{6'b00_0101, 3'b110}, // minu
{6'b00_0101, 3'b111}, // maxu
{6'b00_0100, 3'b100}, // pack
{6'b10_0100, 3'b100}, // packu
{6'b00_0100, 3'b111}: illegal_insn = RV32B ? 1'b0 : 1'b1; // packh
// supported RV32M instructions
{6'b00_0001, 3'b000}: begin // mul
multdiv_operator_o = MD_OP_MULL;
@ -700,14 +736,60 @@ module ibex_decoder #(
3'b111: alu_operator_o = ALU_AND; // And with Immediate
3'b001: begin
alu_operator_o = ALU_SLL; // Shift Left Logical by Immediate
if (RV32B) begin
// We don't factor in instr[31] here to make the ALU decoder more symmetric for
// Reg-Reg and Reg-Imm ALU operations. Instr[31] is only needed to detect illegal
// encodings for Reg-Reg ALU operations (see non-ALU decoder).
unique case (instr[30:25])
6'b00_0000: alu_operator_o = ALU_SLL; // Shift Left Logical by Immediate
6'b01_0000: alu_operator_o = ALU_SLO; // Shift Left Ones by Immediate
6'b11_0000: begin
unique case (instr[24:20])
5'b00000: alu_operator_o = ALU_CLZ; // Count Leading Zeros
5'b00001: alu_operator_o = ALU_CTZ; // Count Trailing Zeros
5'b00010: alu_operator_o = ALU_PCNT; // Count Set Bits
default: ;
endcase
end
default: ;
endcase
end else begin
alu_operator_o = ALU_SLL; // Shift Left Logical by Immediate
end
end
3'b101: begin
if (instr_alu[31:25] == 7'b0) begin
alu_operator_o = ALU_SRL; // Shift Right Logical by Immediate
end else if (instr_alu[31:25] == 7'b010_0000) begin
alu_operator_o = ALU_SRA; // Shift Right Arithmetically by Immediate
if (RV32B) begin
// We don't factor in instr[31] here to make the ALU decoder more symmetric for
// Reg-Reg and Reg-Imm ALU operations. Instr[31] is only needed to detect illegal
// encodings for Reg-Reg ALU operations (see non-ALU decoder).
unique case (instr_alu[30:25])
6'b00_0000: alu_operator_o = ALU_SRL; // Shift Right Logical by Immediate
6'b10_0000: alu_operator_o = ALU_SRA; // Shift Right Arithmetically by Immediate
6'b01_0000: alu_operator_o = ALU_SRO; // Shift Right Ones by Immediate
6'b11_0000: alu_operator_o = ALU_ROR; // Rotate Right by Immediate
6'b11_0100: begin
if (instr_alu[24:20] == 5'b11111) begin
alu_operator_o = ALU_REV; // Reverse
end else if (instr_alu[24:20] == 5'b11000) begin
alu_operator_o = ALU_REV8; // Byte-swap
end
end
6'b01_0100: begin
if (instr_alu[24:20] == 5'b00111) begin
alu_operator_o = ALU_ORCB; // Byte-wise Reverse and Or-Combine
end
end
default: ;
endcase
end else begin
if (instr_alu[31:25] == 7'b0) begin
alu_operator_o = ALU_SRL; // Shift Right Logical by Immediate
end else if (instr_alu[31:25] == 7'b010_0000) begin
alu_operator_o = ALU_SRA; // Shift Right Arithmetically by Immediate
end
end
end
@ -732,6 +814,25 @@ module ibex_decoder #(
{6'b00_0000, 3'b101}: alu_operator_o = ALU_SRL; // Shift Right Logical
{6'b10_0000, 3'b101}: alu_operator_o = ALU_SRA; // Shift Right Arithmetic
// RV32B ALU Operations
{6'b01_0000, 3'b001}: if (RV32B) alu_operator_o = ALU_SLO; // Shift Left Ones
{6'b01_0000, 3'b101}: if (RV32B) alu_operator_o = ALU_SRO; // Shift Right Ones
{6'b11_0000, 3'b001}: if (RV32B) alu_operator_o = ALU_ROL; // Rotate Left
{6'b11_0000, 3'b101}: if (RV32B) alu_operator_o = ALU_ROR; // Rotate Right
{6'b00_0101, 3'b100}: if (RV32B) alu_operator_o = ALU_MIN; // Minimum
{6'b00_0101, 3'b101}: if (RV32B) alu_operator_o = ALU_MAX; // Maximum
{6'b00_0101, 3'b110}: if (RV32B) alu_operator_o = ALU_MINU; // Minimum Unsigned
{6'b00_0101, 3'b111}: if (RV32B) alu_operator_o = ALU_MAXU; // Maximum Unsigned
{6'b00_0100, 3'b100}: if (RV32B) alu_operator_o = ALU_PACK; // Pack Lower Halves
{6'b10_0100, 3'b100}: if (RV32B) alu_operator_o = ALU_PACKU; // Pack Upper Halves
{6'b00_0100, 3'b111}: if (RV32B) alu_operator_o = ALU_PACKH; // Pack LSB Bytes
{6'b10_0000, 3'b100}: if (RV32B) alu_operator_o = ALU_XNOR; // Xnor
{6'b10_0000, 3'b110}: if (RV32B) alu_operator_o = ALU_ORN; // Orn
{6'b10_0000, 3'b111}: if (RV32B) alu_operator_o = ALU_ANDN; // Andn
// supported RV32M instructions, all use the same ALU operation
{6'b00_0001, 3'b000}, // mul
{6'b00_0001, 3'b001}, // mulh

View file

@ -10,6 +10,7 @@
*/
module ibex_ex_block #(
parameter bit RV32M = 1,
parameter bit RV32B = 0,
parameter bit BranchTargetALU = 0,
parameter MultiplierImplementation = "fast"
) (
@ -93,7 +94,9 @@ module ibex_ex_block #(
// ALU //
/////////
ibex_alu alu_i (
ibex_alu #(
.RV32B( RV32B )
) alu_i (
.operator_i ( alu_operator_i ),
.operand_a_i ( alu_operand_a_i ),
.operand_b_i ( alu_operand_b_i ),

View file

@ -19,6 +19,7 @@
module ibex_id_stage #(
parameter bit RV32E = 0,
parameter bit RV32M = 1,
parameter bit RV32B = 0,
parameter bit BranchTargetALU = 0,
parameter bit WritebackStage = 0
) (
@ -360,6 +361,7 @@ module ibex_id_stage #(
ibex_decoder #(
.RV32E ( RV32E ),
.RV32M ( RV32M ),
.RV32B ( RV32B ),
.BranchTargetALU ( BranchTargetALU )
) decoder_i (
.clk_i ( clk_i ),

View file

@ -32,7 +32,7 @@ typedef enum logic [6:0] {
// ALU operations //
////////////////////
typedef enum logic [4:0] {
typedef enum logic [5:0] {
// Arithmetics
ALU_ADD,
ALU_SUB,
@ -41,11 +41,23 @@ typedef enum logic [4:0] {
ALU_XOR,
ALU_OR,
ALU_AND,
// RV32B
ALU_XNOR,
ALU_ORN,
ALU_ANDN,
// Shifts
ALU_SRA,
ALU_SRL,
ALU_SLL,
// RV32B
ALU_SRO,
ALU_SLO,
ALU_ROR,
ALU_ROL,
ALU_REV,
ALU_REV8,
ALU_ORCB,
// Comparisons
ALU_LT,
@ -54,6 +66,23 @@ typedef enum logic [4:0] {
ALU_GEU,
ALU_EQ,
ALU_NE,
// RV32B
ALU_MIN,
ALU_MINU,
ALU_MAX,
ALU_MAXU,
// Pack
// RV32B
ALU_PACK,
ALU_PACKU,
ALU_PACKH,
// Bitcounting
// RV32B
ALU_CLZ,
ALU_CTZ,
ALU_PCNT,
// Set lower than
ALU_SLT,

View file

@ -399,6 +399,11 @@ module ibex_tracer (
decoded_str = $sformatf("%s\tx%0d,x%0d,x%0d", mnemonic, rvfi_rd_addr, rvfi_rs1_addr, rvfi_rs2_addr);
endfunction
function automatic void decode_r1_insn(input string mnemonic);
data_accessed = RS1 | RD;
decoded_str = $sformatf("%s\tx%0d,x%0d", mnemonic, rvfi_rd_addr, rvfi_rs1_addr);
endfunction
function automatic void decode_i_insn(input string mnemonic);
data_accessed = RS1 | RD;
decoded_str = $sformatf("%s\tx%0d,x%0d,%0d", mnemonic, rvfi_rd_addr, rvfi_rs1_addr,
@ -406,7 +411,7 @@ module ibex_tracer (
endfunction
function automatic void decode_i_shift_insn(input string mnemonic);
// SLLI, SRLI, SRAI
// SLLI, SRLI, SRAI, SROI, SLOI, RORI
logic [4:0] shamt;
shamt = {rvfi_insn[24:20]};
data_accessed = RS1 | RD;
@ -842,6 +847,31 @@ module ibex_tracer (
// MISC-MEM
INSN_FENCE: decode_fence();
INSN_FENCEI: decode_mnemonic("fence.i");
// RV32B
INSN_SLOI: decode_i_shift_insn("sloi");
INSN_SROI: decode_i_shift_insn("sroi");
INSN_RORI: decode_i_shift_insn("rori");
INSN_SLO: decode_r_insn("slo");
INSN_SRO: decode_r_insn("sro");
INSN_ROL: decode_r_insn("rol");
INSN_ROR: decode_r_insn("ror");
INSN_MIN: decode_r_insn("min");
INSN_MAX: decode_r_insn("max");
INSN_MINU: decode_r_insn("minu");
INSN_MAXU: decode_r_insn("maxu");
INSN_XNOR: decode_r_insn("xnor");
INSN_ORN: decode_r_insn("orn");
INSN_ANDN: decode_r_insn("andn");
INSN_PACK: decode_r_insn("pack");
INSN_PACKH: decode_r_insn("packh");
INSN_PACKU: decode_r_insn("packu");
INSN_ORCB: decode_r_insn("orcb");
INSN_CLZ: decode_r1_insn("clz");
INSN_CTZ: decode_r1_insn("ctz");
INSN_PCNT: decode_r1_insn("pcnt");
INSN_REV: decode_r1_insn("rev");
INSN_REV8: decode_r1_insn("rev8");
default: decode_mnemonic("INVALID");
endcase
end

View file

@ -71,6 +71,35 @@ parameter logic [31:0] INSN_PMUH = { 7'b0000001, 10'b?, 3'b001, 5'b?, {OPCODE
parameter logic [31:0] INSN_PMULHSU = { 7'b0000001, 10'b?, 3'b010, 5'b?, {OPCODE_OP} };
parameter logic [31:0] INSN_PMULHU = { 7'b0000001, 10'b?, 3'b011, 5'b?, {OPCODE_OP} };
// RV32B
// ZBB
// OPIMM
parameter logic [31:0] INSN_SLOI = { 7'b00100 , 10'b?, 3'b001, 5'b?, {OPCODE_OP_IMM} };
parameter logic [31:0] INSN_SROI = { 7'b0010000 , 10'b?, 3'b101, 5'b?, {OPCODE_OP_IMM} };
parameter logic [31:0] INSN_RORI = { 7'b0110000 , 10'b?, 3'b101, 5'b?, {OPCODE_OP_IMM} };
parameter logic [31:0] INSN_CLZ = { 12'b011000000000, 5'b? , 3'b001, 5'b?, {OPCODE_OP_IMM} };
parameter logic [31:0] INSN_CTZ = { 12'b011000000001, 5'b? , 3'b001, 5'b?, {OPCODE_OP_IMM} };
parameter logic [31:0] INSN_PCNT = { 12'b011000000010, 5'b? , 3'b001, 5'b?, {OPCODE_OP_IMM} };
parameter logic [31:0] INSN_REV = { 12'b011010011111, 5'b? , 3'b101, 5'b?, {OPCODE_OP_IMM} };
parameter logic [31:0] INSN_REV8 = { 12'b011010011000, 5'b? , 3'b101, 5'b?, {OPCODE_OP_IMM} };
parameter logic [31:0] INSN_ORCB = { 12'b001010000111, 5'b? , 3'b101, 5'b?, {OPCODE_OP_IMM} };
// OP
parameter logic [31:0] INSN_SLO = { 7'b0010000, 10'b?, 3'b001, 5'b?, {OPCODE_OP} };
parameter logic [31:0] INSN_SRO = { 7'b0010000, 10'b?, 3'b101, 5'b?, {OPCODE_OP} };
parameter logic [31:0] INSN_ROL = { 7'b0110000, 10'b?, 3'b001, 5'b?, {OPCODE_OP} };
parameter logic [31:0] INSN_ROR = { 7'b0110000, 10'b?, 3'b101, 5'b?, {OPCODE_OP} };
parameter logic [31:0] INSN_MIN = { 7'b0000101, 10'b?, 3'b100, 5'b?, {OPCODE_OP} };
parameter logic [31:0] INSN_MAX = { 7'b0000101, 10'b?, 3'b101, 5'b?, {OPCODE_OP} };
parameter logic [31:0] INSN_MINU = { 7'b0000101, 10'b?, 3'b110, 5'b?, {OPCODE_OP} };
parameter logic [31:0] INSN_MAXU = { 7'b0000101, 10'b?, 3'b111, 5'b?, {OPCODE_OP} };
parameter logic [31:0] INSN_XNOR = { 7'b0100000, 10'b?, 3'b100, 5'b?, {OPCODE_OP} };
parameter logic [31:0] INSN_ORN = { 7'b0100000, 10'b?, 3'b110, 5'b?, {OPCODE_OP} };
parameter logic [31:0] INSN_ANDN = { 7'b0100000, 10'b?, 3'b111, 5'b?, {OPCODE_OP} };
parameter logic [31:0] INSN_PACK = { 7'b0000100, 10'b?, 3'b100, 5'b?, {OPCODE_OP} };
parameter logic [31:0] INSN_PACKU = { 7'b0100100, 10'b?, 3'b100, 5'b?, {OPCODE_OP} };
parameter logic [31:0] INSN_PACKH = { 7'b0000100, 10'b?, 3'b111, 5'b?, {OPCODE_OP} };
// LOAD & STORE
parameter logic [31:0] INSN_LOAD = {25'b?, {OPCODE_LOAD } };
parameter logic [31:0] INSN_STORE = {25'b?, {OPCODE_STORE} };