[rtl] Replicate instruction flops to reduce fanout

Adds a second set of instruction flops that are used to determine ALU
operation and operand selection. This reduces fanout from the
instruction flops and so helps timing.
This commit is contained in:
Greg Chadwick 2020-01-10 16:52:32 +00:00
parent 639964514c
commit 486bf45711
5 changed files with 307 additions and 141 deletions

View file

@ -21,7 +21,7 @@ lint_off -msg DECLFILENAME -file "*/rtl/ibex_register_file_fpga.sv"
// Bits of signal are not used: fetch_addr_n[0] // Bits of signal are not used: fetch_addr_n[0]
// cleaner to write all bits even if not all are used // cleaner to write all bits even if not all are used
lint_off -msg UNUSED -file "*/rtl/ibex_if_stage.sv" -lines 83 lint_off -msg UNUSED -file "*/rtl/ibex_if_stage.sv" -lines 85
// Bits of signal are not used: shift_right_result_ext[32] // Bits of signal are not used: shift_right_result_ext[32]
// cleaner to write all bits even if not all are used // cleaner to write all bits even if not all are used

View file

@ -101,6 +101,8 @@ module ibex_core #(
logic instr_valid_id; logic instr_valid_id;
logic instr_new_id; logic instr_new_id;
logic [31:0] instr_rdata_id; // 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 [15:0] instr_rdata_c_id; // Compressed instruction sampled inside IF stage
logic instr_is_compressed_id; logic instr_is_compressed_id;
logic instr_fetch_err; // Bus error on instr fetch logic instr_fetch_err; // Bus error on instr fetch
@ -322,6 +324,7 @@ module ibex_core #(
.instr_valid_id_o ( instr_valid_id ), .instr_valid_id_o ( instr_valid_id ),
.instr_new_id_o ( instr_new_id ), .instr_new_id_o ( instr_new_id ),
.instr_rdata_id_o ( instr_rdata_id ), .instr_rdata_id_o ( instr_rdata_id ),
.instr_rdata_alu_id_o ( instr_rdata_alu_id ),
.instr_rdata_c_id_o ( instr_rdata_c_id ), .instr_rdata_c_id_o ( instr_rdata_c_id ),
.instr_is_compressed_id_o ( instr_is_compressed_id ), .instr_is_compressed_id_o ( instr_is_compressed_id ),
.instr_fetch_err_o ( instr_fetch_err ), .instr_fetch_err_o ( instr_fetch_err ),
@ -378,6 +381,7 @@ module ibex_core #(
.instr_valid_i ( instr_valid_id ), .instr_valid_i ( instr_valid_id ),
.instr_new_i ( instr_new_id ), .instr_new_i ( instr_new_id ),
.instr_rdata_i ( instr_rdata_id ), .instr_rdata_i ( instr_rdata_id ),
.instr_rdata_alu_i ( instr_rdata_alu_id ),
.instr_rdata_c_i ( instr_rdata_c_id ), .instr_rdata_c_i ( instr_rdata_c_id ),
.instr_is_compressed_i ( instr_is_compressed_id ), .instr_is_compressed_i ( instr_is_compressed_id ),

View file

