mirror of
https://github.com/openhwgroup/cve2.git
synced 2025-04-22 04:57:25 -04:00
[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:
parent
158e9b9714
commit
8a26111f40
11 changed files with 448 additions and 79 deletions
|
@ -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)
|
||||
|
|
|
@ -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 |
|
||||
+------------------------------+-------------+------------+-----------------------------------------------------------------+
|
||||
|
|
|
@ -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
|
||||
|
|
254
rtl/ibex_alu.sv
254
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
|
||||
|
||||
|
|
|
@ -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 ),
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 ),
|
||||
|
|
|
@ -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 ),
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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} };
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue