[bitmanip] Add ZBT Instruction Group

This commits implements the Bit Manipulateion Extension ZBT instruction
group: cmix, cmov, fsr[i] and fsl. Those are instructions depend on
three ALU operands. Completeion of these instructions takes 2 clock
cycles. Additionally, the rotation shifts rol and ror are made
multicycle instructions.

All multicycle instructions take exactly two cycles to complete.

Architectural additions:

        * Multicycle Stage Register in ID stage.
                multicycle_op_stage_reg

        * Decoder generates alu_multicycle signal, to stall pipeline

        * For all ternary instructions:
                1. cycle: connect alu operands a and b to rs1 and rs2
                          respectively
                2. cycle: connect operands a and be to rs3 and rs2
                          respectively

        * Reduce the physical size of the shifter from 64 bit to 63
                bit: 32-bit operand + 1 bit for arithmetic / one-shift

        * Make rotation shifts multicycle instructions.

Instruction Details:
        * cmov:
                1. store operand a (rs1) in stage reg.
                2. return stage reg output (rs2)  or rs3.

                if rs2 != 0 the output (rs1) is already known in the
                  first cycle. -> variable latency implementation is
                  possible.

        * cmix:
                1. store rs1 & rs2 in stage reg
                2. return stage_reg_q | (rs2 & ~rs3)

                reusing bwlogic from zbb

        * rol/ror: (here: ror)
              shift_amt       = rs2 & 31;
              shift_amt_compl = (32 - shift_amt) & 31
              1. store (rs1 >> shift_amt) in stage reg
              2. return (rs1 << shift_amt_compl) | stage_reg_q

        * fsl/fsr:
        For funnel shifts, the order of applying the shift
        amount or its complement is determined by bit [5] of
        shift_amt. Pseudocode for fsr:

              shift_amt       = rs2 & 63
              shift_amt_compl = (32 - shift_amt[4:0])

              1. if (shift_amt >= 33):
                    store (rs1 >> shift_amt_compl[4:0]) in stage reg
                 else if (shift_amt <0 && shift_amt <= 31):
                    store (rs1 << shift_amt[4:0]) in stage reg
                 else if (shift_amt == 32 || shift_amt == 0):
                    store rs1 in stage reg

              2. if (shift_amt >= 33):
                    return stage_reg_q | (rs3 << shift_amt[4:0])
                 else if (shift_amt <0 && shift_amt <= 31):
                    return stage_reg_q | (rs3 >> shift_amt_compl[4:0])
                 else if (shift_amt == 32):
                    return rs3
                 else if (shift_amt == 0):
                    return rs1

Signed-off-by: ganoam <gnoam@live.com>
This commit is contained in:
ganoam 2020-03-27 18:34:49 +01:00 committed by Pirmin Vogel
parent db6f8f050e
commit 4cb77b8121
12 changed files with 679 additions and 310 deletions

View file

@ -64,9 +64,9 @@ 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``.
Support for the RISC-V Bitmanipulation Extension (Document Version 0.92, November 8, 2019) 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.
Currently the Zbb and Zbt sub-extensions are implemented.
All instructions are carried out in a single clock cycle.
.. _mult-div:

View file

@ -28,18 +28,18 @@ lint_off -rule DECLFILENAME -file "*/rtl/ibex_register_file_ff.sv"
lint_off -rule DECLFILENAME -file "*/rtl/ibex_register_file_latch.sv"
lint_off -rule DECLFILENAME -file "*/rtl/ibex_register_file_fpga.sv"
// Bits of signal are not used: shift_amt_compl[5]
// cleaner to write all bits even if not all are used
lint_off -rule UNUSED -file "*/rtl/ibex_alu.sv" -match "*'shift_amt_compl'[5]*"
// Bits of signal are not used: shift_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_result_ext'[32]*"
// Bits of signal are not used: fetch_addr_n[0]
// 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]*"
// 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
lint_off -rule UNUSED -file "*/rtl/ibex_multdiv_fast.sv" -match "*'alu_adder_ext_i'[0]*"
@ -49,7 +49,6 @@ lint_off -rule UNUSED -file "*/rtl/ibex_multdiv_fast.sv" -match "*'alu_adder_ext
lint_off -rule UNUSED -file "*/rtl/ibex_multdiv_fast.sv" -match "*mac_res_ext*"
lint_off -rule UNUSED -file "*/rtl/ibex_multdiv_fast.sv" -match "*mult1_res*"
// Bits of signal are not used: res_adder_h[32]
// cleaner to write all bits even if not all are used
lint_off -rule UNUSED -file "*/rtl/ibex_multdiv_fast.sv" -match "*'res_adder_h'[32]*"

View file

@ -13,11 +13,17 @@ module ibex_alu #(
input logic [31:0] operand_a_i,
input logic [31:0] operand_b_i,
input logic instr_first_cycle_i,
input logic [32:0] multdiv_operand_a_i,
input logic [32:0] multdiv_operand_b_i,
input logic multdiv_sel_i,
input logic [31:0] imd_val_q_i,
output logic [31:0] imd_val_d_o,
output logic imd_val_we_o,
output logic [31:0] adder_result_o,
output logic [33:0] adder_result_ext_o,
@ -57,12 +63,7 @@ module ibex_alu #(
// 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;
ALU_MAX, ALU_MAXU: adder_op_b_negate = 1'b1;
default:;
endcase
@ -72,8 +73,14 @@ module ibex_alu #(
assign adder_in_a = multdiv_sel_i ? multdiv_operand_a_i : {operand_a_i,1'b1};
// 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 operand_b_neg = {operand_b_i,1'b0} ^ {33{1'b1}};
always_comb begin
unique case(1'b1)
multdiv_sel_i: adder_in_b = multdiv_operand_b_i;
adder_op_b_negate: adder_in_b = operand_b_neg;
default : adder_in_b = {operand_b_i, 1'b0};
endcase
end
// actual adder
assign adder_result_ext_o = $unsigned(adder_in_a) + $unsigned(adder_in_b);
@ -86,26 +93,85 @@ module ibex_alu #(
// Shift //
///////////
// The shifter structure consists of a 33-bit shifter: 32-bit operand + 1 bit extension for
// arithmetic shifts and one-shift support.
// Rotations and funnel shifts are implemented as multi-cycle instructions.
// For funnel shifs, operand_a_i is tied to rs1 in the first cycle and rs3 in the
// second cycle. operand_b_i is always tied to rs2.
//
// Rotation pseudocode:
// shift_amt = rs2 & 31;
// multicycle_result = (rs1 >> shift_amt) | (rs1 << (32 - shift_amt));
// ^-- cycle 0 -----^ ^-- cycle 1 --------------^
//
// For funnel shifts, the order of applying the shift amount or its complement is determined by
// bit [5] of shift_amt.
// Funnel shift Pseudocode: (fsl)
// shift_amt = rs2 & 63;
// shift_amt_compl = 32 - shift_amt[4:0]
// if (shift_amt >=33):
// multicycle_result = (rs1 >> shift_amt_cmpl[4:0]) | (rs3 << shift_amt[4:0]);
// ^-- cycle 0 ---------------^ ^-- cycle 1 ------------^
// else if (shift_amt <= 31 && shift_amt > 0):
// multicycle_result = (rs1 << shift_amt[4:0]) | (rs3 >> shift_amt_compl[4:0]);
// ^-- cycle 0 ----------^ ^-- cycle 1 -------------------^
// For shift_amt == 0, 32, both shift_amt[4:0] and shift_amt_compl[4:0] == '0.
// these cases need to be handled separately outside the shifting structure:
// else if (shift_amt == 32):
// multicycle_result = rs3
// else if (shift_amt == 0):
// multicycle_result = rs1.
logic shift_left;
logic shift_ones;
logic shift_arith;
logic shift_rot;
logic shift_funnel;
logic shift_none;
logic shift_op_rev;
logic shift_op_rev8;
logic shift_op_orc_b;
logic [4:0] shift_amt;
logic [5:0] shift_amt;
logic [5:0] shift_amt_compl; // complementary shift amount (32 - shift_amt)
logic shift_multicycle;
assign shift_amt = operand_b_i[4:0];
// bit shift_amt[5]: word swap bit: only considered for FSL/FSR.
// if set, reverse operations in first and second cycle.
assign shift_amt[5] = operand_b_i[5] && shift_funnel;
assign shift_amt_compl = 32 - operand_b_i[4:0];
assign shift_amt[4:0] = instr_first_cycle_i ?
(operand_b_i[5] && shift_funnel ? shift_amt_compl[4:0] : operand_b_i[4:0]) :
(operand_b_i[5] && shift_funnel ? operand_b_i[4:0] : shift_amt_compl[4:0]);
// left shift if this is:
// * a standard left shift (slo, sll)
// * a rol in the first cycle
// * a ror in the second cycle
// * fsl: without word-swap bit: first cycle, else: second cycle
// * fsr: without word-swap bit: second cycle, else: first cycle
always_comb begin
unique case (operator_i)
ALU_SLL: shift_left = 1'b1;
ALU_SLO: shift_left = RV32B ? 1'b1 : 1'b0;
ALU_ROL: shift_left = RV32B ? instr_first_cycle_i : 0;
ALU_ROR: shift_left = RV32B ? !instr_first_cycle_i : 0;
ALU_FSL: shift_left =
RV32B ? (shift_amt[5] ? !instr_first_cycle_i : instr_first_cycle_i) : 1'b0;
ALU_FSR: shift_left =
RV32B ? (shift_amt[5] ? instr_first_cycle_i : !instr_first_cycle_i) : 1'b0;
default: shift_left = 1'b0;
endcase
end
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_funnel = RV32B ? (operator_i == ALU_FSL) || (operator_i == ALU_FSR) : 1'b0;
assign shift_multicycle = shift_funnel || shift_rot;
assign shift_none = RV32B ? (operator_i == ALU_REV) || (operator_i == ALU_REV8) ||
(operator_i == ALU_ORCB) :
(operator_i == ALU_ORCB) :
1'b0;
assign shift_op_rev = RV32B ? (operator_i == ALU_REV) : 1'b0;
@ -113,11 +179,7 @@ module ibex_alu #(
assign shift_op_orc_b = RV32B ? (operator_i == ALU_ORCB) : 1'b0;
logic [31:0] shift_result;
logic [31:0] shift_extension_rvb;
logic shift_extension;
logic [32:0] shift_result_ext;
logic [63:0] shift_result_ext_rvb;
always_comb begin
shift_result = operand_a_i;
@ -127,27 +189,15 @@ module ibex_alu #(
shift_result = operand_a_rev;
end
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])}};
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
shift_result_ext = $signed({shift_ones || (shift_arith && shift_result[31]), shift_result})
>>> shift_amt[4: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];
shift_result = shift_result_ext[31:0];
end
// shift left: bytewise reverse. (orcomnine with '0)
// shift left: bytewise reverse. (orcombine 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) |
@ -182,7 +232,6 @@ module ibex_alu #(
logic cmp_signed;
always_comb begin
cmp_signed = 1'b0;
unique case (operator_i)
ALU_GE,
ALU_LT,
@ -191,7 +240,7 @@ module ibex_alu #(
ALU_MIN,
ALU_MAX: cmp_signed = 1'b1;
default:;
default: cmp_signed = 1'b0;
endcase
end
@ -223,7 +272,6 @@ module ibex_alu #(
logic cmp_result;
always_comb begin
cmp_result = is_equal;
unique case (operator_i)
ALU_EQ: cmp_result = is_equal;
ALU_NE: cmp_result = ~is_equal;
@ -233,7 +281,7 @@ module ibex_alu #(
ALU_MIN, ALU_MINU, //RV32B only
ALU_SLT, ALU_SLTU: cmp_result = ~is_greater_equal;
default:;
default: cmp_result = is_equal;
endcase
end
@ -243,6 +291,7 @@ module ibex_alu #(
logic [5:0] bitcnt_result;
logic [31:0] bwlogic_result;
logic [31:0] pack_result;
logic [31:0] multicycle_result;
///////////////////
// Bitwise Logic //
@ -251,21 +300,100 @@ module ibex_alu #(
logic bwlogic_or;
logic bwlogic_and;
logic [31:0] bwlogic_operand_b;
logic [31:0] bwlogic_or_op_a;
logic [31:0] bwlogic_or_op_b;
logic [31:0] bwlogic_or_result;
logic [31:0] bwlogic_and_result;
logic [31:0] bwlogic_xor_result;
logic bwlogic_op_b_negate;
always_comb begin
unique case (operator_i)
// Logic-with-negate OPs (RV32B Ops)
ALU_XNOR,
ALU_ORN,
ALU_ANDN: bwlogic_op_b_negate = RV32B ? 1'b1 : 1'b0;
ALU_CMIX: bwlogic_op_b_negate = RV32B ? !instr_first_cycle_i : 1'b0;
default: bwlogic_op_b_negate = 1'b0;
endcase
end
assign bwlogic_operand_b = bwlogic_op_b_negate ? operand_b_neg[32:1] : operand_b_i;
assign bwlogic_or_op_a = ((operator_i == ALU_CMIX) || shift_multicycle) ?
imd_val_q_i : operand_a_i;
assign bwlogic_or_op_b = (operator_i == ALU_CMIX) ? bwlogic_and_result :
shift_multicycle ? shift_result : bwlogic_operand_b;
assign bwlogic_or_result = bwlogic_or_op_a | bwlogic_or_op_b;
assign bwlogic_and_result = operand_a_i & bwlogic_operand_b;
assign bwlogic_xor_result = operand_a_i ^ 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;
bwlogic_or: bwlogic_result = bwlogic_or_result;
bwlogic_and: bwlogic_result = bwlogic_and_result;
default: bwlogic_result = bwlogic_xor_result;
endcase
end
if (RV32B) begin : g_alu_rvb
//////////////////////////////////////
// Multicycle Bitmanip Instructions //
//////////////////////////////////////
// Ternary instructions + Shift Rotations
// For ternary instructions (zbt), operand_a_i is tied to rs1 in the first cycle and rs3 in the
// second cycle. operand_b_i is always tied to rs2.
always_comb begin
unique case (operator_i)
ALU_CMOV: begin
imd_val_d_o = operand_a_i;
multicycle_result = (operand_b_i == 32'h0) ? operand_a_i : imd_val_q_i;
if (instr_first_cycle_i) begin
imd_val_we_o = 1'b1;
end else begin
imd_val_we_o = 1'b0;
end
end
ALU_CMIX: begin
multicycle_result = bwlogic_or_result;
imd_val_d_o = bwlogic_and_result;
if (instr_first_cycle_i) begin
imd_val_we_o = 1'b1;
end else begin
imd_val_we_o = 1'b0;
end
end
ALU_FSR, ALU_FSL,
ALU_ROL, ALU_ROR: begin
if (shift_amt[4:0] == 5'h0) begin
multicycle_result = shift_amt[5] ? operand_a_i : imd_val_q_i;
end else begin
multicycle_result = bwlogic_or_result;
end
imd_val_d_o = shift_result;
if (instr_first_cycle_i) begin
imd_val_we_o = 1'b1;
end else begin
imd_val_we_o = 1'b0;
end
end
default: begin
imd_val_d_o = operand_a_i;
imd_val_we_o = 1'b0;
multicycle_result = operand_a_i;
end
endcase
end
///////////////
// Min / Max //
///////////////
@ -315,10 +443,14 @@ module ibex_alu #(
endcase
end
end else begin : g_no_alu_rvb
// Rvb result signals
assign minmax_result = '0;
assign bitcnt_result = '0;
assign pack_result = '0;
// RV32B result signals
assign minmax_result = '0;
assign bitcnt_result = '0;
assign pack_result = '0;
assign multicycle_result = '0;
// RV32B support signals
assign imd_val_d_o = '0;
assign imd_val_we_o = '0;
end
////////////////
@ -342,7 +474,6 @@ module ibex_alu #(
ALU_SRA,
// RV32B Ops
ALU_SLO, ALU_SRO,
ALU_ROL, ALU_ROR,
ALU_REV, ALU_REV8,
ALU_ORCB: result_o = shift_result;
@ -364,6 +495,11 @@ module ibex_alu #(
ALU_PACK, ALU_PACKH,
ALU_PACKU: result_o = pack_result;
// Ternary Bitmanip Operations (RV32B Ops)
ALU_CMIX, ALU_CMOV,
ALU_FSL, ALU_FSR,
ALU_ROL, ALU_ROR: result_o = multicycle_result;
default: ;
endcase
end

View file

@ -80,8 +80,10 @@ module ibex_core #(
output logic [ 1:0] rvfi_mode,
output logic [ 4:0] rvfi_rs1_addr,
output logic [ 4:0] rvfi_rs2_addr,
output logic [ 4:0] rvfi_rs3_addr,
output logic [31:0] rvfi_rs1_rdata,
output logic [31:0] rvfi_rs2_rdata,
output logic [31:0] rvfi_rs3_rdata,
output logic [ 4:0] rvfi_rd_addr,
output logic [31:0] rvfi_rd_wdata,
output logic [31:0] rvfi_pc_rdata,
@ -106,17 +108,20 @@ module ibex_core #(
// IF/ID signals
logic instr_valid_id;
logic instr_new_id;
logic [31:0] instr_rdata_id; // Instruction sampled inside IF stage
logic [31:0] instr_rdata_alu_id; // Instruction sampled inside IF stage (replicated to ease
// fan-out)
logic [15:0] instr_rdata_c_id; // Compressed instruction sampled inside IF stage
logic [31:0] instr_rdata_id; // Instruction sampled inside IF stage
logic [31:0] instr_rdata_alu_id; // Instruction sampled inside IF stage (replicated to ease
// fan-out)
logic [15:0] instr_rdata_c_id; // Compressed instruction sampled inside IF stage
logic instr_is_compressed_id;
logic instr_fetch_err; // Bus error on instr fetch
logic instr_fetch_err_plus2; // Instruction error is misaligned
logic illegal_c_insn_id; // Illegal compressed instruction sent to ID stage
logic [31:0] pc_if; // Program counter in IF stage
logic [31:0] pc_id; // Program counter in ID stage
logic [31:0] pc_wb; // Program counter in WB stage
logic instr_fetch_err; // Bus error on instr fetch
logic instr_fetch_err_plus2; // Instruction error is misaligned
logic illegal_c_insn_id; // Illegal compressed instruction sent to ID stage
logic [31:0] pc_if; // Program counter in IF stage
logic [31:0] pc_id; // Program counter in ID stage
logic [31:0] pc_wb; // Program counter in WB stage
logic [33:0] imd_val_d_ex; // Intermediate register for multicycle Ops
logic [33:0] imd_val_q_ex; // Intermediate register for multicycle Ops
logic imd_val_we_ex;
logic data_ind_timing;
logic icache_enable;
@ -125,9 +130,9 @@ module ibex_core #(
logic instr_first_cycle_id;
logic instr_valid_clear;
logic pc_set;
pc_sel_e pc_mux_id; // Mux selector for next PC
exc_pc_sel_e exc_pc_mux_id; // Mux selector for exception PC
exc_cause_e exc_cause; // Exception cause
pc_sel_e pc_mux_id; // Mux selector for next PC
exc_pc_sel_e exc_pc_mux_id; // Mux selector for exception PC
exc_cause_e exc_cause; // Exception cause
logic lsu_load_err;
logic lsu_store_err;
@ -287,13 +292,21 @@ module ibex_core #(
logic rvfi_set_trap_pc_q;
logic [31:0] rvfi_insn_id;
logic [4:0] rvfi_rs1_addr_id;
logic [4:0] rvfi_rs1_addr_d;
logic [4:0] rvfi_rs1_addr_q;
logic [4:0] rvfi_rs2_addr_id;
logic [4:0] rvfi_rs2_addr_d;
logic [4:0] rvfi_rs2_addr_q;
logic [4:0] rvfi_rs3_addr_id;
logic [4:0] rvfi_rs3_addr_d;
logic [31:0] rvfi_rs1_data_d;
logic [31:0] rvfi_rs1_data_id;
logic [31:0] rvfi_rs1_data_q;
logic [31:0] rvfi_rs2_data_d;
logic [31:0] rvfi_rs2_data_id;
logic [31:0] rvfi_rs2_data_q;
logic [31:0] rvfi_rs3_data_d;
logic [31:0] rvfi_rs3_data_id;
logic [4:0] rvfi_rd_addr_wb;
logic [4:0] rvfi_rd_addr_q;
logic [4:0] rvfi_rd_addr_d;
@ -424,13 +437,13 @@ module ibex_core #(
.DataIndTiming ( DataIndTiming ),
.WritebackStage ( WritebackStage )
) id_stage_i (
.clk_i ( clk ),
.rst_ni ( rst_ni ),
.clk_i ( clk ),
.rst_ni ( rst_ni ),
// Processor Enable
.fetch_enable_i ( fetch_enable_i ),
.ctrl_busy_o ( ctrl_busy ),
.illegal_insn_o ( illegal_insn_id ),
.fetch_enable_i ( fetch_enable_i ),
.ctrl_busy_o ( ctrl_busy ),
.illegal_insn_o ( illegal_insn_id ),
// from/to IF-ID pipeline register
.instr_valid_i ( instr_valid_id ),
@ -469,6 +482,10 @@ module ibex_core #(
.alu_operand_a_ex_o ( alu_operand_a_ex ),
.alu_operand_b_ex_o ( alu_operand_b_ex ),
.imd_val_q_ex_o ( imd_val_q_ex ),
.imd_val_d_ex_i ( imd_val_d_ex ),
.imd_val_we_ex_i ( imd_val_we_ex ),
.bt_a_operand_o ( bt_a_operand ),
.bt_b_operand_o ( bt_b_operand ),
@ -549,7 +566,6 @@ module ibex_core #(
.ready_wb_i ( ready_wb ),
.outstanding_load_wb_i ( outstanding_load_wb ),
.outstanding_store_wb_i ( outstanding_store_wb ),
// Performance Counters
.perf_jump_o ( perf_jump ),
.perf_branch_o ( perf_branch ),
@ -565,40 +581,47 @@ module ibex_core #(
assign unused_illegal_insn_id = illegal_insn_id;
ibex_ex_block #(
.RV32M ( RV32M ),
.RV32B ( RV32B ),
.BranchTargetALU ( BranchTargetALU ),
.MultiplierImplementation ( MultiplierImplementation )
.RV32M ( RV32M ),
.RV32B ( RV32B ),
.BranchTargetALU ( BranchTargetALU ),
.MultiplierImplementation ( MultiplierImplementation )
) ex_block_i (
.clk_i ( clk ),
.rst_ni ( rst_ni ),
.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 ),
.alu_operand_b_i ( alu_operand_b_ex ),
.alu_operator_i ( alu_operator_ex ),
.alu_operand_a_i ( alu_operand_a_ex ),
.alu_operand_b_i ( alu_operand_b_ex ),
.alu_instr_first_cycle_i ( instr_first_cycle_id ),
// Branch target ALU signal from ID stage
.bt_a_operand_i ( bt_a_operand ),
.bt_b_operand_i ( bt_b_operand ),
.bt_a_operand_i ( bt_a_operand ),
.bt_b_operand_i ( bt_b_operand ),
// Multipler/Divider signal from ID stage
.multdiv_operator_i ( multdiv_operator_ex ),
.mult_en_i ( mult_en_ex ),
.div_en_i ( div_en_ex ),
.multdiv_sel_i ( multdiv_sel_ex ),
.multdiv_signed_mode_i ( multdiv_signed_mode_ex ),
.multdiv_operand_a_i ( multdiv_operand_a_ex ),
.multdiv_operand_b_i ( multdiv_operand_b_ex ),
.multdiv_ready_id_i ( multdiv_ready_id ),
.multdiv_operator_i ( multdiv_operator_ex ),
.mult_en_i ( mult_en_ex ),
.div_en_i ( div_en_ex ),
.multdiv_sel_i ( multdiv_sel_ex ),
.multdiv_signed_mode_i ( multdiv_signed_mode_ex ),
.multdiv_operand_a_i ( multdiv_operand_a_ex ),
.multdiv_operand_b_i ( multdiv_operand_b_ex ),
.multdiv_ready_id_i ( multdiv_ready_id ),
// Intermediate value register
.imd_val_we_o ( imd_val_we_ex ),
.imd_val_d_o ( imd_val_d_ex ),
.imd_val_q_i ( imd_val_q_ex ),
// Outputs
.alu_adder_result_ex_o ( alu_adder_result_ex ), // to LSU
.result_ex_o ( result_ex ), // to ID
.alu_adder_result_ex_o ( alu_adder_result_ex ), // to LSU
.result_ex_o ( result_ex ), // to ID
.branch_target_o ( branch_target_ex ), // to IF
.branch_decision_o ( branch_decision ), // to ID
.branch_target_o ( branch_target_ex ), // to IF
.branch_decision_o ( branch_decision ), // to ID
.ex_valid_o ( ex_valid )
.ex_valid_o ( ex_valid )
);
/////////////////////
@ -756,7 +779,8 @@ module ibex_core #(
assign rvfi_rs1_data_id = id_stage_i.rf_rdata_a_fwd;
assign rvfi_rs2_addr_id = rf_raddr_b;
assign rvfi_rs2_data_id = id_stage_i.rf_rdata_b_fwd;
assign rvfi_rs3_addr_id = rf_raddr_a;
assign rvfi_rs3_data_id = id_stage_i.rf_rdata_a_fwd;
assign rvfi_rd_addr_wb = rf_waddr_wb;
assign rvfi_rd_wdata_wb = rf_we_wb ? rf_wdata_wb : rf_wdata_lsu;
assign rvfi_rd_we_wb = rf_we_wb | rf_we_lsu;
@ -931,8 +955,10 @@ module ibex_core #(
logic [ 1:0] rvfi_stage_mode [RVFI_STAGES-1:0];
logic [ 4:0] rvfi_stage_rs1_addr [RVFI_STAGES-1:0];
logic [ 4:0] rvfi_stage_rs2_addr [RVFI_STAGES-1:0];
logic [ 4:0] rvfi_stage_rs3_addr [RVFI_STAGES-1:0];
logic [31:0] rvfi_stage_rs1_rdata [RVFI_STAGES-1:0];
logic [31:0] rvfi_stage_rs2_rdata [RVFI_STAGES-1:0];
logic [31:0] rvfi_stage_rs3_rdata [RVFI_STAGES-1:0];
logic [ 4:0] rvfi_stage_rd_addr [RVFI_STAGES-1:0];
logic [31:0] rvfi_stage_rd_wdata [RVFI_STAGES-1:0];
logic [31:0] rvfi_stage_pc_rdata [RVFI_STAGES-1:0];
@ -954,8 +980,10 @@ module ibex_core #(
assign rvfi_mode = rvfi_stage_mode [RVFI_STAGES-1];
assign rvfi_rs1_addr = rvfi_stage_rs1_addr [RVFI_STAGES-1];
assign rvfi_rs2_addr = rvfi_stage_rs2_addr [RVFI_STAGES-1];
assign rvfi_rs3_addr = rvfi_stage_rs3_addr [RVFI_STAGES-1];
assign rvfi_rs1_rdata = rvfi_stage_rs1_rdata[RVFI_STAGES-1];
assign rvfi_rs2_rdata = rvfi_stage_rs2_rdata[RVFI_STAGES-1];
assign rvfi_rs3_rdata = rvfi_stage_rs3_rdata[RVFI_STAGES-1];
assign rvfi_rd_addr = rvfi_stage_rd_addr [RVFI_STAGES-1];
assign rvfi_rd_wdata = rvfi_stage_rd_wdata [RVFI_STAGES-1];
assign rvfi_pc_rdata = rvfi_stage_pc_rdata [RVFI_STAGES-1];
@ -1012,6 +1040,7 @@ module ibex_core #(
rvfi_stage_mode[i] <= {PRIV_LVL_M};
rvfi_stage_rs1_addr[i] <= '0;
rvfi_stage_rs2_addr[i] <= '0;
rvfi_stage_rs3_addr[i] <= '0;
rvfi_stage_pc_rdata[i] <= '0;
rvfi_stage_pc_wdata[i] <= '0;
rvfi_stage_mem_rmask[i] <= '0;
@ -1019,6 +1048,7 @@ module ibex_core #(
rvfi_stage_valid[i] <= '0;
rvfi_stage_rs1_rdata[i] <= '0;
rvfi_stage_rs2_rdata[i] <= '0;
rvfi_stage_rs3_rdata[i] <= '0;
rvfi_stage_rd_wdata[i] <= '0;
rvfi_stage_rd_addr[i] <= '0;
rvfi_stage_mem_rdata[i] <= '0;
@ -1035,14 +1065,16 @@ module ibex_core #(
rvfi_stage_order[i] <= rvfi_order + 64'(rvfi_valid);
rvfi_stage_insn[i] <= rvfi_insn_id;
rvfi_stage_mode[i] <= {priv_mode_id};
rvfi_stage_rs1_addr[i] <= rvfi_rs1_addr_id;
rvfi_stage_rs2_addr[i] <= rvfi_rs2_addr_id;
rvfi_stage_rs1_addr[i] <= rvfi_rs1_addr_d;
rvfi_stage_rs2_addr[i] <= rvfi_rs2_addr_d;
rvfi_stage_rs3_addr[i] <= rvfi_rs3_addr_d;
rvfi_stage_pc_rdata[i] <= pc_id;
rvfi_stage_pc_wdata[i] <= pc_if;
rvfi_stage_mem_rmask[i] <= rvfi_mem_mask_int;
rvfi_stage_mem_wmask[i] <= data_we_o ? rvfi_mem_mask_int : 4'b0000;
rvfi_stage_rs1_rdata[i] <= rvfi_rs1_data_d;
rvfi_stage_rs2_rdata[i] <= rvfi_rs2_data_d;
rvfi_stage_rs3_rdata[i] <= rvfi_rs3_data_d;
rvfi_stage_rd_addr[i] <= rvfi_rd_addr_d;
rvfi_stage_rd_wdata[i] <= rvfi_rd_wdata_d;
rvfi_stage_mem_rdata[i] <= rvfi_mem_rdata_d;
@ -1059,12 +1091,14 @@ module ibex_core #(
rvfi_stage_mode[i] <= rvfi_stage_mode[i-1];
rvfi_stage_rs1_addr[i] <= rvfi_stage_rs1_addr[i-1];
rvfi_stage_rs2_addr[i] <= rvfi_stage_rs2_addr[i-1];
rvfi_stage_rs3_addr[i] <= rvfi_stage_rs3_addr[i-1];
rvfi_stage_pc_rdata[i] <= rvfi_stage_pc_rdata[i-1];
rvfi_stage_pc_wdata[i] <= rvfi_stage_pc_wdata[i-1];
rvfi_stage_mem_rmask[i] <= rvfi_stage_mem_rmask[i-1];
rvfi_stage_mem_wmask[i] <= rvfi_stage_mem_wmask[i-1];
rvfi_stage_rs1_rdata[i] <= rvfi_stage_rs1_rdata[i-1];
rvfi_stage_rs2_rdata[i] <= rvfi_stage_rs2_rdata[i-1];
rvfi_stage_rs3_rdata[i] <= rvfi_stage_rs3_rdata[i-1];
rvfi_stage_rd_addr[i] <= rvfi_stage_rd_addr[i-1];
rvfi_stage_mem_wdata[i] <= rvfi_stage_mem_wdata[i-1];
rvfi_stage_mem_addr[i] <= rvfi_stage_mem_addr[i-1];
@ -1132,23 +1166,37 @@ module ibex_core #(
end
end
// Source register data are kept stable for each instruction cycle
// Source registers 1 and 2 are read in the first instruction cycle
// Source register 3 is read in the second instruction cycle.
always_comb begin
if (instr_first_cycle_id) begin
rvfi_rs1_data_d = rvfi_rs1_data_id;
rvfi_rs1_addr_d = rvfi_rs1_addr_id;
rvfi_rs2_data_d = rvfi_rs2_data_id;
rvfi_rs2_addr_d = rvfi_rs2_addr_id;
rvfi_rs3_data_d = '0;
rvfi_rs3_addr_d = '0;
end else begin
rvfi_rs1_data_d = rvfi_rs1_data_q;
rvfi_rs1_addr_d = rvfi_rs1_addr_q;
rvfi_rs2_data_d = rvfi_rs2_data_q;
rvfi_rs2_addr_d = rvfi_rs2_addr_q;
rvfi_rs3_data_d = rvfi_rs3_data_id;
rvfi_rs3_addr_d = rvfi_rs3_addr_id;
end
end
always_ff @(posedge clk or negedge rst_ni) begin
if (!rst_ni) begin
rvfi_rs1_data_q <= '0;
rvfi_rs1_addr_q <= '0;
rvfi_rs2_data_q <= '0;
rvfi_rs2_addr_q <= '0;
end else begin
rvfi_rs1_data_q <= rvfi_rs1_data_d;
rvfi_rs1_addr_q <= rvfi_rs1_addr_d;
rvfi_rs2_data_q <= rvfi_rs2_data_d;
rvfi_rs2_addr_q <= rvfi_rs2_addr_d;
end
end

View file

@ -85,8 +85,10 @@ module ibex_core_tracing #(
logic [ 1:0] rvfi_mode;
logic [ 4:0] rvfi_rs1_addr;
logic [ 4:0] rvfi_rs2_addr;
logic [ 4:0] rvfi_rs3_addr;
logic [31:0] rvfi_rs1_rdata;
logic [31:0] rvfi_rs2_rdata;
logic [31:0] rvfi_rs3_rdata;
logic [ 4:0] rvfi_rd_addr;
logic [31:0] rvfi_rd_wdata;
logic [31:0] rvfi_pc_rdata;
@ -158,8 +160,10 @@ module ibex_core_tracing #(
.rvfi_mode,
.rvfi_rs1_addr,
.rvfi_rs2_addr,
.rvfi_rs3_addr,
.rvfi_rs1_rdata,
.rvfi_rs2_rdata,
.rvfi_rs3_rdata,
.rvfi_rd_addr,
.rvfi_rd_wdata,
.rvfi_pc_rdata,
@ -190,8 +194,10 @@ module ibex_core_tracing #(
.rvfi_mode,
.rvfi_rs1_addr,
.rvfi_rs2_addr,
.rvfi_rs3_addr,
.rvfi_rs1_rdata,
.rvfi_rs2_rdata,
.rvfi_rs3_rdata,
.rvfi_rd_addr,
.rvfi_rd_wdata,
.rvfi_pc_rdata,

View file

@ -6,6 +6,7 @@
// Source/Destination register instruction index
`define REG_S1 19:15
`define REG_S2 24:20
`define REG_S3 31:27
`define REG_D 11:07
/**
@ -73,6 +74,7 @@ module ibex_decoder #(
// immediate or zero
output ibex_pkg::op_b_sel_e alu_op_b_mux_sel_o, // operand b selection: reg value or
// immediate
output logic alu_multicycle_o, // ternary bitmanip instruction
// MULT & DIV
output logic mult_en_o, // perform integer multiplication
@ -110,6 +112,8 @@ module ibex_decoder #(
logic [31:0] instr;
logic [31:0] instr_alu;
logic use_rs3;
csr_op_e csr_op;
opcode_e opcode;
@ -136,7 +140,7 @@ module ibex_decoder #(
assign zimm_rs1_type_o = { 27'b0, instr[`REG_S1] }; // rs1
// source registers
assign rf_raddr_a_o = instr[`REG_S1]; // rs1
assign rf_raddr_a_o = use_rs3 ? instr[`REG_S3] : instr[`REG_S1]; // rs3 / rs1
assign rf_raddr_b_o = instr[`REG_S2]; // rs2
// destination register
@ -347,24 +351,28 @@ module ibex_decoder #(
end
3'b101: begin
unique case (instr[31:25])
7'b000_0000, // srli
7'b010_0000: illegal_insn = 1'b0; // srai
if (instr[26]) begin
illegal_insn = RV32B ? 1'b0 : 1'b1; // fsri
end else begin
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'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
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
default: illegal_insn = 1'b1;
endcase
end
default: illegal_insn = 1'b1;
endcase
end
end
default: illegal_insn = 1'b1;
@ -375,92 +383,95 @@ module ibex_decoder #(
rf_ren_a_o = 1'b1;
rf_ren_b_o = 1'b1;
rf_we = 1'b1;
if (instr[31]) begin
illegal_insn = 1'b1;
end else begin
unique case ({instr[30:25], instr[14:12]})
// RV32I ALU operations
{6'b00_0000, 3'b000},
{6'b10_0000, 3'b000},
{6'b00_0000, 3'b010},
{6'b00_0000, 3'b011},
{6'b00_0000, 3'b100},
{6'b00_0000, 3'b110},
{6'b00_0000, 3'b111},
{6'b00_0000, 3'b001},
{6'b00_0000, 3'b101},
{6'b10_0000, 3'b101}: illegal_insn = 1'b0;
if ({instr[26], instr[13:12]} == {1'b1, 2'b01}) begin
illegal_insn = RV32B ? 1'b0 : 1'b1; // cmix / cmov / fsl / fsr
end else begin
unique case ({instr[30:25], instr[14:12]})
// RV32I ALU operations
{6'b00_0000, 3'b000},
{6'b10_0000, 3'b000},
{6'b00_0000, 3'b010},
{6'b00_0000, 3'b011},
{6'b00_0000, 3'b100},
{6'b00_0000, 3'b110},
{6'b00_0000, 3'b111},
{6'b00_0000, 3'b001},
{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 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;
mult_en_o = RV32M ? 1'b1 : 1'b0;
multdiv_signed_mode_o = 2'b00;
illegal_insn = RV32M ? 1'b0 : 1'b1;
end
{6'b00_0001, 3'b001}: begin // mulh
multdiv_operator_o = MD_OP_MULH;
mult_en_o = RV32M ? 1'b1 : 1'b0;
multdiv_signed_mode_o = 2'b11;
illegal_insn = RV32M ? 1'b0 : 1'b1;
end
{6'b00_0001, 3'b010}: begin // mulhsu
multdiv_operator_o = MD_OP_MULH;
mult_en_o = RV32M ? 1'b1 : 1'b0;
multdiv_signed_mode_o = 2'b01;
illegal_insn = RV32M ? 1'b0 : 1'b1;
end
{6'b00_0001, 3'b011}: begin // mulhu
multdiv_operator_o = MD_OP_MULH;
mult_en_o = RV32M ? 1'b1 : 1'b0;
multdiv_signed_mode_o = 2'b00;
illegal_insn = RV32M ? 1'b0 : 1'b1;
end
{6'b00_0001, 3'b100}: begin // div
multdiv_operator_o = MD_OP_DIV;
div_en_o = RV32M ? 1'b1 : 1'b0;
multdiv_signed_mode_o = 2'b11;
illegal_insn = RV32M ? 1'b0 : 1'b1;
end
{6'b00_0001, 3'b101}: begin // divu
multdiv_operator_o = MD_OP_DIV;
div_en_o = RV32M ? 1'b1 : 1'b0;
multdiv_signed_mode_o = 2'b00;
illegal_insn = RV32M ? 1'b0 : 1'b1;
end
{6'b00_0001, 3'b110}: begin // rem
multdiv_operator_o = MD_OP_REM;
div_en_o = RV32M ? 1'b1 : 1'b0;
multdiv_signed_mode_o = 2'b11;
illegal_insn = RV32M ? 1'b0 : 1'b1;
end
{6'b00_0001, 3'b111}: begin // remu
multdiv_operator_o = MD_OP_REM;
div_en_o = RV32M ? 1'b1 : 1'b0;
multdiv_signed_mode_o = 2'b00;
illegal_insn = RV32M ? 1'b0 : 1'b1;
end
default: begin
illegal_insn = 1'b1;
end
endcase
// supported RV32M instructions
{6'b00_0001, 3'b000}: begin // mul
multdiv_operator_o = MD_OP_MULL;
mult_en_o = RV32M ? 1'b1 : 1'b0;
multdiv_signed_mode_o = 2'b00;
illegal_insn = RV32M ? 1'b0 : 1'b1;
end
{6'b00_0001, 3'b001}: begin // mulh
multdiv_operator_o = MD_OP_MULH;
mult_en_o = RV32M ? 1'b1 : 1'b0;
multdiv_signed_mode_o = 2'b11;
illegal_insn = RV32M ? 1'b0 : 1'b1;
end
{6'b00_0001, 3'b010}: begin // mulhsu
multdiv_operator_o = MD_OP_MULH;
mult_en_o = RV32M ? 1'b1 : 1'b0;
multdiv_signed_mode_o = 2'b01;
illegal_insn = RV32M ? 1'b0 : 1'b1;
end
{6'b00_0001, 3'b011}: begin // mulhu
multdiv_operator_o = MD_OP_MULH;
mult_en_o = RV32M ? 1'b1 : 1'b0;
multdiv_signed_mode_o = 2'b00;
illegal_insn = RV32M ? 1'b0 : 1'b1;
end
{6'b00_0001, 3'b100}: begin // div
multdiv_operator_o = MD_OP_DIV;
div_en_o = RV32M ? 1'b1 : 1'b0;
multdiv_signed_mode_o = 2'b11;
illegal_insn = RV32M ? 1'b0 : 1'b1;
end
{6'b00_0001, 3'b101}: begin // divu
multdiv_operator_o = MD_OP_DIV;
div_en_o = RV32M ? 1'b1 : 1'b0;
multdiv_signed_mode_o = 2'b00;
illegal_insn = RV32M ? 1'b0 : 1'b1;
end
{6'b00_0001, 3'b110}: begin // rem
multdiv_operator_o = MD_OP_REM;
div_en_o = RV32M ? 1'b1 : 1'b0;
multdiv_signed_mode_o = 2'b11;
illegal_insn = RV32M ? 1'b0 : 1'b1;
end
{6'b00_0001, 3'b111}: begin // remu
multdiv_operator_o = MD_OP_REM;
div_en_o = RV32M ? 1'b1 : 1'b0;
multdiv_signed_mode_o = 2'b00;
illegal_insn = RV32M ? 1'b0 : 1'b1;
end
default: begin
illegal_insn = 1'b1;
end
endcase
end
end
end
@ -593,6 +604,9 @@ module ibex_decoder #(
opcode_alu = opcode_e'(instr_alu[6:0]);
use_rs3 = 1'b0;
alu_multicycle_o = 1'b0;
unique case (opcode_alu)
///////////
@ -760,6 +774,15 @@ module ibex_decoder #(
3'b101: begin
if (RV32B) begin
if (instr_alu[26] == 1'b1) begin
alu_operator_o = ALU_FSR;
alu_multicycle_o = 1'b1;
if (instr_first_cycle_i) begin
use_rs3 = 1'b0;
end else begin
use_rs3 = 1'b1;
end
end
// 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).
@ -767,7 +790,10 @@ module ibex_decoder #(
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_0000: begin
alu_operator_o = ALU_ROR; // Rotate Right by Immediate
alu_multicycle_o = 1'b1;
end
6'b11_0100: begin
if (instr_alu[24:20] == 5'b11111) begin
alu_operator_o = ALU_REV; // Reverse
@ -800,6 +826,49 @@ module ibex_decoder #(
alu_op_a_mux_sel_o = OP_A_REG_A;
alu_op_b_mux_sel_o = OP_B_REG_B;
if (instr_alu[26]) begin
if (RV32B) begin
unique case ({instr_alu[26:25], instr_alu[14:12]})
{2'b11, 3'b001}: begin
alu_operator_o = ALU_CMIX; // cmix
alu_multicycle_o = 1'b1;
if (instr_first_cycle_i) begin
use_rs3 = 1'b0;
end else begin
use_rs3 = 1'b1;
end
end
{2'b11, 3'b101}: begin
alu_operator_o = ALU_CMOV; // cmov
alu_multicycle_o = 1'b1;
if (instr_first_cycle_i) begin
use_rs3 = 1'b0;
end else begin
use_rs3 = 1'b1;
end
end
{2'b10, 3'b001}: begin
alu_operator_o = ALU_FSL; // fsl
alu_multicycle_o = 1'b1;
if (instr_first_cycle_i) begin
use_rs3 = 1'b0;
end else begin
use_rs3 = 1'b1;
end
end
{2'b10, 3'b101}: begin
alu_operator_o = ALU_FSR; // fsr
alu_multicycle_o = 1'b1;
if (instr_first_cycle_i) begin
use_rs3 = 1'b0;
end else begin
use_rs3 = 1'b1;
end
end
default: ;
endcase
end
end
unique case ({instr_alu[30:25], instr_alu[14:12]})
// RV32I ALU operations
{6'b00_0000, 3'b000}: alu_operator_o = ALU_ADD; // Add
@ -816,8 +885,18 @@ module ibex_decoder #(
// 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'b11_0000, 3'b001}: begin
if (RV32B) begin
alu_operator_o = ALU_ROL; // Rotate Left
alu_multicycle_o = 1'b1;
end
end
{6'b11_0000, 3'b101}: begin
if (RV32B) begin
alu_operator_o = ALU_ROR; // Rotate Right
alu_multicycle_o = 1'b1;
end
end
{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

View file

@ -21,6 +21,7 @@ module ibex_ex_block #(
input ibex_pkg::alu_op_e alu_operator_i,
input logic [31:0] alu_operand_a_i,
input logic [31:0] alu_operand_b_i,
input logic alu_instr_first_cycle_i,
// Branch Target ALU
// All of these signals are unusued when BranchTargetALU == 0
@ -37,6 +38,11 @@ module ibex_ex_block #(
input logic [31:0] multdiv_operand_b_i,
input logic multdiv_ready_id_i,
// intermediate val reg
output logic imd_val_we_o,
output logic [33:0] imd_val_d_o,
input logic [33:0] imd_val_q_i,
// Outputs
output logic [31:0] alu_adder_result_ex_o, // to LSU
output logic [31:0] result_ex_o,
@ -55,6 +61,14 @@ module ibex_ex_block #(
logic alu_cmp_result, alu_is_equal_result;
logic multdiv_valid;
logic multdiv_en;
logic [31:0] alu_imd_val_d;
logic alu_imd_val_we;
logic [33:0] multdiv_imd_val_d;
logic multdiv_imd_val_we;
// Intermediate Value Register Mux
assign imd_val_d_o = multdiv_sel_i ? multdiv_imd_val_d : {2'b0, alu_imd_val_d};
assign imd_val_we_o = multdiv_sel_i ? multdiv_imd_val_we : alu_imd_val_we;
/*
The multdiv_i output is never selected if RV32M=0
@ -95,19 +109,23 @@ module ibex_ex_block #(
/////////
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 ),
.multdiv_operand_a_i ( multdiv_alu_operand_a ),
.multdiv_operand_b_i ( multdiv_alu_operand_b ),
.multdiv_sel_i ( multdiv_sel_i ),
.adder_result_o ( alu_adder_result_ex_o ),
.adder_result_ext_o ( alu_adder_result_ext ),
.result_o ( alu_result ),
.comparison_result_o ( alu_cmp_result ),
.is_equal_result_o ( alu_is_equal_result )
.RV32B(RV32B)
) alu_i (
.operator_i ( alu_operator_i ),
.operand_a_i ( alu_operand_a_i ),
.operand_b_i ( alu_operand_b_i ),
.instr_first_cycle_i ( alu_instr_first_cycle_i ),
.imd_val_q_i ( imd_val_q_i[31:0] ),
.imd_val_we_o ( alu_imd_val_we ),
.imd_val_d_o ( alu_imd_val_d ),
.multdiv_operand_a_i ( multdiv_alu_operand_a ),
.multdiv_operand_b_i ( multdiv_alu_operand_b ),
.multdiv_sel_i ( multdiv_sel_i ),
.adder_result_o ( alu_adder_result_ex_o ),
.adder_result_ext_o ( alu_adder_result_ext ),
.result_o ( alu_result ),
.comparison_result_o ( alu_cmp_result ),
.is_equal_result_o ( alu_is_equal_result )
);
////////////////
@ -134,50 +152,56 @@ module ibex_ex_block #(
.multdiv_result_o ( multdiv_result )
);
end else if (MultiplierImplementation == "fast") begin : gen_multdiv_fast
ibex_multdiv_fast #(
.SingleCycleMultiply(0)
) multdiv_i (
.clk_i ( clk_i ),
.rst_ni ( rst_ni ),
.mult_en_i ( mult_en_i ),
.div_en_i ( div_en_i ),
.operator_i ( multdiv_operator_i ),
.signed_mode_i ( multdiv_signed_mode_i ),
.op_a_i ( multdiv_operand_a_i ),
.op_b_i ( multdiv_operand_b_i ),
.alu_operand_a_o ( multdiv_alu_operand_a ),
.alu_operand_b_o ( multdiv_alu_operand_b ),
.alu_adder_ext_i ( alu_adder_result_ext ),
.alu_adder_i ( alu_adder_result_ex_o ),
.equal_to_zero ( alu_is_equal_result ),
.multdiv_ready_id_i ( multdiv_ready_id_i ),
.valid_o ( multdiv_valid ),
.multdiv_result_o ( multdiv_result )
ibex_multdiv_fast # (
.SingleCycleMultiply (0)
) multdiv_i (
.clk_i ( clk_i ),
.rst_ni ( rst_ni ),
.mult_en_i ( mult_en_i ),
.div_en_i ( div_en_i ),
.operator_i ( multdiv_operator_i ),
.signed_mode_i ( multdiv_signed_mode_i ),
.op_a_i ( multdiv_operand_a_i ),
.op_b_i ( multdiv_operand_b_i ),
.alu_operand_a_o ( multdiv_alu_operand_a ),
.alu_operand_b_o ( multdiv_alu_operand_b ),
.alu_adder_ext_i ( alu_adder_result_ext ),
.alu_adder_i ( alu_adder_result_ex_o ),
.equal_to_zero ( alu_is_equal_result ),
.imd_val_q_i ( imd_val_q_i ),
.imd_val_d_o ( multdiv_imd_val_d ),
.imd_val_we_o ( multdiv_imd_val_we ),
.multdiv_ready_id_i ( multdiv_ready_id_i ),
.valid_o ( multdiv_valid ),
.multdiv_result_o ( multdiv_result )
);
end else if (MultiplierImplementation == "single-cycle") begin: gen_multdiv_single_cycle
ibex_multdiv_fast #(
.SingleCycleMultiply(1)
) multdiv_i (
.clk_i ( clk_i ),
.rst_ni ( rst_ni ),
.mult_en_i ( mult_en_i ),
.div_en_i ( div_en_i ),
.operator_i ( multdiv_operator_i ),
.signed_mode_i ( multdiv_signed_mode_i ),
.op_a_i ( multdiv_operand_a_i ),
.op_b_i ( multdiv_operand_b_i ),
.alu_operand_a_o ( multdiv_alu_operand_a ),
.alu_operand_b_o ( multdiv_alu_operand_b ),
.alu_adder_ext_i ( alu_adder_result_ext ),
.alu_adder_i ( alu_adder_result_ex_o ),
.equal_to_zero ( alu_is_equal_result ),
.multdiv_ready_id_i ( multdiv_ready_id_i ),
.valid_o ( multdiv_valid ),
.multdiv_result_o ( multdiv_result )
.clk_i ( clk_i ),
.rst_ni ( rst_ni ),
.mult_en_i ( mult_en_i ),
.div_en_i ( div_en_i ),
.operator_i ( multdiv_operator_i ),
.signed_mode_i ( multdiv_signed_mode_i ),
.op_a_i ( multdiv_operand_a_i ),
.op_b_i ( multdiv_operand_b_i ),
.alu_operand_a_o ( multdiv_alu_operand_a ),
.alu_operand_b_o ( multdiv_alu_operand_b ),
.alu_adder_ext_i ( alu_adder_result_ext ),
.alu_adder_i ( alu_adder_result_ex_o ),
.equal_to_zero ( alu_is_equal_result ),
.imd_val_q_i ( imd_val_q_i ),
.imd_val_d_o ( multdiv_imd_val_d ),
.imd_val_we_o ( multdiv_imd_val_we ),
.multdiv_ready_id_i ( multdiv_ready_id_i ),
.valid_o ( multdiv_valid ),
.multdiv_result_o ( multdiv_result )
);
end
// ALU output valid in same cycle, multiplier/divider may require multiple cycles
assign ex_valid_o = multdiv_en ? multdiv_valid : 1'b1;
assign ex_valid_o = multdiv_en ? multdiv_valid : !alu_imd_val_we;
endmodule

View file

@ -68,6 +68,11 @@ module ibex_id_stage #(
output logic [31:0] alu_operand_a_ex_o,
output logic [31:0] alu_operand_b_ex_o,
// Multicycle Operation Stage Register
input logic imd_val_we_ex_i,
input logic [33:0] imd_val_d_ex_i,
output logic [33:0] imd_val_q_ex_o,
// Branch target ALU
output logic [31:0] bt_a_operand_o,
output logic [31:0] bt_b_operand_o,
@ -227,6 +232,10 @@ module ibex_id_stage #(
alu_op_e alu_operator;
op_a_sel_e alu_op_a_mux_sel, alu_op_a_mux_sel_dec;
op_b_sel_e alu_op_b_mux_sel, alu_op_b_mux_sel_dec;
logic alu_multicycle_dec;
logic stall_alu;
logic [33:0] imd_val_q;
op_a_sel_e bt_a_mux_sel;
imm_b_sel_e bt_b_mux_sel;
@ -341,6 +350,20 @@ module ibex_id_stage #(
// ALU MUX for Operand B
assign alu_operand_b = (alu_op_b_mux_sel == OP_B_IMM) ? imm_b : rf_rdata_b_fwd;
/////////////////////////////////////////
// Multicycle Operation Stage Register //
/////////////////////////////////////////
always_ff @(posedge clk_i or negedge rst_ni) begin : intermediate_val_reg
if (!rst_ni) begin
imd_val_q <= '0;
end else if (imd_val_we_ex_i) begin
imd_val_q <= imd_val_d_ex_i;
end
end
assign imd_val_q_ex_o = imd_val_q;
///////////////////////
// Register File MUX //
///////////////////////
@ -414,6 +437,7 @@ module ibex_id_stage #(
.alu_operator_o ( alu_operator ),
.alu_op_a_mux_sel_o ( alu_op_a_mux_sel_dec ),
.alu_op_b_mux_sel_o ( alu_op_b_mux_sel_dec ),
.alu_multicycle_o ( alu_multicycle_dec ),
// MULT & DIV
.mult_en_o ( mult_en_dec ),
@ -427,10 +451,10 @@ module ibex_id_stage #(
.csr_op_o ( csr_op_o ),
// LSU
.data_req_o ( lsu_req_dec ),
.data_we_o ( lsu_we ),
.data_type_o ( lsu_type ),
.data_sign_extension_o ( lsu_sign_ext ),
.data_req_o ( lsu_req_dec ),
.data_we_o ( lsu_we ),
.data_type_o ( lsu_type ),
.data_sign_extension_o ( lsu_sign_ext ),
// jump/branches
.jump_in_dec_o ( jump_in_dec ),
@ -666,6 +690,7 @@ module ibex_id_stage #(
stall_multdiv = 1'b0;
stall_jump = 1'b0;
stall_branch = 1'b0;
stall_alu = 1'b0;
branch_set_d = 1'b0;
perf_branch_o = 1'b0;
@ -709,6 +734,11 @@ module ibex_id_stage #(
id_fsm_d = BranchTargetALU ? FIRST_CYCLE : MULTI_CYCLE;
stall_jump = ~BranchTargetALU;
end
alu_multicycle_dec: begin
stall_alu = 1'b1;
id_fsm_d = MULTI_CYCLE;
rf_we_raw = 1'b0;
end
default: begin
id_fsm_d = FIRST_CYCLE;
end
@ -742,7 +772,8 @@ module ibex_id_stage #(
`ASSERT(StallIDIfMulticycle, (id_fsm_q == FIRST_CYCLE) & (id_fsm_d == MULTI_CYCLE) |-> stall_id)
// Stall ID/EX stage for reason that relates to instruction in ID/EX
assign stall_id = stall_ld_hz | stall_mem | stall_multdiv | stall_jump | stall_branch;
assign stall_id = stall_ld_hz | stall_mem | stall_multdiv | stall_jump | stall_branch |
stall_alu;
assign instr_done = ~stall_id & ~flush_id & instr_executing;
@ -756,6 +787,7 @@ module ibex_id_stage #(
// first cycle if it is stalled.
assign instr_first_cycle = instr_valid_i & (id_fsm_q == FIRST_CYCLE);
// Used by RVFI to know when to capture register read data
// Used by ALU to access RS3 if ternary instruction.
assign instr_first_cycle_id_o = instr_first_cycle;
if (WritebackStage) begin : gen_stall_mem

View file

@ -32,6 +32,10 @@ module ibex_multdiv_fast #(
output logic [32:0] alu_operand_a_o,
output logic [32:0] alu_operand_b_o,
input logic [33:0] imd_val_q_i,
output logic [33:0] imd_val_d_o,
output logic imd_val_we_o,
input logic multdiv_ready_id_i,
output logic [31:0] multdiv_result_o,
@ -48,8 +52,6 @@ module ibex_multdiv_fast #(
logic mult_valid;
logic signed_mult;
// Flop used for intermediate value holding during div & mul calculation
logic [33:0] intermediate_val_q, intermediate_val_d;
// Results that become intermediate value depending on whether mul or div is being calculated
logic [33:0] mac_res_d, op_remainder_d;
// Raw output of MAC calculation
@ -103,13 +105,6 @@ module ibex_multdiv_fast #(
end
end
always_ff @(posedge clk_i or negedge rst_ni) begin
if (!rst_ni) begin
intermediate_val_q <= '0;
end else if (multdiv_en) begin
intermediate_val_q <= intermediate_val_d;
end
end
`ASSERT_KNOWN(DivEnKnown, div_en_internal);
`ASSERT_KNOWN(MultEnKnown, mult_en_internal);
@ -117,10 +112,11 @@ module ibex_multdiv_fast #(
assign multdiv_en = mult_en_internal | div_en_internal;
assign intermediate_val_d = div_en_i ? op_remainder_d : mac_res_d;
assign imd_val_d_o = div_en_i ? op_remainder_d : mac_res_d;
assign imd_val_we_o = multdiv_en;
assign signed_mult = (signed_mode_i != 2'b00);
assign multdiv_result_o = div_en_i ? intermediate_val_q[31:0] : mac_res_d[31:0];
assign multdiv_result_o = div_en_i ? imd_val_q_i[31:0] : mac_res_d[31:0];
// The single cycle multiplier uses three 17 bit multipliers to compute MUL instructions in a
// single cycle and MULH instructions in two cycles.
@ -166,8 +162,8 @@ module ibex_multdiv_fast #(
assign mult2_op_b = op_b_i[`OP_H];
// used in MULH
assign accum[17:0] = intermediate_val_q[33:16];
assign accum[33:18] = {16{signed_mult & intermediate_val_q[33]}};
assign accum[17:0] = imd_val_q_i[33:16];
assign accum[33:18] = {16{signed_mult & imd_val_q_i[33]}};
always_comb begin
// Default values == MULL
@ -264,7 +260,7 @@ module ibex_multdiv_fast #(
mult_op_b = op_b_i[`OP_L];
sign_a = 1'b0;
sign_b = 1'b0;
accum = intermediate_val_q;
accum = imd_val_q_i;
mac_res_d = mac_res;
mult_state_d = mult_state_q;
mult_valid = 1'b0;
@ -289,10 +285,10 @@ module ibex_multdiv_fast #(
mult_op_b = op_b_i[`OP_H];
sign_a = 1'b0;
sign_b = signed_mode_i[1] & op_b_i[31];
// result of AL*BL (in intermediate_val_q) always unsigned with no carry, so carries_q always 00
accum = {18'b0, intermediate_val_q[31:16]};
// result of AL*BL (in imd_val_q_i) always unsigned with no carry, so carries_q always 00
accum = {18'b0, imd_val_q_i[31:16]};
if (operator_i == MD_OP_MULL) begin
mac_res_d = {2'b0, mac_res[`OP_L], intermediate_val_q[`OP_L]};
mac_res_d = {2'b0, mac_res[`OP_L], imd_val_q_i[`OP_L]};
end else begin
// MD_OP_MULH
mac_res_d = mac_res;
@ -307,15 +303,15 @@ module ibex_multdiv_fast #(
sign_a = signed_mode_i[0] & op_a_i[31];
sign_b = 1'b0;
if (operator_i == MD_OP_MULL) begin
accum = {18'b0, intermediate_val_q[31:16]};
mac_res_d = {2'b0, mac_res[15:0], intermediate_val_q[15:0]};
accum = {18'b0, imd_val_q_i[31:16]};
mac_res_d = {2'b0, mac_res[15:0], imd_val_q_i[15:0]};
mult_valid = 1'b1;
// Note no state transition will occur if mult_hold is set
mult_state_d = ALBL;
mult_hold = ~multdiv_ready_id_i;
end else begin
accum = intermediate_val_q;
accum = imd_val_q_i;
mac_res_d = mac_res;
mult_state_d = AHBH;
end
@ -328,8 +324,8 @@ module ibex_multdiv_fast #(
mult_op_b = op_b_i[`OP_H];
sign_a = signed_mode_i[0] & op_a_i[31];
sign_b = signed_mode_i[1] & op_b_i[31];
accum[17: 0] = intermediate_val_q[33:16];
accum[33:18] = {16{signed_mult & intermediate_val_q[33]}};
accum[17: 0] = imd_val_q_i[33:16];
accum[33:18] = {16{signed_mult & imd_val_q_i[33]}};
// result of AH*BL is not signed only if signed_mode_i == 2'b00
mac_res_d = mac_res;
mult_valid = 1'b1;
@ -362,7 +358,7 @@ module ibex_multdiv_fast #(
// Divider
assign res_adder_h = alu_adder_ext_i[33:1];
assign next_remainder = is_greater_equal ? res_adder_h[31:0] : intermediate_val_q[31:0];
assign next_remainder = is_greater_equal ? res_adder_h[31:0] : imd_val_q_i[31:0];
assign next_quotient = is_greater_equal ? {1'b0, op_quotient_q} | {1'b0, one_shift} :
{1'b0, op_quotient_q};
@ -372,10 +368,10 @@ module ibex_multdiv_fast #(
// Remainder - Divisor. If Remainder - Divisor >= 0, is_greater_equal is equal to 1,
// the next Remainder is Remainder - Divisor contained in res_adder_h and the
always_comb begin
if ((intermediate_val_q[31] ^ op_denominator_q[31]) == 1'b0) begin
if ((imd_val_q_i[31] ^ op_denominator_q[31]) == 1'b0) begin
is_greater_equal = (res_adder_h[31] == 1'b0);
end else begin
is_greater_equal = intermediate_val_q[31];
is_greater_equal = imd_val_q_i[31];
end
end
@ -387,7 +383,7 @@ module ibex_multdiv_fast #(
always_comb begin
div_counter_d = div_counter_q - 5'h1;
op_remainder_d = intermediate_val_q;
op_remainder_d = imd_val_q_i;
op_quotient_d = op_quotient_q;
md_state_d = md_state_q;
op_numerator_d = op_numerator_q;
@ -445,13 +441,13 @@ module ibex_multdiv_fast #(
op_quotient_d = next_quotient[31:0];
md_state_d = (div_counter_q == 5'd1) ? MD_LAST : MD_COMP;
// Division
alu_operand_a_o = {intermediate_val_q[31:0], 1'b1}; // it contains the remainder
alu_operand_a_o = {imd_val_q_i[31:0], 1'b1}; // it contains the remainder
alu_operand_b_o = {~op_denominator_q[31:0], 1'b1}; // -denominator two's compliment
end
MD_LAST: begin
if (operator_i == MD_OP_DIV) begin
// this time we save the quotient in op_remainder_d (i.e. intermediate_val_q) since
// this time we save the quotient in op_remainder_d (i.e. imd_val_q_i) since
// we do not need anymore the remainder
op_remainder_d = {1'b0, next_quotient};
end else begin
@ -459,7 +455,7 @@ module ibex_multdiv_fast #(
op_remainder_d = {2'b0, next_remainder[31:0]};
end
// Division
alu_operand_a_o = {intermediate_val_q[31:0], 1'b1}; // it contains the remainder
alu_operand_a_o = {imd_val_q_i[31:0], 1'b1}; // it contains the remainder
alu_operand_b_o = {~op_denominator_q[31:0], 1'b1}; // -denominator two's compliment
md_state_d = MD_CHANGE_SIGN;
@ -468,13 +464,13 @@ module ibex_multdiv_fast #(
MD_CHANGE_SIGN: begin
md_state_d = MD_FINISH;
if (operator_i == MD_OP_DIV) begin
op_remainder_d = (div_change_sign) ? {2'h0, alu_adder_i} : intermediate_val_q;
op_remainder_d = (div_change_sign) ? {2'h0, alu_adder_i} : imd_val_q_i;
end else begin
op_remainder_d = (rem_change_sign) ? {2'h0, alu_adder_i} : intermediate_val_q;
op_remainder_d = (rem_change_sign) ? {2'h0, alu_adder_i} : imd_val_q_i;
end
// ABS(Quotient) = 0 - Quotient (or Remainder)
alu_operand_a_o = {32'h0 , 1'b1};
alu_operand_b_o = {~intermediate_val_q[31:0], 1'b1};
alu_operand_b_o = {~imd_val_q_i[31:0], 1'b1};
end
MD_FINISH: begin

View file

@ -86,7 +86,14 @@ typedef enum logic [5:0] {
// Set lower than
ALU_SLT,
ALU_SLTU
ALU_SLTU,
// Ternary Bitmanip Operations
// RV32B
ALU_CMOV,
ALU_CMIX,
ALU_FSL,
ALU_FSR
} alu_op_e;
typedef enum logic [1:0] {

View file

@ -48,8 +48,10 @@ module ibex_tracer (
input logic [ 1:0] rvfi_mode,
input logic [ 4:0] rvfi_rs1_addr,
input logic [ 4:0] rvfi_rs2_addr,
input logic [ 4:0] rvfi_rs3_addr,
input logic [31:0] rvfi_rs1_rdata,
input logic [31:0] rvfi_rs2_rdata,
input logic [31:0] rvfi_rs3_rdata,
input logic [ 4:0] rvfi_rd_addr,
input logic [31:0] rvfi_rd_wdata,
input logic [31:0] rvfi_pc_rdata,
@ -83,9 +85,10 @@ module ibex_tracer (
// Data items accessed during this instruction
localparam RS1 = (1 << 0);
localparam RS2 = (1 << 1);
localparam RD = (1 << 2);
localparam MEM = (1 << 3);
logic [3:0] data_accessed;
localparam RS3 = (1 << 2);
localparam RD = (1 << 3);
localparam MEM = (1 << 4);
logic [4:0] data_accessed;
function automatic void printbuffer_dumpline();
string rvfi_insn_str;
@ -116,6 +119,9 @@ module ibex_tracer (
if ((data_accessed & RS2) != 0) begin
$fwrite(file_handle, " %s:0x%08x", reg_addr_to_str(rvfi_rs2_addr), rvfi_rs2_rdata);
end
if ((data_accessed & RS3) != 0) begin
$fwrite(file_handle, " %s:0x%08x", reg_addr_to_str(rvfi_rs3_addr), rvfi_rs3_rdata);
end
if ((data_accessed & RD) != 0) begin
$fwrite(file_handle, " %s=0x%08x", reg_addr_to_str(rvfi_rd_addr), rvfi_rd_wdata);
end
@ -396,7 +402,8 @@ module ibex_tracer (
function automatic void decode_r_insn(input string mnemonic);
data_accessed = RS1 | RS2 | RD;
decoded_str = $sformatf("%s\tx%0d,x%0d,x%0d", mnemonic, rvfi_rd_addr, rvfi_rs1_addr, rvfi_rs2_addr);
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);
@ -404,6 +411,18 @@ module ibex_tracer (
decoded_str = $sformatf("%s\tx%0d,x%0d", mnemonic, rvfi_rd_addr, rvfi_rs1_addr);
endfunction
function automatic void decode_r_cmixcmov_insn(input string mnemonic);
data_accessed = RS1 | RS2 | RS3 | RD;
decoded_str = $sformatf("%s\tx%0d,x%0d,x%0d,x%0d", mnemonic, rvfi_rd_addr, rvfi_rs2_addr,
rvfi_rs1_addr, rvfi_rs3_addr);
endfunction
function automatic void decode_r_funnelshift_insn(input string mnemonic);
data_accessed = RS1 | RS2 | RS3 | RD;
decoded_str = $sformatf("%s\tx%0d,x%0d,x%0d,x%0d", mnemonic, rvfi_rd_addr, rvfi_rs1_addr,
rvfi_rs3_addr, rvfi_rs2_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,
@ -418,6 +437,15 @@ module ibex_tracer (
decoded_str = $sformatf("%s\tx%0d,x%0d,0x%0x", mnemonic, rvfi_rd_addr, rvfi_rs1_addr, shamt);
endfunction
function automatic void decode_i_funnelshift_insn( input string mnemonic);
// fsri
logic [5:0] shamt;
shamt = {rvfi_insn[25:20]};
data_accessed = RS1 | RS3;
decoded_str = $sformatf("%s\tx%0d,x%0d,x%0d,0x%0x", mnemonic, rvfi_rd_addr, rvfi_rs1_addr,
rvfi_rs3_addr, shamt);
endfunction
function automatic void decode_i_jalr_insn(input string mnemonic);
// JALR
data_accessed = RS1 | RD;
@ -709,7 +737,7 @@ module ibex_tracer (
always_comb begin
decoded_str = "";
data_accessed = 4'h0;
data_accessed = 5'h0;
insn_is_compressed = 0;
// Check for compressed instructions
@ -871,6 +899,12 @@ module ibex_tracer (
INSN_PCNT: decode_r1_insn("pcnt");
INSN_REV: decode_r1_insn("rev");
INSN_REV8: decode_r1_insn("rev8");
// TERNARY BITMABIP INSTR
INSN_CMIX: decode_r_cmixcmov_insn("cmix");
INSN_CMOV: decode_r_cmixcmov_insn("cmov");
INSN_FSR: decode_r_funnelshift_insn("fsr");
INSN_FSL: decode_r_funnelshift_insn("fsl");
INSN_FSRI: decode_i_funnelshift_insn("fsri");
default: decode_mnemonic("INVALID");
endcase

View file

@ -72,8 +72,8 @@ parameter logic [31:0] INSN_PMULHSU = { 7'b0000001, 10'b?, 3'b010, 5'b?, {OPCODE
parameter logic [31:0] INSN_PMULHU = { 7'b0000001, 10'b?, 3'b011, 5'b?, {OPCODE_OP} };
// RV32B
// ZBB
// OPIMM
// ZBB
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} };
@ -83,22 +83,30 @@ parameter logic [31:0] INSN_PCNT = { 12'b011000000010, 5'b? , 3'b001, 5'b?, {OPC
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} };
// ZBT
parameter logic [31:0] INSN_FSRI = { 5'b?, 1'b1, 11'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} };
// ZBB
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} };
// ZBT
parameter logic [31:0] INSN_CMIX = {5'b?, 2'b11, 10'b?, 3'b001, 5'b?, {OPCODE_OP} };
parameter logic [31:0] INSN_CMOV = {5'b?, 2'b11, 10'b?, 3'b101, 5'b?, {OPCODE_OP} };
parameter logic [31:0] INSN_FSL = {5'b?, 2'b10, 10'b?, 3'b001, 5'b?, {OPCODE_OP} };
parameter logic [31:0] INSN_FSR = {5'b?, 2'b10, 10'b?, 3'b101, 5'b?, {OPCODE_OP} };
// LOAD & STORE
parameter logic [31:0] INSN_LOAD = {25'b?, {OPCODE_LOAD } };