@ -38,6 +38,9 @@ module ibex_decoder #(
// from IF-ID pipeline register // from IF-ID pipeline register
input logic instr_new_i, // instruction read is new input logic instr_new_i, // instruction read is new
input logic [31:0] instr_rdata_i, // instruction read from memory/cache input logic [31:0] instr_rdata_i, // instruction read from memory/cache
input logic [31:0] instr_rdata_alu_i, // instruction read from memory/cache
// replicated to ease fan-out)
input logic illegal_c_insn_i, // compressed instruction decode failed input logic illegal_c_insn_i, // compressed instruction decode failed
// immediates // immediates
@ -98,12 +101,18 @@ module ibex_decoder #(
logic regfile_we; logic regfile_we;
logic [31:0] instr; logic [31:0] instr;
logic [31:0] instr_alu;
csr_op_e csr_op; csr_op_e csr_op;
opcode_e opcode; opcode_e opcode;
opcode_e opcode_alu;
assign instr = instr_rdata_i; // To help timing the flops containing the current instruction are replicated to reduce fan-out.
// instr_alu is used to determine the ALU control logic and associated operand/imm select signals
// as the ALU is often on the more critical timing paths. instr is used for everything else.
assign instr = instr_rdata_i;
assign instr_alu = instr_rdata_alu_i;
////////////////////////////////////// //////////////////////////////////////
// Register and immediate selection // // Register and immediate selection //
@ -185,12 +194,6 @@ module ibex_decoder #(
jump_in_dec_o = 1'b0; jump_in_dec_o = 1'b0;
jump_set_o = 1'b0; jump_set_o = 1'b0;
branch_in_dec_o = 1'b0; branch_in_dec_o = 1'b0;
alu_operator_o = ALU_SLTU;
alu_op_a_mux_sel_o = OP_A_IMM;
alu_op_b_mux_sel_o = OP_B_IMM;
imm_a_mux_sel_o = IMM_A_ZERO;
imm_b_mux_sel_o = IMM_B_I;
mult_en_o = 1'b0; mult_en_o = 1'b0;
div_en_o = 1'b0; div_en_o = 1'b0;
@ -216,8 +219,6 @@ module ibex_decoder #(
ecall_insn_o = 1'b0; ecall_insn_o = 1'b0;
wfi_insn_o = 1'b0; wfi_insn_o = 1'b0;
jt_mux_sel_o = JT_ALU;
opcode = opcode_e'(instr[6:0]); opcode = opcode_e'(instr[6:0]);
unique case (opcode) unique case (opcode)
@ -229,24 +230,12 @@ module ibex_decoder #(
OPCODE_JAL: begin // Jump and Link OPCODE_JAL: begin // Jump and Link
jump_in_dec_o = 1'b1; jump_in_dec_o = 1'b1;
if(BranchTargetALU) begin
jt_mux_sel_o = JT_ALU;
end
if (instr_new_i) begin if (instr_new_i) begin
// Calculate jump target // Calculate jump target
alu_op_a_mux_sel_o = OP_A_CURRPC;
alu_op_b_mux_sel_o = OP_B_IMM;
imm_b_mux_sel_o = IMM_B_J;
alu_operator_o = ALU_ADD;
regfile_we = 1'b0; regfile_we = 1'b0;
jump_set_o = 1'b1; jump_set_o = 1'b1;
end else begin end else begin
// Calculate and store PC+4 // Calculate and store PC+4
alu_op_a_mux_sel_o = OP_A_CURRPC;
alu_op_b_mux_sel_o = OP_B_IMM;
imm_b_mux_sel_o = IMM_B_INCR_PC;
alu_operator_o = ALU_ADD;
regfile_we = 1'b1; regfile_we = 1'b1;
end end
end end
@ -254,24 +243,12 @@ module ibex_decoder #(
OPCODE_JALR: begin // Jump and Link Register OPCODE_JALR: begin // Jump and Link Register
jump_in_dec_o = 1'b1; jump_in_dec_o = 1'b1;
if(BranchTargetALU) begin
jt_mux_sel_o = JT_ALU;
end
if (instr_new_i) begin if (instr_new_i) begin
// Calculate jump target // Calculate jump target
alu_op_a_mux_sel_o = OP_A_REG_A;
alu_op_b_mux_sel_o = OP_B_IMM;
imm_b_mux_sel_o = IMM_B_I;
alu_operator_o = ALU_ADD;
regfile_we = 1'b0; regfile_we = 1'b0;
jump_set_o = 1'b1; jump_set_o = 1'b1;
end else begin end else begin
// Calculate and store PC+4 // Calculate and store PC+4
alu_op_a_mux_sel_o = OP_A_CURRPC;
alu_op_b_mux_sel_o = OP_B_IMM;
imm_b_mux_sel_o = IMM_B_INCR_PC;
alu_operator_o = ALU_ADD;
regfile_we = 1'b1; regfile_we = 1'b1;
end end
if (instr[14:12] != 3'b0) begin if (instr[14:12] != 3'b0) begin
@ -283,37 +260,14 @@ module ibex_decoder #(
branch_in_dec_o = 1'b1; branch_in_dec_o = 1'b1;
// Check branch condition selection // Check branch condition selection
unique case (instr[14:12]) unique case (instr[14:12])
3'b000: alu_operator_o = ALU_EQ; 3'b000,
3'b001: alu_operator_o = ALU_NE; 3'b001,
3'b100: alu_operator_o = ALU_LT; 3'b100,
3'b101: alu_operator_o = ALU_GE; 3'b101,
3'b110: alu_operator_o = ALU_LTU; 3'b110,
3'b111: alu_operator_o = ALU_GEU; 3'b111: illegal_insn = 1'b0;
default: illegal_insn = 1'b1; default: illegal_insn = 1'b1;
endcase endcase
if (BranchTargetALU) begin
// With branch target ALU main ALU evaluates branch condition and branch target ALU
// calculates target (which is controlled in a seperate block below)
alu_op_a_mux_sel_o = OP_A_REG_A;
alu_op_b_mux_sel_o = OP_B_REG_B;
regfile_we = 1'b0;
jt_mux_sel_o = JT_BT_ALU;
end else begin
// Without branch target ALU branch is 2 stage operation using the Main ALU in both stages
if (instr_new_i) begin
// First evaluates branch condition
alu_op_a_mux_sel_o = OP_A_REG_A;
alu_op_b_mux_sel_o = OP_B_REG_B;
end else begin
// Then calculate jump target
alu_op_a_mux_sel_o = OP_A_CURRPC;
alu_op_b_mux_sel_o = OP_B_IMM;
imm_b_mux_sel_o = IMM_B_B;
alu_operator_o = ALU_ADD;
regfile_we = 1'b0;
end
end
end end
//////////////// ////////////////
@ -321,18 +275,10 @@ module ibex_decoder #(
//////////////// ////////////////
OPCODE_STORE: begin OPCODE_STORE: begin
alu_op_a_mux_sel_o = OP_A_REG_A;
alu_op_b_mux_sel_o = OP_B_REG_B;
data_req_o = 1'b1; data_req_o = 1'b1;
data_we_o = 1'b1; data_we_o = 1'b1;
alu_operator_o = ALU_ADD;
if (!instr[14]) begin if (instr[14]) begin
// offset from immediate
imm_b_mux_sel_o = IMM_B_S;
alu_op_b_mux_sel_o = OP_B_IMM;
end else begin
// Register offset is illegal since no register c available
illegal_insn = 1'b1; illegal_insn = 1'b1;
end end
@ -346,17 +292,11 @@ module ibex_decoder #(
end end
OPCODE_LOAD: begin OPCODE_LOAD: begin
alu_op_a_mux_sel_o = OP_A_REG_A;
data_req_o = 1'b1; data_req_o = 1'b1;
regfile_wdata_sel_o = RF_WD_LSU; regfile_wdata_sel_o = RF_WD_LSU;
regfile_we = 1'b1; regfile_we = 1'b1;
data_type_o = 2'b00; data_type_o = 2'b00;
// offset from immediate
alu_operator_o = ALU_ADD;
alu_op_b_mux_sel_o = OP_B_IMM;
imm_b_mux_sel_o = IMM_B_I;
// sign/zero extension // sign/zero extension
data_sign_extension_o = ~instr[14]; data_sign_extension_o = ~instr[14];
@ -381,38 +321,25 @@ module ibex_decoder #(
///////// /////////
OPCODE_LUI: begin // Load Upper Immediate OPCODE_LUI: begin // Load Upper Immediate
alu_op_a_mux_sel_o = OP_A_IMM;
alu_op_b_mux_sel_o = OP_B_IMM;
imm_a_mux_sel_o = IMM_A_ZERO;
imm_b_mux_sel_o = IMM_B_U;
alu_operator_o = ALU_ADD;
regfile_we = 1'b1; regfile_we = 1'b1;
end end
OPCODE_AUIPC: begin // Add Upper Immediate to PC OPCODE_AUIPC: begin // Add Upper Immediate to PC
alu_op_a_mux_sel_o = OP_A_CURRPC;
alu_op_b_mux_sel_o = OP_B_IMM;
imm_b_mux_sel_o = IMM_B_U;
alu_operator_o = ALU_ADD;
regfile_we = 1'b1; regfile_we = 1'b1;
end end
OPCODE_OP_IMM: begin // Register-Immediate ALU Operations OPCODE_OP_IMM: begin // Register-Immediate ALU Operations
alu_op_a_mux_sel_o = OP_A_REG_A;
alu_op_b_mux_sel_o = OP_B_IMM;
imm_b_mux_sel_o = IMM_B_I;
regfile_we = 1'b1; regfile_we = 1'b1;
unique case (instr[14:12]) unique case (instr[14:12])
3'b000: alu_operator_o = ALU_ADD; // Add Immediate 3'b000,
3'b010: alu_operator_o = ALU_SLT; // Set to one if Lower Than Immediate 3'b010,
3'b011: alu_operator_o = ALU_SLTU; // Set to one if Lower Than Immediate Unsigned 3'b011,
3'b100: alu_operator_o = ALU_XOR; // Exclusive Or with Immediate 3'b100,
3'b110: alu_operator_o = ALU_OR; // Or with Immediate 3'b110,
3'b111: alu_operator_o = ALU_AND; // And with Immediate 3'b111: illegal_insn = 1'b0;
3'b001: begin 3'b001: begin
alu_operator_o = ALU_SLL; // Shift Left Logical by Immediate
if (instr[31:25] != 7'b0) begin if (instr[31:25] != 7'b0) begin
illegal_insn = 1'b1; illegal_insn = 1'b1;
end end
@ -420,23 +347,21 @@ module ibex_decoder #(
3'b101: begin 3'b101: begin
if (instr[31:25] == 7'b0) begin if (instr[31:25] == 7'b0) begin
alu_operator_o = ALU_SRL; // Shift Right Logical by Immediate illegal_insn = 1'b0;
end else if (instr[31:25] == 7'b010_0000) begin end else if (instr[31:25] == 7'b010_0000) begin
alu_operator_o = ALU_SRA; // Shift Right Arithmetically by Immediate illegal_insn = 1'b0;
end else begin end else begin
illegal_insn = 1'b1; illegal_insn = 1'b1;
end end
end end
default: begin default: begin
alu_operator_o = ALU_SLTU; illegal_insn = 1'b1;
end end
endcase endcase
end end
OPCODE_OP: begin // Register-Register ALU operation OPCODE_OP: begin // Register-Register ALU operation
alu_op_a_mux_sel_o = OP_A_REG_A;
alu_op_b_mux_sel_o = OP_B_REG_B;
regfile_we = 1'b1; regfile_we = 1'b1;
if (instr[31]) begin if (instr[31]) begin
@ -444,69 +369,61 @@ module ibex_decoder #(
end else begin end else begin
unique case ({instr[30:25], instr[14:12]}) unique case ({instr[30:25], instr[14:12]})
// RV32I ALU operations // RV32I ALU operations
{6'b00_0000, 3'b000}: alu_operator_o = ALU_ADD; // Add {6'b00_0000, 3'b000},
{6'b10_0000, 3'b000}: alu_operator_o = ALU_SUB; // Sub {6'b10_0000, 3'b000},
{6'b00_0000, 3'b010}: alu_operator_o = ALU_SLT; // Set Lower Than {6'b00_0000, 3'b010},
{6'b00_0000, 3'b011}: alu_operator_o = ALU_SLTU; // Set Lower Than Unsigned {6'b00_0000, 3'b011},
{6'b00_0000, 3'b100}: alu_operator_o = ALU_XOR; // Xor {6'b00_0000, 3'b100},
{6'b00_0000, 3'b110}: alu_operator_o = ALU_OR; // Or {6'b00_0000, 3'b110},
{6'b00_0000, 3'b111}: alu_operator_o = ALU_AND; // And {6'b00_0000, 3'b111},
{6'b00_0000, 3'b001}: alu_operator_o = ALU_SLL; // Shift Left Logical {6'b00_0000, 3'b001},
{6'b00_0000, 3'b101}: alu_operator_o = ALU_SRL; // Shift Right Logical {6'b00_0000, 3'b101},
{6'b10_0000, 3'b101}: alu_operator_o = ALU_SRA; // Shift Right Arithmetic {6'b10_0000, 3'b101}: illegal_insn = 1'b0;
// supported RV32M instructions // supported RV32M instructions
{6'b00_0001, 3'b000}: begin // mul {6'b00_0001, 3'b000}: begin // mul
alu_operator_o = ALU_ADD;
multdiv_operator_o = MD_OP_MULL; multdiv_operator_o = MD_OP_MULL;
mult_en_o = RV32M ? 1'b1 : 1'b0; mult_en_o = RV32M ? 1'b1 : 1'b0;
multdiv_signed_mode_o = 2'b00; multdiv_signed_mode_o = 2'b00;
illegal_insn = RV32M ? 1'b0 : 1'b1; illegal_insn = RV32M ? 1'b0 : 1'b1;
end end
{6'b00_0001, 3'b001}: begin // mulh {6'b00_0001, 3'b001}: begin // mulh
alu_operator_o = ALU_ADD;
multdiv_operator_o = MD_OP_MULH; multdiv_operator_o = MD_OP_MULH;
mult_en_o = RV32M ? 1'b1 : 1'b0; mult_en_o = RV32M ? 1'b1 : 1'b0;
multdiv_signed_mode_o = 2'b11; multdiv_signed_mode_o = 2'b11;
illegal_insn = RV32M ? 1'b0 : 1'b1; illegal_insn = RV32M ? 1'b0 : 1'b1;
end end
{6'b00_0001, 3'b010}: begin // mulhsu {6'b00_0001, 3'b010}: begin // mulhsu
alu_operator_o = ALU_ADD;
multdiv_operator_o = MD_OP_MULH; multdiv_operator_o = MD_OP_MULH;
mult_en_o = RV32M ? 1'b1 : 1'b0; mult_en_o = RV32M ? 1'b1 : 1'b0;
multdiv_signed_mode_o = 2'b01; multdiv_signed_mode_o = 2'b01;
illegal_insn = RV32M ? 1'b0 : 1'b1; illegal_insn = RV32M ? 1'b0 : 1'b1;
end end
{6'b00_0001, 3'b011}: begin // mulhu {6'b00_0001, 3'b011}: begin // mulhu
alu_operator_o = ALU_ADD;
multdiv_operator_o = MD_OP_MULH; multdiv_operator_o = MD_OP_MULH;
mult_en_o = RV32M ? 1'b1 : 1'b0; mult_en_o = RV32M ? 1'b1 : 1'b0;
multdiv_signed_mode_o = 2'b00; multdiv_signed_mode_o = 2'b00;
illegal_insn = RV32M ? 1'b0 : 1'b1; illegal_insn = RV32M ? 1'b0 : 1'b1;
end end
{6'b00_0001, 3'b100}: begin // div {6'b00_0001, 3'b100}: begin // div
alu_operator_o = ALU_ADD;
multdiv_operator_o = MD_OP_DIV; multdiv_operator_o = MD_OP_DIV;
div_en_o = RV32M ? 1'b1 : 1'b0; div_en_o = RV32M ? 1'b1 : 1'b0;
multdiv_signed_mode_o = 2'b11; multdiv_signed_mode_o = 2'b11;
illegal_insn = RV32M ? 1'b0 : 1'b1; illegal_insn = RV32M ? 1'b0 : 1'b1;
end end
{6'b00_0001, 3'b101}: begin // divu {6'b00_0001, 3'b101}: begin // divu
alu_operator_o = ALU_ADD;
multdiv_operator_o = MD_OP_DIV; multdiv_operator_o = MD_OP_DIV;
div_en_o = RV32M ? 1'b1 : 1'b0; div_en_o = RV32M ? 1'b1 : 1'b0;
multdiv_signed_mode_o = 2'b00; multdiv_signed_mode_o = 2'b00;
illegal_insn = RV32M ? 1'b0 : 1'b1; illegal_insn = RV32M ? 1'b0 : 1'b1;
end end
{6'b00_0001, 3'b110}: begin // rem {6'b00_0001, 3'b110}: begin // rem
alu_operator_o = ALU_ADD;
multdiv_operator_o = MD_OP_REM; multdiv_operator_o = MD_OP_REM;
div_en_o = RV32M ? 1'b1 : 1'b0; div_en_o = RV32M ? 1'b1 : 1'b0;
multdiv_signed_mode_o = 2'b11; multdiv_signed_mode_o = 2'b11;
illegal_insn = RV32M ? 1'b0 : 1'b1; illegal_insn = RV32M ? 1'b0 : 1'b1;
end end
{6'b00_0001, 3'b111}: begin // remu {6'b00_0001, 3'b111}: begin // remu
alu_operator_o = ALU_ADD;
multdiv_operator_o = MD_OP_REM; multdiv_operator_o = MD_OP_REM;
div_en_o = RV32M ? 1'b1 : 1'b0; div_en_o = RV32M ? 1'b1 : 1'b0;
multdiv_signed_mode_o = 2'b00; multdiv_signed_mode_o = 2'b00;
@ -529,9 +446,6 @@ module ibex_decoder #(
// FENCE.I will flush the IF stage and prefetch buffer but nothing else. // FENCE.I will flush the IF stage and prefetch buffer but nothing else.
unique case (instr[14:12]) unique case (instr[14:12])
3'b000: begin 3'b000: begin
alu_operator_o = ALU_ADD; // nop
alu_op_a_mux_sel_o = OP_A_REG_A;
alu_op_b_mux_sel_o = OP_B_IMM;
regfile_we = 1'b0; regfile_we = 1'b0;
end end
3'b001: begin 3'b001: begin
@ -540,10 +454,6 @@ module ibex_decoder #(
// requests will be ignored). // requests will be ignored).
jump_in_dec_o = 1'b1; jump_in_dec_o = 1'b1;
alu_op_a_mux_sel_o = OP_A_CURRPC;
alu_op_b_mux_sel_o = OP_B_IMM;
imm_b_mux_sel_o = IMM_B_INCR_PC;
alu_operator_o = ALU_ADD;
regfile_we = 1'b0; regfile_we = 1'b0;
if (instr_new_i) begin if (instr_new_i) begin
@ -559,8 +469,6 @@ module ibex_decoder #(
OPCODE_SYSTEM: begin OPCODE_SYSTEM: begin
if (instr[14:12] == 3'b000) begin if (instr[14:12] == 3'b000) begin
// non CSR related SYSTEM instructions // non CSR related SYSTEM instructions
alu_op_a_mux_sel_o = OP_A_REG_A;
alu_op_b_mux_sel_o = OP_B_IMM;
unique case (instr[31:20]) unique case (instr[31:20])
12'h000: // ECALL 12'h000: // ECALL
// environment (system) call // environment (system) call
@ -592,16 +500,6 @@ module ibex_decoder #(
csr_access_o = 1'b1; csr_access_o = 1'b1;
regfile_wdata_sel_o = RF_WD_CSR; regfile_wdata_sel_o = RF_WD_CSR;
regfile_we = 1'b1; regfile_we = 1'b1;
alu_op_b_mux_sel_o = OP_B_IMM;
imm_a_mux_sel_o = IMM_A_Z;
imm_b_mux_sel_o = IMM_B_I; // CSR address is encoded in I imm
if (instr[14]) begin
// rs1 field is used as immediate
alu_op_a_mux_sel_o = OP_A_IMM;
end else begin
alu_op_a_mux_sel_o = OP_A_REG_A;
end
unique case (instr[13:12]) unique case (instr[13:12])
2'b01: csr_op = CSR_OP_WRITE; 2'b01: csr_op = CSR_OP_WRITE;
@ -642,6 +540,256 @@ module ibex_decoder #(
end end
end end
/////////////////////////////
// Decoder for ALU control //
/////////////////////////////
always_comb begin
alu_operator_o = ALU_SLTU;
alu_op_a_mux_sel_o = OP_A_IMM;
alu_op_b_mux_sel_o = OP_B_IMM;
imm_a_mux_sel_o = IMM_A_ZERO;
imm_b_mux_sel_o = IMM_B_I;
jt_mux_sel_o = JT_ALU;
opcode_alu = opcode_e'(instr_alu[6:0]);
unique case (opcode_alu)
///////////
// Jumps //
///////////
OPCODE_JAL: begin // Jump and Link
if(BranchTargetALU) begin
jt_mux_sel_o = JT_ALU;
end
if (instr_new_i) begin
// Calculate jump target
alu_op_a_mux_sel_o = OP_A_CURRPC;
alu_op_b_mux_sel_o = OP_B_IMM;
imm_b_mux_sel_o = IMM_B_J;
alu_operator_o = ALU_ADD;
end else begin
// Calculate and store PC+4
alu_op_a_mux_sel_o = OP_A_CURRPC;
alu_op_b_mux_sel_o = OP_B_IMM;
imm_b_mux_sel_o = IMM_B_INCR_PC;
alu_operator_o = ALU_ADD;
end
end
OPCODE_JALR: begin // Jump and Link Register
if(BranchTargetALU) begin
jt_mux_sel_o = JT_ALU;
end
if (instr_new_i) begin
// Calculate jump target
alu_op_a_mux_sel_o = OP_A_REG_A;
alu_op_b_mux_sel_o = OP_B_IMM;
imm_b_mux_sel_o = IMM_B_I;
alu_operator_o = ALU_ADD;
end else begin
// Calculate and store PC+4
alu_op_a_mux_sel_o = OP_A_CURRPC;
alu_op_b_mux_sel_o = OP_B_IMM;
imm_b_mux_sel_o = IMM_B_INCR_PC;
alu_operator_o = ALU_ADD;
end
end
OPCODE_BRANCH: begin // Branch
// Check branch condition selection
unique case (instr_alu[14:12])
3'b000: alu_operator_o = ALU_EQ;
3'b001: alu_operator_o = ALU_NE;
3'b100: alu_operator_o = ALU_LT;
3'b101: alu_operator_o = ALU_GE;
3'b110: alu_operator_o = ALU_LTU;
3'b111: alu_operator_o = ALU_GEU;
default: ;
endcase
if (BranchTargetALU) begin
// With branch target ALU main ALU evaluates branch condition and branch target ALU
// calculates target (which is controlled in a seperate block below)
alu_op_a_mux_sel_o = OP_A_REG_A;
alu_op_b_mux_sel_o = OP_B_REG_B;
jt_mux_sel_o = JT_BT_ALU;
end else begin
// Without branch target ALU branch is 2 stage operation using the Main ALU in both stages
if (instr_new_i) begin
// First evaluates branch condition
alu_op_a_mux_sel_o = OP_A_REG_A;
alu_op_b_mux_sel_o = OP_B_REG_B;
end else begin
// Then calculate jump target
alu_op_a_mux_sel_o = OP_A_CURRPC;
alu_op_b_mux_sel_o = OP_B_IMM;
imm_b_mux_sel_o = IMM_B_B;
alu_operator_o = ALU_ADD;
end
end
end
////////////////
// Load/store //
////////////////
OPCODE_STORE: begin
alu_op_a_mux_sel_o = OP_A_REG_A;
alu_op_b_mux_sel_o = OP_B_REG_B;
alu_operator_o = ALU_ADD;
if (!instr_alu[14]) begin
// offset from immediate
imm_b_mux_sel_o = IMM_B_S;
alu_op_b_mux_sel_o = OP_B_IMM;
end
end
OPCODE_LOAD: begin
alu_op_a_mux_sel_o = OP_A_REG_A;
// offset from immediate
alu_operator_o = ALU_ADD;
alu_op_b_mux_sel_o = OP_B_IMM;
imm_b_mux_sel_o = IMM_B_I;
end
/////////
// ALU //
/////////
OPCODE_LUI: begin // Load Upper Immediate
alu_op_a_mux_sel_o = OP_A_IMM;
alu_op_b_mux_sel_o = OP_B_IMM;
imm_a_mux_sel_o = IMM_A_ZERO;
imm_b_mux_sel_o = IMM_B_U;
alu_operator_o = ALU_ADD;
end
OPCODE_AUIPC: begin // Add Upper Immediate to PC
alu_op_a_mux_sel_o = OP_A_CURRPC;
alu_op_b_mux_sel_o = OP_B_IMM;
imm_b_mux_sel_o = IMM_B_U;
alu_operator_o = ALU_ADD;
end
OPCODE_OP_IMM: begin // Register-Immediate ALU Operations
alu_op_a_mux_sel_o = OP_A_REG_A;
alu_op_b_mux_sel_o = OP_B_IMM;
imm_b_mux_sel_o = IMM_B_I;
unique case (instr_alu[14:12])
3'b000: alu_operator_o = ALU_ADD; // Add Immediate
3'b010: alu_operator_o = ALU_SLT; // Set to one if Lower Than Immediate
3'b011: alu_operator_o = ALU_SLTU; // Set to one if Lower Than Immediate Unsigned
3'b100: alu_operator_o = ALU_XOR; // Exclusive Or with Immediate
3'b110: alu_operator_o = ALU_OR; // Or with Immediate
3'b111: alu_operator_o = ALU_AND; // And with Immediate
3'b001: begin
alu_operator_o = ALU_SLL; // Shift Left Logical by Immediate
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
end
end
default: ;
endcase
end
OPCODE_OP: begin // Register-Register ALU operation
alu_op_a_mux_sel_o = OP_A_REG_A;
alu_op_b_mux_sel_o = OP_B_REG_B;
unique case ({instr_alu[30:25], instr_alu[14:12]})
// RV32I ALU operations
{6'b00_0000, 3'b000}: alu_operator_o = ALU_ADD; // Add
{6'b10_0000, 3'b000}: alu_operator_o = ALU_SUB; // Sub
{6'b00_0000, 3'b010}: alu_operator_o = ALU_SLT; // Set Lower Than
{6'b00_0000, 3'b011}: alu_operator_o = ALU_SLTU; // Set Lower Than Unsigned
{6'b00_0000, 3'b100}: alu_operator_o = ALU_XOR; // Xor
{6'b00_0000, 3'b110}: alu_operator_o = ALU_OR; // Or
{6'b00_0000, 3'b111}: alu_operator_o = ALU_AND; // And
{6'b00_0000, 3'b001}: alu_operator_o = ALU_SLL; // Shift Left Logical
{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
// supported RV32M instructions, all use the same ALU operation
{6'b00_0001, 3'b000}, // mul
{6'b00_0001, 3'b001}, // mulh
{6'b00_0001, 3'b010}, // mulhsu
{6'b00_0001, 3'b011}, // mulhu
{6'b00_0001, 3'b100}, // div
{6'b00_0001, 3'b101}, // divu
{6'b00_0001, 3'b110}, // rem
{6'b00_0001, 3'b111}: begin // remu
alu_operator_o = ALU_ADD;
end
default: ;
endcase
end
/////////////
// Special //
/////////////
OPCODE_MISC_MEM: begin
// For now, treat the FENCE (funct3 == 000) instruction as a NOP. This may not be correct
// in a system with caches and should be revisited.
// FENCE.I will flush the IF stage and prefetch buffer but nothing else.
unique case (instr_alu[14:12])
3'b000: begin
alu_operator_o = ALU_ADD; // nop
alu_op_a_mux_sel_o = OP_A_REG_A;
alu_op_b_mux_sel_o = OP_B_IMM;
end
3'b001: begin
alu_op_a_mux_sel_o = OP_A_CURRPC;
alu_op_b_mux_sel_o = OP_B_IMM;
imm_b_mux_sel_o = IMM_B_INCR_PC;
alu_operator_o = ALU_ADD;
end
default: ;
endcase
end
OPCODE_SYSTEM: begin
if (instr_alu[14:12] == 3'b000) begin
// non CSR related SYSTEM instructions
alu_op_a_mux_sel_o = OP_A_REG_A;
alu_op_b_mux_sel_o = OP_B_IMM;
end else begin
// instruction to read/modify CSR
alu_op_b_mux_sel_o = OP_B_IMM;
imm_a_mux_sel_o = IMM_A_Z;
imm_b_mux_sel_o = IMM_B_I; // CSR address is encoded in I imm
if (instr_alu[14]) begin
// rs1 field is used as immediate
alu_op_a_mux_sel_o = OP_A_IMM;
end else begin
alu_op_a_mux_sel_o = OP_A_REG_A;
end
end
end
default: ;
endcase
end
// make sure instructions accessing non-available registers in RV32E cause illegal // make sure instructions accessing non-available registers in RV32E cause illegal
// instruction exceptions // instruction exceptions
assign illegal_insn_o = illegal_insn | illegal_reg_rv32e; assign illegal_insn_o = illegal_insn | illegal_reg_rv32e;
@ -656,5 +804,4 @@ module ibex_decoder #(
// Selectors must be known/valid. // Selectors must be known/valid.
`ASSERT(IbexRegImmAluOpKnown, (opcode == OPCODE_OP_IMM) |-> `ASSERT(IbexRegImmAluOpKnown, (opcode == OPCODE_OP_IMM) |->
!$isunknown(instr[14:12]), clk_i, !rst_ni) !$isunknown(instr[14:12]), clk_i, !rst_ni)
endmodule // controller endmodule // controller

View file

@ -34,6 +34,7 @@ module ibex_id_stage #(
input logic instr_valid_i, input logic instr_valid_i,
input logic instr_new_i, input logic instr_new_i,
input logic [31:0] instr_rdata_i, // from IF-ID pipeline registers input logic [31:0] instr_rdata_i, // from IF-ID pipeline registers
input logic [31:0] instr_rdata_alu_i, // from IF-ID pipeline registers
input logic [15:0] instr_rdata_c_i, // from IF-ID pipeline registers input logic [15:0] instr_rdata_c_i, // from IF-ID pipeline registers
input logic instr_is_compressed_i, input logic instr_is_compressed_i,
output logic instr_req_o, output logic instr_req_o,
@ -341,6 +342,7 @@ module ibex_id_stage #(
// from IF-ID pipeline register // from IF-ID pipeline register
.instr_new_i ( instr_new_i ), .instr_new_i ( instr_new_i ),
.instr_rdata_i ( instr_rdata_i ), .instr_rdata_i ( instr_rdata_i ),
.instr_rdata_alu_i ( instr_rdata_alu_i ),
.illegal_c_insn_i ( illegal_c_insn_i ), .illegal_c_insn_i ( illegal_c_insn_i ),
// immediates // immediates
@ -676,10 +678,18 @@ module ibex_id_stage #(
(instr_valid_i && !(illegal_c_insn_i || instr_fetch_err_i)) |-> !$isunknown(instr_rdata_i), (instr_valid_i && !(illegal_c_insn_i || instr_fetch_err_i)) |-> !$isunknown(instr_rdata_i),
clk_i, !rst_ni) clk_i, !rst_ni)
// Instruction delivered to ID stage can not contain X.
`ASSERT(IbexIdInstrALUKnown,
(instr_valid_i && !(illegal_c_insn_i || instr_fetch_err_i)) |-> !$isunknown(instr_rdata_alu_i),
clk_i, !rst_ni)
// Multicycle enable signals must be unique. // Multicycle enable signals must be unique.
`ASSERT(IbexMulticycleEnableUnique, `ASSERT(IbexMulticycleEnableUnique,
$onehot0({data_req_dec, multdiv_en_dec, branch_in_dec, jump_in_dec}), clk_i, !rst_ni) $onehot0({data_req_dec, multdiv_en_dec, branch_in_dec, jump_in_dec}), clk_i, !rst_ni)
// Duplicated instruction flops must match
`ASSERT(IbexDuplicateInstrMatch, instr_valid_i |-> instr_rdata_i == instr_rdata_alu_i, clk_i, !rst_ni);
`ifdef CHECK_MISALIGNED `ifdef CHECK_MISALIGNED
`ASSERT(IbexMisalignedMemoryAccess, !lsu_addr_incr_req_i, clk_i, !rst_ni) `ASSERT(IbexMisalignedMemoryAccess, !lsu_addr_incr_req_i, clk_i, !rst_ni)
`endif `endif

View file

@ -35,6 +35,8 @@ module ibex_if_stage #(
output logic instr_valid_id_o, // instr in IF-ID is valid output logic instr_valid_id_o, // instr in IF-ID is valid
output logic instr_new_id_o, // instr in IF-ID is new output logic instr_new_id_o, // instr in IF-ID is new
output logic [31:0] instr_rdata_id_o, // instr for ID stage output logic [31:0] instr_rdata_id_o, // instr for ID stage
output logic [31:0] instr_rdata_alu_id_o, // replicated instr for ID stage
// to reduce fan-out
output logic [15:0] instr_rdata_c_id_o, // compressed instr for ID stage output logic [15:0] instr_rdata_c_id_o, // compressed instr for ID stage
// (mtval), meaningful only if // (mtval), meaningful only if
// instr_is_compressed_id_o = 1'b1 // instr_is_compressed_id_o = 1'b1
@ -237,6 +239,7 @@ module ibex_if_stage #(
instr_new_id_o <= 1'b0; instr_new_id_o <= 1'b0;
instr_valid_id_o <= 1'b0; instr_valid_id_o <= 1'b0;
instr_rdata_id_o <= '0; instr_rdata_id_o <= '0;
instr_rdata_alu_id_o <= '0;
instr_fetch_err_o <= '0; instr_fetch_err_o <= '0;
instr_rdata_c_id_o <= '0; instr_rdata_c_id_o <= '0;
instr_is_compressed_id_o <= 1'b0; instr_is_compressed_id_o <= 1'b0;
@ -247,6 +250,8 @@ module ibex_if_stage #(
if (if_id_pipe_reg_we) begin if (if_id_pipe_reg_we) begin
instr_valid_id_o <= 1'b1; instr_valid_id_o <= 1'b1;
instr_rdata_id_o <= instr_decompressed; instr_rdata_id_o <= instr_decompressed;
// To reduce fan-out and help timing from the instr_rdata_id flops they are replicated.
instr_rdata_alu_id_o <= instr_decompressed;
instr_fetch_err_o <= fetch_err; instr_fetch_err_o <= fetch_err;
instr_rdata_c_id_o <= fetch_rdata[15:0]; instr_rdata_c_id_o <= fetch_rdata[15:0];
instr_is_compressed_id_o <= instr_is_compressed_int; instr_is_compressed_id_o <= instr_is_compressed_int;