mirror of
https://github.com/lowRISC/ibex.git
synced 2025-06-28 01:12:02 -04:00
[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:
parent
639964514c
commit
486bf45711
5 changed files with 307 additions and 141 deletions
|
@ -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]
|
||||
// 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]
|
||||
// cleaner to write all bits even if not all are used
|
||||
|
|
|
@ -101,6 +101,8 @@ module ibex_core #(
|
|||
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 instr_is_compressed_id;
|
||||
logic instr_fetch_err; // Bus error on instr fetch
|
||||
|
@ -322,6 +324,7 @@ module ibex_core #(
|
|||
.instr_valid_id_o ( instr_valid_id ),
|
||||
.instr_new_id_o ( instr_new_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_is_compressed_id_o ( instr_is_compressed_id ),
|
||||
.instr_fetch_err_o ( instr_fetch_err ),
|
||||
|
@ -378,6 +381,7 @@ module ibex_core #(
|
|||
.instr_valid_i ( instr_valid_id ),
|
||||
.instr_new_i ( instr_new_id ),
|
||||
.instr_rdata_i ( instr_rdata_id ),
|
||||
.instr_rdata_alu_i ( instr_rdata_alu_id ),
|
||||
.instr_rdata_c_i ( instr_rdata_c_id ),
|
||||
.instr_is_compressed_i ( instr_is_compressed_id ),
|
||||
|
||||
|
|
|
@ -38,6 +38,9 @@ module ibex_decoder #(
|
|||
// from IF-ID pipeline register
|
||||
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_alu_i, // instruction read from memory/cache
|
||||
// replicated to ease fan-out)
|
||||
|
||||
input logic illegal_c_insn_i, // compressed instruction decode failed
|
||||
|
||||
// immediates
|
||||
|
@ -98,12 +101,18 @@ module ibex_decoder #(
|
|||
logic regfile_we;
|
||||
|
||||
logic [31:0] instr;
|
||||
logic [31:0] instr_alu;
|
||||
|
||||
csr_op_e csr_op;
|
||||
|
||||
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 //
|
||||
|
@ -185,12 +194,6 @@ module ibex_decoder #(
|
|||
jump_in_dec_o = 1'b0;
|
||||
jump_set_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;
|
||||
div_en_o = 1'b0;
|
||||
|
@ -216,8 +219,6 @@ module ibex_decoder #(
|
|||
ecall_insn_o = 1'b0;
|
||||
wfi_insn_o = 1'b0;
|
||||
|
||||
jt_mux_sel_o = JT_ALU;
|
||||
|
||||
opcode = opcode_e'(instr[6:0]);
|
||||
|
||||
unique case (opcode)
|
||||
|
@ -229,24 +230,12 @@ module ibex_decoder #(
|
|||
OPCODE_JAL: begin // Jump and Link
|
||||
jump_in_dec_o = 1'b1;
|
||||
|
||||
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;
|
||||
regfile_we = 1'b0;
|
||||
jump_set_o = 1'b1;
|
||||
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;
|
||||
regfile_we = 1'b1;
|
||||
end
|
||||
end
|
||||
|
@ -254,24 +243,12 @@ module ibex_decoder #(
|
|||
OPCODE_JALR: begin // Jump and Link Register
|
||||
jump_in_dec_o = 1'b1;
|
||||
|
||||
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;
|
||||
regfile_we = 1'b0;
|
||||
jump_set_o = 1'b1;
|
||||
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;
|
||||
regfile_we = 1'b1;
|
||||
end
|
||||
if (instr[14:12] != 3'b0) begin
|
||||
|
@ -283,37 +260,14 @@ module ibex_decoder #(
|
|||
branch_in_dec_o = 1'b1;
|
||||
// Check branch condition selection
|
||||
unique case (instr[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: illegal_insn = 1'b1;
|
||||
3'b000,
|
||||
3'b001,
|
||||
3'b100,
|
||||
3'b101,
|
||||
3'b110,
|
||||
3'b111: illegal_insn = 1'b0;
|
||||
default: illegal_insn = 1'b1;
|
||||
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
|
||||
|
||||
////////////////
|
||||
|
@ -321,18 +275,10 @@ module ibex_decoder #(
|
|||
////////////////
|
||||
|
||||
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_we_o = 1'b1;
|
||||
alu_operator_o = ALU_ADD;
|
||||
|
||||
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
|
||||
if (instr[14]) begin
|
||||
illegal_insn = 1'b1;
|
||||
end
|
||||
|
||||
|
@ -346,17 +292,11 @@ module ibex_decoder #(
|
|||
end
|
||||
|
||||
OPCODE_LOAD: begin
|
||||
alu_op_a_mux_sel_o = OP_A_REG_A;
|
||||
data_req_o = 1'b1;
|
||||
regfile_wdata_sel_o = RF_WD_LSU;
|
||||
regfile_we = 1'b1;
|
||||
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
|
||||
data_sign_extension_o = ~instr[14];
|
||||
|
||||
|
@ -381,38 +321,25 @@ module ibex_decoder #(
|
|||
/////////
|
||||
|
||||
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;
|
||||
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;
|
||||
regfile_we = 1'b1;
|
||||
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;
|
||||
regfile_we = 1'b1;
|
||||
|
||||
unique case (instr[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'b000,
|
||||
3'b010,
|
||||
3'b011,
|
||||
3'b100,
|
||||
3'b110,
|
||||
3'b111: illegal_insn = 1'b0;
|
||||
|
||||
3'b001: begin
|
||||
alu_operator_o = ALU_SLL; // Shift Left Logical by Immediate
|
||||
if (instr[31:25] != 7'b0) begin
|
||||
illegal_insn = 1'b1;
|
||||
end
|
||||
|
@ -420,23 +347,21 @@ module ibex_decoder #(
|
|||
|
||||
3'b101: 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
|
||||
alu_operator_o = ALU_SRA; // Shift Right Arithmetically by Immediate
|
||||
illegal_insn = 1'b0;
|
||||
end else begin
|
||||
illegal_insn = 1'b1;
|
||||
end
|
||||
end
|
||||
|
||||
default: begin
|
||||
alu_operator_o = ALU_SLTU;
|
||||
illegal_insn = 1'b1;
|
||||
end
|
||||
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;
|
||||
regfile_we = 1'b1;
|
||||
|
||||
if (instr[31]) begin
|
||||
|
@ -444,69 +369,61 @@ module ibex_decoder #(
|
|||
end else begin
|
||||
unique case ({instr[30:25], instr[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
|
||||
{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 RV32M instructions
|
||||
{6'b00_0001, 3'b000}: begin // mul
|
||||
alu_operator_o = ALU_ADD;
|
||||
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
|
||||
alu_operator_o = ALU_ADD;
|
||||
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
|
||||
alu_operator_o = ALU_ADD;
|
||||
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
|
||||
alu_operator_o = ALU_ADD;
|
||||
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
|
||||
alu_operator_o = ALU_ADD;
|
||||
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
|
||||
alu_operator_o = ALU_ADD;
|
||||
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
|
||||
alu_operator_o = ALU_ADD;
|
||||
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
|
||||
alu_operator_o = ALU_ADD;
|
||||
multdiv_operator_o = MD_OP_REM;
|
||||
div_en_o = RV32M ? 1'b1 : 1'b0;
|
||||
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.
|
||||
unique case (instr[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;
|
||||
regfile_we = 1'b0;
|
||||
end
|
||||
3'b001: begin
|
||||
|
@ -540,10 +454,6 @@ module ibex_decoder #(
|
|||
// requests will be ignored).
|
||||
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;
|
||||
|
||||
if (instr_new_i) begin
|
||||
|
@ -559,8 +469,6 @@ module ibex_decoder #(
|
|||
OPCODE_SYSTEM: begin
|
||||
if (instr[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;
|
||||
unique case (instr[31:20])
|
||||
12'h000: // ECALL
|
||||
// environment (system) call
|
||||
|
@ -592,16 +500,6 @@ module ibex_decoder #(
|
|||
csr_access_o = 1'b1;
|
||||
regfile_wdata_sel_o = RF_WD_CSR;
|
||||
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])
|
||||
2'b01: csr_op = CSR_OP_WRITE;
|
||||
|
@ -642,6 +540,256 @@ module ibex_decoder #(
|
|||
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
|
||||
// instruction exceptions
|
||||
assign illegal_insn_o = illegal_insn | illegal_reg_rv32e;
|
||||
|
@ -656,5 +804,4 @@ module ibex_decoder #(
|
|||
// Selectors must be known/valid.
|
||||
`ASSERT(IbexRegImmAluOpKnown, (opcode == OPCODE_OP_IMM) |->
|
||||
!$isunknown(instr[14:12]), clk_i, !rst_ni)
|
||||
|
||||
endmodule // controller
|
||||
|
|
|
@ -34,6 +34,7 @@ module ibex_id_stage #(
|
|||
input logic instr_valid_i,
|
||||
input logic instr_new_i,
|
||||
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 instr_is_compressed_i,
|
||||
output logic instr_req_o,
|
||||
|
@ -341,6 +342,7 @@ module ibex_id_stage #(
|
|||
// from IF-ID pipeline register
|
||||
.instr_new_i ( instr_new_i ),
|
||||
.instr_rdata_i ( instr_rdata_i ),
|
||||
.instr_rdata_alu_i ( instr_rdata_alu_i ),
|
||||
.illegal_c_insn_i ( illegal_c_insn_i ),
|
||||
|
||||
// immediates
|
||||
|
@ -676,10 +678,18 @@ module ibex_id_stage #(
|
|||
(instr_valid_i && !(illegal_c_insn_i || instr_fetch_err_i)) |-> !$isunknown(instr_rdata_i),
|
||||
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.
|
||||
`ASSERT(IbexMulticycleEnableUnique,
|
||||
$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
|
||||
`ASSERT(IbexMisalignedMemoryAccess, !lsu_addr_incr_req_i, clk_i, !rst_ni)
|
||||
`endif
|
||||
|
|
|
@ -35,6 +35,8 @@ module ibex_if_stage #(
|
|||
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 [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
|
||||
// (mtval), meaningful only if
|
||||
// instr_is_compressed_id_o = 1'b1
|
||||
|
@ -237,6 +239,7 @@ module ibex_if_stage #(
|
|||
instr_new_id_o <= 1'b0;
|
||||
instr_valid_id_o <= 1'b0;
|
||||
instr_rdata_id_o <= '0;
|
||||
instr_rdata_alu_id_o <= '0;
|
||||
instr_fetch_err_o <= '0;
|
||||
instr_rdata_c_id_o <= '0;
|
||||
instr_is_compressed_id_o <= 1'b0;
|
||||
|
@ -247,6 +250,8 @@ module ibex_if_stage #(
|
|||
if (if_id_pipe_reg_we) begin
|
||||
instr_valid_id_o <= 1'b1;
|
||||
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_rdata_c_id_o <= fetch_rdata[15:0];
|
||||
instr_is_compressed_id_o <= instr_is_compressed_int;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue