diff --git a/doc/instruction_decode_execute.rst b/doc/instruction_decode_execute.rst index 0d1be09b..920edc42 100644 --- a/doc/instruction_decode_execute.rst +++ b/doc/instruction_decode_execute.rst @@ -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) diff --git a/doc/integration.rst b/doc/integration.rst index f80dfee0..59e6f558 100644 --- a/doc/integration.rst +++ b/doc/integration.rst @@ -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 | +------------------------------+-------------+------------+-----------------------------------------------------------------+ diff --git a/lint/verilator_waiver.vlt b/lint/verilator_waiver.vlt index 2ddfcd37..f3b1f6e2 100644 --- a/lint/verilator_waiver.vlt +++ b/lint/verilator_waiver.vlt @@ -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 diff --git a/rtl/ibex_alu.sv b/rtl/ibex_alu.sv index a7bf21a6..24bf7160 100644 --- a/rtl/ibex_alu.sv +++ b/rtl/ibex_alu.sv @@ -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 diff --git a/rtl/ibex_core.sv b/rtl/ibex_core.sv index 76033d91..6e1d7fdf 100644 --- a/rtl/ibex_core.sv +++ b/rtl/ibex_core.sv @@ -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 ), diff --git a/rtl/ibex_decoder.sv b/rtl/ibex_decoder.sv index 2b1aec26..c3c0d9c9 100644 --- a/rtl/ibex_decoder.sv +++ b/rtl/ibex_decoder.sv @@ -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 diff --git a/rtl/ibex_ex_block.sv b/rtl/ibex_ex_block.sv index c7672288..fc42665d 100644 --- a/rtl/ibex_ex_block.sv +++ b/rtl/ibex_ex_block.sv @@ -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 ), diff --git a/rtl/ibex_id_stage.sv b/rtl/ibex_id_stage.sv index 10d73fdd..2a511a8e 100644 --- a/rtl/ibex_id_stage.sv +++ b/rtl/ibex_id_stage.sv @@ -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 ), diff --git a/rtl/ibex_pkg.sv b/rtl/ibex_pkg.sv index 448db40c..9dc01d11 100644 --- a/rtl/ibex_pkg.sv +++ b/rtl/ibex_pkg.sv @@ -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, diff --git a/rtl/ibex_tracer.sv b/rtl/ibex_tracer.sv index ef3b2838..6d19f17c 100644 --- a/rtl/ibex_tracer.sv +++ b/rtl/ibex_tracer.sv @@ -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 diff --git a/rtl/ibex_tracer_pkg.sv b/rtl/ibex_tracer_pkg.sv index 95270910..2ff41645 100644 --- a/rtl/ibex_tracer_pkg.sv +++ b/rtl/ibex_tracer_pkg.sv @@ -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} };