mirror of
https://github.com/lowRISC/ibex.git
synced 2025-04-22 21:07:34 -04:00
Fixed Jumps and Branches (jump target now calculated in ID, up for debate) and some general code cleanups
This commit is contained in:
parent
c974349bbc
commit
af8b208029
7 changed files with 334 additions and 449 deletions
16
alu.sv
16
alu.sv
|
@ -36,7 +36,7 @@ module alu
|
|||
input logic [`ALU_OP_WIDTH-1:0] operator_i,
|
||||
input logic [31:0] operand_a_i,
|
||||
input logic [31:0] operand_b_i,
|
||||
input logic [31:0] operand_c_i, // for jump target calculation
|
||||
input logic [31:0] operand_c_i,
|
||||
input logic carry_i,
|
||||
input logic flag_i,
|
||||
|
||||
|
@ -45,15 +45,12 @@ module alu
|
|||
input logic [1:0] vec_ext_i,
|
||||
|
||||
output logic [31:0] result_o,
|
||||
output logic [31:0] jump_target_o,
|
||||
output logic overflow_o,
|
||||
output logic carry_o,
|
||||
output logic flag_o
|
||||
);
|
||||
|
||||
|
||||
logic [31:0] pc_after_jal;
|
||||
|
||||
logic [31:0] operand_a_rev; // bit reversed signal of operand_a_i
|
||||
|
||||
// bit reverse operand_a for left shifts
|
||||
|
@ -144,9 +141,6 @@ module alu
|
|||
assign {carry_out[2], adder_result[23:16]} = adder_op_a[23:16] + adder_op_b[23:16] + carry_in[2];
|
||||
assign {carry_out[3], adder_result[31:24]} = adder_op_a[31:24] + adder_op_b[31:24] + carry_in[3];
|
||||
|
||||
// additional 32 bit adder for PC after JAL(R) instruction
|
||||
assign pc_after_jal = operand_c_i + 32'd4;
|
||||
|
||||
|
||||
// averaging by right shifting of one bit
|
||||
logic [31:0] result_avg;
|
||||
|
@ -549,7 +543,6 @@ module alu
|
|||
shift_left = 1'b0;
|
||||
shift_amt = operand_b_i;
|
||||
result_o = 'x;
|
||||
jump_target_o = 1'b0;
|
||||
carry_o = 1'b0;
|
||||
overflow_o = 1'b0;
|
||||
flag_o = 1'b0;
|
||||
|
@ -567,13 +560,6 @@ module alu
|
|||
`ALU_OR: result_o = operand_a_i | operand_b_i;
|
||||
`ALU_XOR: result_o = operand_a_i ^ operand_b_i;
|
||||
|
||||
// Jump Target Calculation
|
||||
`ALU_JAL:
|
||||
begin
|
||||
result_o = pc_after_jal;
|
||||
jump_target_o = adder_result;
|
||||
end
|
||||
|
||||
// Shift Operations
|
||||
`ALU_MOVHI:
|
||||
begin
|
||||
|
|
466
controller.sv
466
controller.sv
|
@ -40,6 +40,8 @@ module controller
|
|||
output logic eoc_o, // End of computation: triggered by a special instruction
|
||||
output logic core_busy_o, // Core is busy processing instructions
|
||||
|
||||
output logic force_nop_o,
|
||||
|
||||
input logic [31:0] instr_rdata_i, // Instruction read from instr memory/cache: (sampled in the if stage)
|
||||
output logic instr_req_o, // Fetch instruction Request:
|
||||
input logic instr_gnt_i, // grant from icache
|
||||
|
@ -103,7 +105,7 @@ module controller
|
|||
input logic irq_present_i, // there is an IRQ, so if we are sleeping we should wake up now
|
||||
|
||||
// Exception Controller Signals
|
||||
output logic jump_in_id_o, // jump instruction in ID stage
|
||||
//output logic jump_in_id_o, // jump instruction in ID stage
|
||||
output logic illegal_insn_o, // illegal instruction encountered
|
||||
output logic trap_insn_o, // trap instruction encountered
|
||||
output logic pipe_flush_o, // pipe flush requested by controller
|
||||
|
@ -136,16 +138,9 @@ module controller
|
|||
output logic [1:0] operand_c_fw_mux_sel_o, // regfile rc data selector form ID stage
|
||||
|
||||
// Jump target calcuation done detection
|
||||
input logic jump_in_ex_i, // jump is being calculated in ALU
|
||||
input logic [1:0] jump_in_ex_i, // jump is being calculated in ALU
|
||||
output logic [1:0] jump_in_id_o, // jump is being calculated in ALU
|
||||
|
||||
// Branch result from ALU
|
||||
input logic branch_taken_i,
|
||||
|
||||
output logic drop_instruction_o, // prevent instruction to enter ID stage
|
||||
`ifdef BRANCH_PREDICTION
|
||||
output logic wrong_branch_taken_o, // 1 if the wrong branch was selected
|
||||
output logic take_branch_o, // 1 if branch should be taken
|
||||
`endif
|
||||
output logic stall_if_o, // Stall IF stage (deassert requests)
|
||||
output logic stall_id_o, // Stall ID stage (and instr and data memory interface) ( ID_STAGE )
|
||||
output logic stall_ex_o, // Stall ex stage ( EX_STAGE )
|
||||
|
@ -182,7 +177,7 @@ module controller
|
|||
logic mfspr_stall;
|
||||
logic instr_ack_stall;
|
||||
logic load_stall;
|
||||
logic j_stall;
|
||||
logic jr_stall;
|
||||
|
||||
logic set_npc;
|
||||
`ifdef BRANCH_PREDICTION
|
||||
|
@ -207,8 +202,9 @@ module controller
|
|||
|
||||
instr_req_o = 1'b1;
|
||||
|
||||
pc_mux_sel_o = `INCR_PC;
|
||||
pc_mux_sel_o = `PC_INCR;
|
||||
pc_mux_boot_o = 1'b0;
|
||||
jump_in_id_o = 2'b00;
|
||||
|
||||
alu_operator = `ALU_NOP;
|
||||
extend_immediate_o = 1'b0;
|
||||
|
@ -287,7 +283,7 @@ module controller
|
|||
// we begin execution when either fetch_enable is high or an
|
||||
// interrupt has arrived
|
||||
instr_req_o = fetch_enable_i || irq_present_i;
|
||||
pc_mux_sel_o = `NO_INCR;
|
||||
pc_mux_sel_o = `PC_NO_INCR;
|
||||
|
||||
if (fetch_enable_i || irq_present_i)
|
||||
begin
|
||||
|
@ -323,13 +319,17 @@ module controller
|
|||
|
||||
`OPCODE_JAL: begin // Jump and Link
|
||||
if (instr_rdata_i ==? `INSTR_JAL) begin
|
||||
pc_mux_sel_o = `PC_FROM_ALU;
|
||||
// Insert bubbles
|
||||
pc_mux_sel_o = `PC_NO_INCR;
|
||||
jump_in_id_o = 2'b01;
|
||||
// Calculate and store PC+4
|
||||
alu_op_a_mux_sel_o = `OP_A_CURRPC;
|
||||
alu_op_b_mux_sel_o = `OP_B_IMM;
|
||||
alu_op_c_mux_sel_o = `OP_C_CURRPC;
|
||||
immediate_mux_sel_o = `IMM_UJ;
|
||||
alu_operator = `ALU_JAL;
|
||||
immediate_mux_sel_o = `IMM_HEX4;
|
||||
alu_operator = `ALU_ADD;
|
||||
regfile_alu_we = 1'b1;
|
||||
// Calculate jump target (= PC + UJ imm)
|
||||
alu_op_c_mux_sel_o = `OP_C_JT;
|
||||
end else begin
|
||||
illegal_insn_o = 1'b1;
|
||||
end
|
||||
|
@ -337,21 +337,29 @@ module controller
|
|||
|
||||
`OPCODE_JALR: begin // Jump and Link Register
|
||||
if (instr_rdata_i ==? `INSTR_JALR) begin
|
||||
pc_mux_sel_o = `PC_FROM_ALU;
|
||||
// Insert bubbles
|
||||
pc_mux_sel_o = `PC_NO_INCR;
|
||||
jump_in_id_o = 2'b01;
|
||||
// Calculate and store PC+4
|
||||
alu_op_a_mux_sel_o = `OP_A_CURRPC;
|
||||
alu_op_b_mux_sel_o = `OP_B_IMM;
|
||||
alu_op_c_mux_sel_o = `OP_C_CURRPC;
|
||||
immediate_mux_sel_o = `IMM_I;
|
||||
alu_operator = `ALU_JAL;
|
||||
immediate_mux_sel_o = `IMM_HEX4;
|
||||
alu_operator = `ALU_ADD;
|
||||
regfile_alu_we = 1'b1;
|
||||
// Calculate jump target (= RS1 + I imm)
|
||||
rega_used = 1'b1;
|
||||
alu_op_c_mux_sel_o = `OP_C_JT;
|
||||
end else begin
|
||||
illegal_insn_o = 1'b1;
|
||||
end
|
||||
end
|
||||
|
||||
`OPCODE_BRANCH: begin // Branch
|
||||
rega_used = 1'b1;
|
||||
regb_used = 1'b1;
|
||||
pc_mux_sel_o = `PC_NO_INCR;
|
||||
jump_in_id_o = 2'b10;
|
||||
alu_op_c_mux_sel_o = `OP_C_JT;
|
||||
rega_used = 1'b1;
|
||||
regb_used = 1'b1;
|
||||
|
||||
unique case (instr_rdata_i) inside
|
||||
`INSTR_BEQ: alu_operator = `ALU_EQ;
|
||||
|
@ -366,32 +374,15 @@ module controller
|
|||
end
|
||||
endcase // case (instr_rdata_i)
|
||||
|
||||
if (branch_taken_i == 1'b1) begin
|
||||
/*if (branch_taken_i == 1'b1) begin
|
||||
pc_mux_sel_o = `PC_FROM_IMM; // TODO: Think about clever adder use
|
||||
end else begin
|
||||
pc_mux_sel_o = `INCR_PC;
|
||||
end
|
||||
end*/
|
||||
end
|
||||
|
||||
/*
|
||||
|
||||
`OPCODE_JR:
|
||||
begin // Jump Register
|
||||
pc_mux_sel_o = `PC_FROM_REGFILE;
|
||||
regb_used = 1'b1;
|
||||
end
|
||||
|
||||
`OPCODE_JALR: begin // Jump and Link Register
|
||||
pc_mux_sel_o = `PC_FROM_REGFILE;
|
||||
alu_op_a_mux_sel_o = `OP_A_CURRPC;
|
||||
alu_op_b_mux_sel_o = `OP_B_IMM;
|
||||
immediate_mux_sel_o = `IMM_HEX4;
|
||||
alu_operator = `ALU_ADD;
|
||||
regfile_alu_waddr_mux_sel_o = 2'b10; // select r9 to write back return address
|
||||
regfile_alu_we = 1'b1;
|
||||
regb_used = 1'b1;
|
||||
end
|
||||
|
||||
`ifndef BRANCH_PREDICTION
|
||||
`OPCODE_BNF:
|
||||
begin // Branch if No Flag
|
||||
|
@ -448,7 +439,7 @@ module controller
|
|||
|
||||
`OPCODE_EOC: begin // End of Computation (Custom Instruction 1)
|
||||
eoc_o = 1'b1;
|
||||
pc_mux_sel_o = `NO_INCR;
|
||||
pc_mux_sel_o = `PC_NO_INCR;
|
||||
end
|
||||
|
||||
`OPCODE_RFE:
|
||||
|
@ -619,9 +610,9 @@ module controller
|
|||
data_sign_extension_o = instr_rdata_i[1];
|
||||
end
|
||||
|
||||
|
||||
*/
|
||||
|
||||
|
||||
//////////////////////////
|
||||
// _ _ _ _ //
|
||||
// / \ | | | | | | //
|
||||
|
@ -671,19 +662,7 @@ module controller
|
|||
endcase // unique case (instr_rdata_i)
|
||||
end // case: `OPCODE_OPIMM
|
||||
|
||||
/*
|
||||
`OPCODE_ADDIC: begin // Add Immediate and Carry
|
||||
alu_op_b_mux_sel_o = `OP_B_IMM;
|
||||
immediate_mux_sel_o = `IMM_16;
|
||||
alu_operator = `ALU_ADDC;
|
||||
regfile_alu_we = 1'b1;
|
||||
set_overflow = 1'b1;
|
||||
set_carry = 1'b1;
|
||||
rega_used = 1'b1;
|
||||
end
|
||||
*/
|
||||
|
||||
`OPCODE_OP: begin // ALU register-register operation
|
||||
`OPCODE_OP: begin // Register-Register ALU operation
|
||||
regfile_alu_we = 1'b1;
|
||||
rega_used = 1'b1;
|
||||
regb_used = 1'b1;
|
||||
|
@ -712,24 +691,6 @@ module controller
|
|||
|
||||
/*
|
||||
|
||||
`OPCODE_MOVHI:
|
||||
begin
|
||||
if (instr_rdata_i[16] == 1'b0)
|
||||
begin // Move Immediate High
|
||||
extend_immediate_o = 1'b1;
|
||||
alu_op_a_mux_sel_o = `OP_A_IMM16;
|
||||
alu_operator = `ALU_MOVHI;
|
||||
regfile_alu_we = 1'b1;
|
||||
end
|
||||
else
|
||||
begin
|
||||
// synopsys translate_off
|
||||
$display("%t: Illegal l.movhi received.", $time);
|
||||
// synopsys translate_on
|
||||
illegal_insn_o = 1'b1;
|
||||
end
|
||||
end
|
||||
|
||||
`OPCODE_MULI: begin // Multiply Immediate Signed
|
||||
alu_op_b_mux_sel_o = `OP_B_IMM;
|
||||
immediate_mux_sel_o = `IMM_16;
|
||||
|
@ -911,37 +872,6 @@ module controller
|
|||
endcase
|
||||
end
|
||||
|
||||
`OPCODE_SFI: begin // Set Flag Immediate-Instructions
|
||||
if (instr_rdata_i[25] == 1'b0) begin
|
||||
alu_op_b_mux_sel_o = `OP_B_IMM;
|
||||
immediate_mux_sel_o = `IMM_16;
|
||||
alu_operator = {2'b10, instr_rdata_i[24:21]};
|
||||
set_flag = 1'b1;
|
||||
rega_used = 1'b1;
|
||||
end
|
||||
else begin
|
||||
// synopsys translate_off
|
||||
$display("%t: Illegal Set Flag Immediate instruction received.", $time);
|
||||
// synopsys translate_on
|
||||
illegal_insn_o = 1'b1;
|
||||
end
|
||||
end
|
||||
|
||||
`OPCODE_SF: begin // Set Flag Instruction
|
||||
if (instr_rdata_i[25] == 1'b0) begin
|
||||
alu_operator = {2'b10, instr_rdata_i[24:21]};
|
||||
set_flag = 1'b1;
|
||||
rega_used = 1'b1;
|
||||
regb_used = 1'b1;
|
||||
end
|
||||
else begin
|
||||
// synopsys translate_off
|
||||
$display("%t: Illegal Set Flag instruction received.", $time);
|
||||
// synopsys translate_on
|
||||
illegal_insn_o = 1'b1;
|
||||
end
|
||||
end
|
||||
|
||||
`OPCODE_VEC: begin // vectorial alu operations
|
||||
rega_used = 1'b1;
|
||||
regfile_alu_we = 1'b1;
|
||||
|
@ -1168,11 +1098,10 @@ module controller
|
|||
*/
|
||||
|
||||
default: begin
|
||||
illegal_insn_o = 1'b1;
|
||||
// TODO: Replace with exception
|
||||
pc_mux_sel_o = `NO_INCR;
|
||||
illegal_insn_o = 1'b1;
|
||||
pc_mux_sel_o = `PC_NO_INCR;
|
||||
end
|
||||
|
||||
endcase; // case (instr_rdata_i[6:0])
|
||||
|
||||
// synopsys translate_off
|
||||
|
@ -1203,7 +1132,7 @@ module controller
|
|||
end
|
||||
|
||||
if ( set_npc == 1'b1 )
|
||||
pc_mux_sel_o = `NO_INCR;
|
||||
pc_mux_sel_o = `PC_NO_INCR;
|
||||
|
||||
// hwloop detected, jump to start address!
|
||||
if (hwloop_jump_i == 1'b1)
|
||||
|
@ -1218,184 +1147,153 @@ module controller
|
|||
ctrl_fsm_ns = IDLE;
|
||||
end
|
||||
endcase
|
||||
end
|
||||
end
|
||||
|
||||
assign core_busy_o = (ctrl_fsm_cs != IDLE);
|
||||
assign core_busy_o = (ctrl_fsm_cs != IDLE);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Generate Stall Signals! //
|
||||
////////////////////////////////////////////////////////////////////////////////////////////
|
||||
always_comb
|
||||
begin
|
||||
mfspr_stall = 1'b0;
|
||||
mtspr_stall = 1'b0;
|
||||
load_stall = 1'b0;
|
||||
j_stall = 1'b0;
|
||||
deassert_we = 1'b0;
|
||||
////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Generate Stall Signals! //
|
||||
////////////////////////////////////////////////////////////////////////////////////////////
|
||||
always_comb
|
||||
begin
|
||||
mfspr_stall = 1'b0;
|
||||
mtspr_stall = 1'b0;
|
||||
load_stall = 1'b0;
|
||||
jr_stall = 1'b0;
|
||||
deassert_we = 1'b0;
|
||||
|
||||
/*
|
||||
// Stall because of l.mfspr with dependency
|
||||
if ((regfile_wdata_mux_sel_ex_i == 1'b0) && (regfile_we_ex_i == 1'b1) &&
|
||||
((reg_d_ex_is_reg_a_id == 1'b1) || (reg_d_ex_is_reg_b_id == 1'b1) || (reg_d_ex_is_reg_c_id == 1'b1)) )
|
||||
begin
|
||||
deassert_we = 1'b1;
|
||||
mfspr_stall = 1'b1;
|
||||
end
|
||||
|
||||
// Stall because of l.mtspr (always...)
|
||||
// mtspr in ex stage, normal instruction in id stage which can change an spr reg
|
||||
if ((sp_we_ex_i == 1'b1) && (instr_rdata_i[31:26] != `OPCODE_MTSPR))
|
||||
begin
|
||||
deassert_we = 1'b1;
|
||||
mtspr_stall = 1'b1;
|
||||
end
|
||||
*/
|
||||
|
||||
// Stall because of load operation
|
||||
if ((data_req_ex_i == 1'b1) && (regfile_we_ex_i == 1'b1) &&
|
||||
((reg_d_ex_is_reg_a_id == 1'b1) || (reg_d_ex_is_reg_b_id == 1'b1) || (reg_d_ex_is_reg_c_id == 1'b1)) )
|
||||
begin
|
||||
deassert_we = 1'b1;
|
||||
load_stall = 1'b1;
|
||||
end
|
||||
|
||||
// TODO: check JALR/JR
|
||||
// Stall because of jr path
|
||||
// - Load results cannot directly be forwarded to PC
|
||||
// - Multiplication results cannot be forwarded to PC
|
||||
if ((instr_rdata_i[6:0] == `OPCODE_JALR) &&
|
||||
(((regfile_we_wb_i == 1'b1) && (reg_d_wb_is_reg_b_id == 1'b1) && (data_rvalid_i == 1'b1)) ||
|
||||
((regfile_we_ex_i == 1'b1) && (reg_d_ex_is_reg_b_id == 1'b1)) ||
|
||||
((regfile_alu_we_fw_i == 1'b1) && (reg_d_alu_is_reg_b_id == 1'b1) && (mult_is_running_ex_i == 1'b1))) )
|
||||
begin
|
||||
jr_stall = 1'b1;
|
||||
deassert_we = 1'b1;
|
||||
end
|
||||
end
|
||||
|
||||
// Stall because of IF miss
|
||||
assign instr_ack_stall = ~instr_ack_i;
|
||||
|
||||
// Stall if TCDM contention has been detected
|
||||
assign lsu_stall = ~data_ack_i;
|
||||
|
||||
assign misalign_stall = data_misaligned_i;
|
||||
|
||||
// deassert we signals (in case of stalls)
|
||||
assign alu_operator_o = (deassert_we) ? `ALU_NOP : alu_operator;
|
||||
assign mult_is_running_o = (deassert_we) ? 1'b0 : mult_is_running;
|
||||
assign regfile_we_o = (deassert_we) ? 1'b0 : regfile_we;
|
||||
assign regfile_alu_we_o = (deassert_we) ? 1'b0 : regfile_alu_we;
|
||||
assign data_we_o = (deassert_we) ? 1'b0 : data_we;
|
||||
assign data_req_o = (deassert_we) ? 1'b0 : data_req;
|
||||
assign set_flag_o = (deassert_we) ? 1'b0 : set_flag;
|
||||
assign set_overflow_o = (deassert_we) ? 1'b0 : set_overflow;
|
||||
assign set_carry_o = (deassert_we) ? 1'b0 : set_carry;
|
||||
|
||||
|
||||
/*
|
||||
// Stall because of l.mfspr with dependency
|
||||
if ((regfile_wdata_mux_sel_ex_i == 1'b0) && (regfile_we_ex_i == 1'b1) &&
|
||||
((reg_d_ex_is_reg_a_id == 1'b1) || (reg_d_ex_is_reg_b_id == 1'b1) || (reg_d_ex_is_reg_c_id == 1'b1)) )
|
||||
begin
|
||||
deassert_we = 1'b1;
|
||||
mfspr_stall = 1'b1;
|
||||
end
|
||||
////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Jump and Branch handling //
|
||||
////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Stall because of l.mtspr (always...)
|
||||
// mtspr in ex stage, normal instruction in id stage which can change an spr reg
|
||||
if ((sp_we_ex_i == 1'b1) && (instr_rdata_i[31:26] != `OPCODE_MTSPR))
|
||||
begin
|
||||
deassert_we = 1'b1;
|
||||
mtspr_stall = 1'b1;
|
||||
end
|
||||
*/
|
||||
assign force_nop_o = (jump_in_id_o != 2'b00 || jump_in_ex_i != 2'b00)? 1'b1 : 1'b0;
|
||||
assign drop_instruction_o = 1'b0;
|
||||
|
||||
// Stall because of load operation
|
||||
if ((data_req_ex_i == 1'b1) && (regfile_we_ex_i == 1'b1) &&
|
||||
((reg_d_ex_is_reg_a_id == 1'b1) || (reg_d_ex_is_reg_b_id == 1'b1) || (reg_d_ex_is_reg_c_id == 1'b1)) )
|
||||
begin
|
||||
deassert_we = 1'b1;
|
||||
load_stall = 1'b1;
|
||||
end
|
||||
|
||||
// TODO: check JALR/JR
|
||||
// Stall because of jr path
|
||||
// - Load results cannot directly be forwarded to PC
|
||||
// - Multiplication results cannot be forwarded to PC
|
||||
if ((instr_rdata_i[6:0] == `OPCODE_JALR) &&
|
||||
(((regfile_we_wb_i == 1'b1) && (reg_d_wb_is_reg_b_id == 1'b1) && (data_rvalid_i == 1'b1)) ||
|
||||
((regfile_we_ex_i == 1'b1) && (reg_d_ex_is_reg_b_id == 1'b1)) ||
|
||||
((regfile_alu_we_fw_i == 1'b1) && (reg_d_alu_is_reg_b_id == 1'b1) && (mult_is_running_ex_i == 1'b1))) )
|
||||
begin
|
||||
j_stall = 1'b1;
|
||||
deassert_we = 1'b1;
|
||||
end
|
||||
|
||||
// Stall because of JAL/JALR/branch
|
||||
// Stall until jump target or branch decision is calculated in EX (1 cycle, then fetch instruction)
|
||||
if ( (instr_rdata_i[6:0] == `OPCODE_JAL || instr_rdata_i[6:0] == `OPCODE_JALR
|
||||
|| instr_rdata_i[6:0] == `OPCODE_BRANCH) && (jump_in_ex_i == 1'b0) )
|
||||
begin
|
||||
j_stall = 1'b1;
|
||||
//deassert_we = 1'b1;
|
||||
end
|
||||
|
||||
`ifdef BRANCH_PREDICTION
|
||||
// Stall because of set_flag path
|
||||
if (wrong_branch_taken)
|
||||
begin
|
||||
deassert_we = 1'b1;
|
||||
end
|
||||
`endif
|
||||
|
||||
end
|
||||
|
||||
// NOTE: current_pc_id_i is wrong after drop instruction !
|
||||
`ifdef BRANCH_PREDICTION
|
||||
assign drop_instruction_o = wrong_branch_taken | j_stall;
|
||||
`else
|
||||
assign drop_instruction_o = j_stall;
|
||||
`endif
|
||||
|
||||
// Stall because of IF miss
|
||||
assign instr_ack_stall = ~instr_ack_i;
|
||||
|
||||
// Stall if TCDM contention has been detected
|
||||
assign lsu_stall = ~data_ack_i;
|
||||
|
||||
assign misalign_stall = data_misaligned_i;
|
||||
|
||||
// deassert we signals (in case of stalls)
|
||||
assign alu_operator_o = (deassert_we) ? `ALU_NOP : alu_operator;
|
||||
assign mult_is_running_o = (deassert_we) ? 1'b0 : mult_is_running;
|
||||
assign regfile_we_o = (deassert_we) ? 1'b0 : regfile_we;
|
||||
assign regfile_alu_we_o = (deassert_we) ? 1'b0 : regfile_alu_we;
|
||||
assign data_we_o = (deassert_we) ? 1'b0 : data_we;
|
||||
assign data_req_o = (deassert_we) ? 1'b0 : data_req;
|
||||
assign set_flag_o = (deassert_we) ? 1'b0 : set_flag;
|
||||
assign set_overflow_o = (deassert_we) ? 1'b0 : set_overflow;
|
||||
assign set_carry_o = (deassert_we) ? 1'b0 : set_carry;
|
||||
////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Freeze Unit. This unit controls the pipeline stages //
|
||||
////////////////////////////////////////////////////////////////////////////////////////////
|
||||
always_comb
|
||||
begin
|
||||
// we unstall the if_stage if the debug unit wants to set a new
|
||||
// pc, so that the new value gets written into current_pc_if and is
|
||||
// used by the instr_core_interface
|
||||
stall_if_o = (instr_ack_stall | mfspr_stall | mtspr_stall | load_stall | jr_stall | lsu_stall | misalign_stall | dbg_stall_i | (~pc_valid_i));
|
||||
stall_id_o = instr_ack_stall | mfspr_stall | mtspr_stall | load_stall | jr_stall | lsu_stall | misalign_stall | dbg_stall_i;
|
||||
stall_ex_o = instr_ack_stall | lsu_stall | dbg_stall_i;
|
||||
stall_wb_o = lsu_stall | dbg_stall_i;
|
||||
end
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Freeze Unit. This unit controls the pipeline stages //
|
||||
////////////////////////////////////////////////////////////////////////////////////////////
|
||||
always_comb
|
||||
begin
|
||||
// we unstall the if_stage if the debug unit wants to set a new
|
||||
// pc, so that the new value gets written into current_pc_if and is
|
||||
// used by the instr_core_interface
|
||||
stall_if_o = (instr_ack_stall | mfspr_stall | mtspr_stall | load_stall | j_stall | lsu_stall | misalign_stall | dbg_stall_i | (~pc_valid_i));
|
||||
stall_id_o = instr_ack_stall | mfspr_stall | mtspr_stall | load_stall | j_stall | lsu_stall | misalign_stall | dbg_stall_i;
|
||||
stall_ex_o = instr_ack_stall | lsu_stall | dbg_stall_i;
|
||||
stall_wb_o = lsu_stall | dbg_stall_i;
|
||||
end
|
||||
////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Forwarding control unit. (Forwarding from wb and ex stage to id stage) //
|
||||
// RiscV register encoding: rs1 is [19:15], rs2 is [24:20], rd is [11:7] //
|
||||
// Or10n register encoding: ra is [20:16], rb is [15:11], rd is [25:21] //
|
||||
////////////////////////////////////////////////////////////////////////////////////////////
|
||||
assign reg_d_ex_is_reg_a_id = (regfile_waddr_ex_i == instr_rdata_i[`REG_S1]) && (rega_used == 1'b1);
|
||||
assign reg_d_ex_is_reg_b_id = (regfile_waddr_ex_i == instr_rdata_i[`REG_S2]) && (regb_used == 1'b1);
|
||||
assign reg_d_ex_is_reg_c_id = (regfile_waddr_ex_i == instr_rdata_i[`REG_D]) && (regc_used == 1'b1);
|
||||
assign reg_d_wb_is_reg_a_id = (regfile_waddr_wb_i == instr_rdata_i[`REG_S1]) && (rega_used == 1'b1);
|
||||
assign reg_d_wb_is_reg_b_id = (regfile_waddr_wb_i == instr_rdata_i[`REG_S2]) && (regb_used == 1'b1);
|
||||
assign reg_d_wb_is_reg_c_id = (regfile_waddr_wb_i == instr_rdata_i[`REG_D]) && (regc_used == 1'b1);
|
||||
assign reg_d_alu_is_reg_a_id = (regfile_alu_waddr_fw_i == instr_rdata_i[`REG_S1]) && (rega_used == 1'b1);
|
||||
assign reg_d_alu_is_reg_b_id = (regfile_alu_waddr_fw_i == instr_rdata_i[`REG_S2]) && (regb_used == 1'b1);
|
||||
//assign reg_d_alu_is_reg_c_id = (regfile_alu_waddr_fw_i == instr_rdata_i[`REG_RD]) && (regc_used == 1'b1);
|
||||
|
||||
always_comb
|
||||
begin
|
||||
// default assignements
|
||||
operand_a_fw_mux_sel_o = `SEL_REGFILE;
|
||||
operand_b_fw_mux_sel_o = `SEL_REGFILE;
|
||||
operand_c_fw_mux_sel_o = `SEL_REGFILE;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Forwarding control unit. (Forwarding from wb and ex stage to id stage) //
|
||||
// RiscV register encoding: rs1 is [19:15], rs2 is [24:20], rd is [11:7] //
|
||||
// Or10n register encoding: ra is [20:16], rb is [15:11], rd is [25:21] //
|
||||
////////////////////////////////////////////////////////////////////////////////////////////
|
||||
assign reg_d_ex_is_reg_a_id = (regfile_waddr_ex_i == instr_rdata_i[`REG_S1]) && (rega_used == 1'b1);
|
||||
assign reg_d_ex_is_reg_b_id = (regfile_waddr_ex_i == instr_rdata_i[`REG_S2]) && (regb_used == 1'b1);
|
||||
assign reg_d_ex_is_reg_c_id = (regfile_waddr_ex_i == instr_rdata_i[`REG_D]) && (regc_used == 1'b1);
|
||||
assign reg_d_wb_is_reg_a_id = (regfile_waddr_wb_i == instr_rdata_i[`REG_S1]) && (rega_used == 1'b1);
|
||||
assign reg_d_wb_is_reg_b_id = (regfile_waddr_wb_i == instr_rdata_i[`REG_S2]) && (regb_used == 1'b1);
|
||||
assign reg_d_wb_is_reg_c_id = (regfile_waddr_wb_i == instr_rdata_i[`REG_D]) && (regc_used == 1'b1);
|
||||
assign reg_d_alu_is_reg_a_id = (regfile_alu_waddr_fw_i == instr_rdata_i[`REG_S1]) && (rega_used == 1'b1);
|
||||
assign reg_d_alu_is_reg_b_id = (regfile_alu_waddr_fw_i == instr_rdata_i[`REG_S2]) && (regb_used == 1'b1);
|
||||
//assign reg_d_alu_is_reg_c_id = (regfile_alu_waddr_fw_i == instr_rdata_i[`REG_RD]) && (regc_used == 1'b1);
|
||||
// Forwarding WB -> ID
|
||||
if (regfile_we_wb_i == 1'b1)
|
||||
begin
|
||||
if (reg_d_wb_is_reg_a_id == 1'b1)
|
||||
operand_a_fw_mux_sel_o = `SEL_FW_WB;
|
||||
if (reg_d_wb_is_reg_b_id == 1'b1)
|
||||
operand_b_fw_mux_sel_o = `SEL_FW_WB;
|
||||
if (reg_d_wb_is_reg_c_id == 1'b1)
|
||||
operand_c_fw_mux_sel_o = `SEL_FW_WB;
|
||||
end
|
||||
|
||||
always_comb
|
||||
begin
|
||||
// default assignements
|
||||
operand_a_fw_mux_sel_o = `SEL_REGFILE;
|
||||
operand_b_fw_mux_sel_o = `SEL_REGFILE;
|
||||
operand_c_fw_mux_sel_o = `SEL_REGFILE;
|
||||
|
||||
// Forwarding WB -> ID
|
||||
if (regfile_we_wb_i == 1'b1)
|
||||
begin
|
||||
if (reg_d_wb_is_reg_a_id == 1'b1)
|
||||
operand_a_fw_mux_sel_o = `SEL_FW_WB;
|
||||
if (reg_d_wb_is_reg_b_id == 1'b1)
|
||||
operand_b_fw_mux_sel_o = `SEL_FW_WB;
|
||||
if (reg_d_wb_is_reg_c_id == 1'b1)
|
||||
operand_c_fw_mux_sel_o = `SEL_FW_WB;
|
||||
end
|
||||
|
||||
// Forwarding EX -> ID
|
||||
if (regfile_alu_we_fw_i == 1'b1)
|
||||
begin
|
||||
if (reg_d_alu_is_reg_a_id == 1'b1)
|
||||
operand_a_fw_mux_sel_o = `SEL_FW_EX;
|
||||
if (reg_d_alu_is_reg_b_id == 1'b1)
|
||||
operand_b_fw_mux_sel_o = `SEL_FW_EX;
|
||||
if (reg_d_alu_is_reg_c_id == 1'b1)
|
||||
operand_c_fw_mux_sel_o = `SEL_FW_EX;
|
||||
end
|
||||
|
||||
if (data_misaligned_i == 1'b1)
|
||||
begin
|
||||
operand_a_fw_mux_sel_o = `SEL_FW_EX;
|
||||
operand_b_fw_mux_sel_o = `SEL_REGFILE;
|
||||
end
|
||||
end
|
||||
|
||||
// check if jump or branch in pipeline
|
||||
/*
|
||||
assign jump_in_id_o = ((instr_rdata_i[31:26] == `OPCODE_BF) || (instr_rdata_i[31:26] == `OPCODE_BNF) ||
|
||||
(instr_rdata_i[31:26] == `OPCODE_J) || (instr_rdata_i[31:26] == `OPCODE_JR) ||
|
||||
(instr_rdata_i[31:26] == `OPCODE_JAL) || (instr_rdata_i[31:26] == `OPCODE_JALR) ||
|
||||
(instr_rdata_i[31:26] == `OPCODE_RFE) );
|
||||
*/
|
||||
// TODO: FIXME
|
||||
assign jump_in_id_o = ((instr_rdata_i[6:0] == `OPCODE_JAL) || (instr_rdata_i[6:0] == `OPCODE_JALR) ||
|
||||
(instr_rdata_i[6:0] == `OPCODE_BRANCH));
|
||||
// Forwarding EX -> ID
|
||||
if (regfile_alu_we_fw_i == 1'b1)
|
||||
begin
|
||||
if (reg_d_alu_is_reg_a_id == 1'b1)
|
||||
operand_a_fw_mux_sel_o = `SEL_FW_EX;
|
||||
if (reg_d_alu_is_reg_b_id == 1'b1)
|
||||
operand_b_fw_mux_sel_o = `SEL_FW_EX;
|
||||
if (reg_d_alu_is_reg_c_id == 1'b1)
|
||||
operand_c_fw_mux_sel_o = `SEL_FW_EX;
|
||||
end
|
||||
|
||||
if (data_misaligned_i == 1'b1)
|
||||
begin
|
||||
operand_a_fw_mux_sel_o = `SEL_FW_EX;
|
||||
operand_b_fw_mux_sel_o = `SEL_REGFILE;
|
||||
end
|
||||
end
|
||||
|
||||
// update registers
|
||||
always_ff @(posedge clk , negedge rst_n)
|
||||
|
@ -1426,20 +1324,4 @@ module controller
|
|||
end
|
||||
end
|
||||
|
||||
`ifdef BRANCH_PREDICTION
|
||||
// Wrong branch was taken!
|
||||
always_ff @(posedge clk , negedge rst_n)
|
||||
begin : WRONG_BRANCH
|
||||
if ( rst_n == 1'b0 )
|
||||
begin
|
||||
wrong_branch_taken <= 1'b0;
|
||||
end
|
||||
else
|
||||
begin
|
||||
if (stall_if_o == 1'b0)
|
||||
wrong_branch_taken <= wrong_branch_taken_o;
|
||||
end
|
||||
end
|
||||
`endif
|
||||
|
||||
endmodule // controller
|
||||
|
|
20
ex_stage.sv
20
ex_stage.sv
|
@ -121,11 +121,13 @@ module ex_stage
|
|||
output logic [31:0] regfile_alu_wdata_fw_o, // forward to RF and ID/EX pipe, ALU & MUL
|
||||
output logic [31:0] regfile_alu_wdata_fw_pc_o, // forward to PC, no multiplication
|
||||
|
||||
// JAL/JALR jumpt target calculation (to IF)
|
||||
output logic [31:0] jump_target_o,
|
||||
// From ID: Jump and branch indication
|
||||
input logic [1:0] jump_in_id_i,
|
||||
|
||||
// Branch decision (to controller)
|
||||
output logic branch_taken_o
|
||||
// To IF: Jump and branch target and decision
|
||||
output logic [31:0] jump_target_o,
|
||||
output logic [1:0] jump_in_ex_o,
|
||||
output logic branch_decision_o
|
||||
|
||||
`ifdef TCDM_ADDR_PRECAL
|
||||
,
|
||||
|
@ -140,7 +142,6 @@ module ex_stage
|
|||
|
||||
// Internal output of the LU
|
||||
logic [31:0] alu_result;
|
||||
logic [31:0] alu_jump_target_int;
|
||||
|
||||
logic [31:0] alu_adder_lsu_int; // to LS unit
|
||||
|
||||
|
@ -183,17 +184,17 @@ module ex_stage
|
|||
// NOTE a dedicated adder, no carry is considered , just op_a + op_b from id stage
|
||||
`ifdef TCDM_ADDR_PRECAL
|
||||
assign alu_adder_lsu_int = alu_adder_i;
|
||||
$stop("TCDM_ADDR_PRECAL unsupported in RiscV! (jump/branch target calculation not implemented yet");
|
||||
`else
|
||||
assign alu_adder_lsu_int = alu_operand_a_i + alu_operand_b_i;
|
||||
`endif
|
||||
assign data_addr_ex_o = (prepost_useincr_i == 1'b1) ? alu_adder_lsu_int : alu_operand_a_i;
|
||||
|
||||
|
||||
// PC calculation for JAL/JALR
|
||||
assign jump_target_o = alu_jump_target_int;
|
||||
|
||||
// Branch is taken when result == 1'b1
|
||||
assign branch_taken_o = alu_result[0];
|
||||
assign branch_decision_o = alu_result[0];
|
||||
assign jump_target_o = alu_operand_c_i;
|
||||
|
||||
|
||||
////////////////////////////
|
||||
|
@ -218,7 +219,6 @@ module ex_stage
|
|||
.vec_ext_i ( alu_vec_ext_i ),
|
||||
|
||||
.result_o ( alu_result ),
|
||||
.jump_target_o ( alu_jump_target_int ),
|
||||
.overflow_o ( alu_overflow_int ), // Internal signal
|
||||
.carry_o ( alu_carry_int ), // Internal signal
|
||||
.flag_o ( alu_flag_o )
|
||||
|
@ -269,6 +269,7 @@ module ex_stage
|
|||
regfile_rb_data_wb_o <= 32'h0000_0000;
|
||||
sp_we_wb_o <= 1'b0;
|
||||
eoc_o <= 1'b0;
|
||||
jump_in_ex_o <= '0;
|
||||
end
|
||||
else
|
||||
begin
|
||||
|
@ -281,6 +282,7 @@ module ex_stage
|
|||
regfile_rb_data_wb_o <= regfile_rb_data_i;
|
||||
sp_we_wb_o <= sp_we_i;
|
||||
eoc_o <= eoc_i;
|
||||
jump_in_ex_o <= jump_in_id_i;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
85
id_stage.sv
85
id_stage.sv
|
@ -41,16 +41,18 @@ module id_stage
|
|||
input logic fetch_enable_i,
|
||||
output logic core_busy_o,
|
||||
|
||||
input logic branch_taken_i,
|
||||
|
||||
// Interface to instruction memory
|
||||
input logic [31:0] instr_rdata_i, // comes from pipeline of IF stage
|
||||
output logic instr_req_o,
|
||||
input logic instr_gnt_i,
|
||||
input logic instr_ack_i,
|
||||
|
||||
// Jumps and branches
|
||||
output logic [1:0] jump_in_id_o,
|
||||
input logic [1:0] jump_in_ex_i,
|
||||
|
||||
// IF and ID stage signals
|
||||
output logic [31:0] pc_from_immediate_o,
|
||||
//output logic [31:0] pc_from_immediate_o, // TODO: remove
|
||||
|
||||
output logic [2:0] pc_mux_sel_o,
|
||||
output logic pc_mux_boot_o,
|
||||
|
@ -61,12 +63,6 @@ module id_stage
|
|||
input logic [31:0] current_pc_if_i,
|
||||
input logic [31:0] current_pc_id_i,
|
||||
|
||||
// branch prediction
|
||||
output logic drop_instruction_o,
|
||||
`ifdef BRANCH_PREDICTION
|
||||
output logic wrong_branch_taken_o,
|
||||
output logic take_branch_o,
|
||||
`endif
|
||||
// STALLS
|
||||
output logic stall_if_o,
|
||||
output logic stall_id_o,
|
||||
|
@ -189,15 +185,19 @@ module id_stage
|
|||
|
||||
logic [31:0] current_pc; // PC to be used in ALU (either IF or ID)
|
||||
|
||||
logic [31:0] jump_target; // calculated jump target (-> EX -> IF)
|
||||
|
||||
logic exc_pc_sel;
|
||||
logic [2:0] pc_mux_sel_int; // selects next PC in if stage
|
||||
//logic pc_from_immediate_mux_sel = 1'b0; // TODO: FIXME (remove)
|
||||
|
||||
logic force_nop_controller;
|
||||
|
||||
logic irq_present;
|
||||
|
||||
// Signals running between controller and exception controller
|
||||
logic jump_in_id;
|
||||
logic jump_in_ex; // registered copy of jump_in_id
|
||||
//logic jump_in_id;
|
||||
//logic jump_in_ex; // registered copy of jump_in_id
|
||||
logic illegal_insn;
|
||||
logic trap_insn;
|
||||
logic pipe_flush;
|
||||
|
@ -308,7 +308,6 @@ module id_stage
|
|||
assign regfile_addr_ra_id = instr_rdata_i[`REG_S1];
|
||||
assign regfile_addr_rb_id = instr_rdata_i[`REG_S2];
|
||||
//assign regfile_addr_rc_id = instr_rdata_i[25:21];
|
||||
assign regfile_addr_rc_id = 32'd0;
|
||||
|
||||
// destination registers
|
||||
assign regfile_waddr_id = instr_rdata_i[`REG_D];
|
||||
|
@ -346,7 +345,7 @@ module id_stage
|
|||
// 1'b1: pc_from_immediate_o = imm_i_type; // JALR
|
||||
// endcase // case (pc_from_immediate_mux_sel)
|
||||
//end
|
||||
assign pc_from_immediate_o = imm_sb_type; // TODO: Remove/Replace?
|
||||
//assign pc_from_immediate_o = imm_sb_type; // TODO: Remove/Replace?
|
||||
|
||||
// PC Mux
|
||||
always_comb
|
||||
|
@ -384,6 +383,26 @@ module id_stage
|
|||
*/
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////
|
||||
// _ _____ _ //
|
||||
// | |_ _ _ __ ___ _ __ |_ _|_ _ _ __ __ _ ___| |_ //
|
||||
// _ | | | | | '_ ` _ \| '_ \ | |/ _` | '__/ _` |/ _ \ __| //
|
||||
// | |_| | |_| | | | | | | |_) | | | (_| | | | (_| | __/ |_ //
|
||||
// \___/ \__,_|_| |_| |_| .__/ |_|\__,_|_| \__, |\___|\__| //
|
||||
// |_| |___/ //
|
||||
//////////////////////////////////////////////////////////////////
|
||||
|
||||
always_comb
|
||||
begin
|
||||
unique case (instr_rdata_i[6:0])
|
||||
`OPCODE_JAL: jump_target = current_pc_id_i + imm_uj_type;
|
||||
`OPCODE_JALR: jump_target = operand_a_fw_id + imm_i_type;
|
||||
`OPCODE_BRANCH: jump_target = current_pc_id_i + imm_sb_type;
|
||||
default: jump_target = '0;
|
||||
endcase // unique case (instr_rdata_i[6:0])
|
||||
end
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////
|
||||
// ___ _ _ //
|
||||
// / _ \ _ __ ___ _ __ __ _ _ __ __| | / \ //
|
||||
|
@ -429,13 +448,12 @@ module id_stage
|
|||
always_comb
|
||||
begin : immediate_mux
|
||||
case (immediate_mux_sel)
|
||||
default: immediate_b = 32'h4;
|
||||
//`IMM_VEC: immediate_b = immediate_vec_id;
|
||||
`IMM_I: immediate_b = imm_i_type;
|
||||
`IMM_S: immediate_b = imm_s_type;
|
||||
//`IMM_SB: immediate_b = imm_sb_type;
|
||||
`IMM_U: immediate_b = imm_u_type;
|
||||
`IMM_UJ: immediate_b = imm_uj_type;
|
||||
`IMM_I: immediate_b = imm_i_type;
|
||||
`IMM_S: immediate_b = imm_s_type;
|
||||
`IMM_U: immediate_b = imm_u_type;
|
||||
`IMM_HEX4: immediate_b = 32'h4;
|
||||
default: immediate_b = 32'h4;
|
||||
endcase; // case (immediate_mux_sel)
|
||||
end
|
||||
|
||||
|
@ -482,8 +500,9 @@ module id_stage
|
|||
always_comb
|
||||
begin : alu_operand_c_mux
|
||||
case (alu_op_c_mux_sel)
|
||||
`OP_C_CURRPC: operand_c = current_pc;
|
||||
default: operand_c = regfile_data_rc_id;
|
||||
`OP_C_JT: operand_c = jump_target;
|
||||
//`OP_C_CURRPC: operand_c = current_pc;
|
||||
default: operand_c = regfile_data_rc_id;
|
||||
endcase // case (alu_op_c_mux_sel)
|
||||
end
|
||||
|
||||
|
@ -553,7 +572,7 @@ module id_stage
|
|||
.eoc_o ( eoc ),
|
||||
.core_busy_o ( core_busy_o ),
|
||||
|
||||
.branch_taken_i ( branch_taken_i ),
|
||||
.force_nop_o ( force_nop_controller ),
|
||||
|
||||
// Signal from-to PC pipe (instr rdata) and instr mem system (req and ack)
|
||||
.instr_rdata_i ( instr_rdata_i ),
|
||||
|
@ -620,7 +639,7 @@ module id_stage
|
|||
.irq_present_i ( irq_present ),
|
||||
|
||||
// Exception Controller Signals
|
||||
.jump_in_id_o ( jump_in_id ),
|
||||
//.jump_in_id_o ( jump_in_id ),
|
||||
.illegal_insn_o ( illegal_insn ),
|
||||
.trap_insn_o ( trap_insn ),
|
||||
.pipe_flush_o ( pipe_flush ),
|
||||
|
@ -656,14 +675,12 @@ module id_stage
|
|||
.operand_b_fw_mux_sel_o ( operand_b_fw_mux_sel ),
|
||||
.operand_c_fw_mux_sel_o ( operand_c_fw_mux_sel ),
|
||||
|
||||
.jump_in_ex_i ( jump_in_ex ),
|
||||
// To controller (TODO: Remove when control/decode separated and moved)
|
||||
.jump_in_ex_i ( jump_in_ex_i ),
|
||||
|
||||
// To EX: Jump/Branch indication
|
||||
.jump_in_id_o ( jump_in_id_o ),
|
||||
|
||||
// branch prediction
|
||||
.drop_instruction_o ( drop_instruction_o ),
|
||||
`ifdef BRANCH_PREDICTION
|
||||
.wrong_branch_taken_o ( wrong_branch_taken_o ),
|
||||
.take_branch_o ( take_branch_o ),
|
||||
`endif
|
||||
// Stall signals
|
||||
.stall_if_o ( stall_if_o ),
|
||||
.stall_id_o ( stall_id_o ),
|
||||
|
@ -680,7 +697,8 @@ module id_stage
|
|||
// //
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
|
||||
assign force_nop_o = 1'b0;
|
||||
assign force_nop_o = force_nop_controller;
|
||||
|
||||
/*
|
||||
exc_controller exc_controller_i
|
||||
(
|
||||
|
@ -823,8 +841,6 @@ module id_stage
|
|||
hwloop_wb_mux_sel_ex_o <= 1'b0;
|
||||
hwloop_cnt_o <= 32'b0;
|
||||
|
||||
jump_in_ex <= 1'b0;
|
||||
|
||||
eoc_ex_o <= 1'b0;
|
||||
|
||||
`ifdef TCDM_ADDR_PRECAL
|
||||
|
@ -898,14 +914,11 @@ module id_stage
|
|||
hwloop_wb_mux_sel_ex_o <= hwloop_wb_mux_sel;
|
||||
hwloop_cnt_o <= hwloop_cnt;
|
||||
|
||||
jump_in_ex <= jump_in_id;
|
||||
|
||||
eoc_ex_o <= eoc;
|
||||
|
||||
`ifdef TCDM_ADDR_PRECAL
|
||||
alu_adder_o <= alu_operand_a + alu_operand_b;
|
||||
`endif
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
|
|
126
if_stage.sv
126
if_stage.sv
|
@ -40,42 +40,39 @@ module if_stage
|
|||
input logic [31:0] boot_addr_i,
|
||||
|
||||
// Output of IF Pipeline stage
|
||||
output logic [31:0] instr_rdata_id_o, // read instruction is sampled and sent to ID stage for decoding
|
||||
output logic [31:0] current_pc_if_o, // current pc program counter
|
||||
output logic [31:0] current_pc_id_o, // current pc program counter
|
||||
output logic [31:0] instr_rdata_id_o, // read instruction is sampled and sent to ID stage for decoding
|
||||
output logic [31:0] current_pc_if_o, // "current" pc program counter
|
||||
output logic [31:0] current_pc_id_o, // current pc program counter
|
||||
|
||||
// From to Instr memory
|
||||
input logic [31:0] instr_rdata_i, // Instruction read from instruction memory /cache
|
||||
output logic [31:0] instr_addr_o, // address for instruction fetch
|
||||
input logic [31:0] instr_rdata_i, // Instruction read from instruction memory /cache
|
||||
output logic [31:0] instr_addr_o, // address for instruction fetch
|
||||
|
||||
// Forwarding ports - control signals
|
||||
input logic force_nop_i, // insert a NOP in the pipe
|
||||
input logic [31:0] exception_pc_reg_i, // address used to restore the program counter when the interrupt/exception is served
|
||||
input logic [31:0] pc_from_regfile_i, // pc from reg file
|
||||
input logic [31:0] pc_from_alu_i, // calculated jump target form ALU
|
||||
input logic [31:0] pc_from_immediate_i, // pc from immediate
|
||||
input logic [31:0] pc_from_hwloop_i, // pc from hwloop start addr
|
||||
input logic [2:0] pc_mux_sel_i, // sel for pc multiplexer
|
||||
input logic pc_mux_boot_i, // load boot address as PC
|
||||
input logic [1:0] exc_pc_mux_i, // select which exception to execute
|
||||
input logic force_nop_i, // insert a NOP in the pipe
|
||||
input logic [31:0] exception_pc_reg_i, // address used to restore the program counter when the interrupt/exception is served
|
||||
input logic [31:0] pc_from_regfile_i, // pc from reg file
|
||||
//input logic [31:0] pc_from_immediate_i, // pc from immediate
|
||||
input logic [31:0] pc_from_hwloop_i, // pc from hwloop start addr
|
||||
input logic [2:0] pc_mux_sel_i, // sel for pc multiplexer
|
||||
input logic pc_mux_boot_i, // load boot address as PC
|
||||
input logic [1:0] exc_pc_mux_i, // select which exception to execute
|
||||
|
||||
// jump and branch target and decision
|
||||
input logic [31:0] jump_target_i, // jump target
|
||||
input logic [1:0] jump_in_ex_i, // jump in EX -> get PC from jump target (could also be branch)
|
||||
input logic branch_decision_i,
|
||||
|
||||
// from debug unit
|
||||
input logic [31:0] dbg_pc_from_npc,
|
||||
input logic dbg_set_npc,
|
||||
|
||||
// branch prediction
|
||||
input logic drop_instruction_i,
|
||||
`ifdef BRANCH_PREDICTION
|
||||
input logic wrong_branch_taken_i,
|
||||
input logic take_branch_i,
|
||||
`endif
|
||||
// pipeline stall
|
||||
input logic stall_if_i,
|
||||
input logic stall_id_i // Stall in the id stage: here (if_stage) freeze the registers
|
||||
);
|
||||
|
||||
|
||||
|
||||
////////////////////////////////////
|
||||
// Instruction Fetch (IF) signals //
|
||||
////////////////////////////////////
|
||||
|
@ -83,29 +80,18 @@ module if_stage
|
|||
logic [31:0] exc_pc; // Exception PC
|
||||
logic [31:0] instr_rdata_int; // The instruction read from instr memory/cache is forwarded to ID stage, and the controller can force this forwarding to a nop (BUBBLE)
|
||||
|
||||
`ifdef BRANCH_PREDICTION
|
||||
logic [31:0] correct_branch;
|
||||
`endif
|
||||
|
||||
logic [31:0] branch_taken;
|
||||
logic [31:0] branch_not_taken;
|
||||
|
||||
|
||||
// Address to fetch the instruction
|
||||
assign instr_addr_o = next_pc;
|
||||
|
||||
assign branch_taken = current_pc_id_o + pc_from_immediate_i;
|
||||
//assign branch_not_taken = current_pc_if_o + 32'd4;
|
||||
|
||||
// Next PC Selection: pc_mux_sel_i comes from id_stage.controller
|
||||
always_comb
|
||||
/*always_comb
|
||||
begin : PC_MUX
|
||||
case (pc_mux_sel_i)
|
||||
`INCR_PC: begin next_pc = current_pc_if_o + 32'd4; end // PC is incremented and points the next instruction
|
||||
`NO_INCR: begin next_pc = current_pc_if_o; end // PC is not incremented
|
||||
//`PC_FROM_REGFILE: begin next_pc = pc_from_regfile_i; end // PC is taken from the regfile
|
||||
`PC_FROM_ALU: begin next_pc = pc_from_alu_i; end // use calculated jump target from ALU
|
||||
`PC_FROM_IMM: begin next_pc = branch_taken; end // PC is taken from current PC in id + the immediate displacement
|
||||
//`PC_FROM_ALU: begin next_pc = pc_from_alu_i; end // use calculated jump target from ALU
|
||||
`PC_EXCEPTION: begin next_pc = exc_pc; end // PC that points to the exception
|
||||
`EXC_PC_REG: begin next_pc = exception_pc_reg_i; end // restore the PC when exiting from interr/ecpetions
|
||||
`HWLOOP_ADDR: begin next_pc = pc_from_hwloop_i; end // PC is taken from hwloop start addr
|
||||
|
@ -114,8 +100,7 @@ module if_stage
|
|||
`endif
|
||||
default: begin next_pc = current_pc_if_o + 32'd4; end
|
||||
endcase //~case (pc_mux_sel_i)
|
||||
end
|
||||
|
||||
end */
|
||||
|
||||
// Exception PC selection
|
||||
always_comb
|
||||
|
@ -128,8 +113,45 @@ module if_stage
|
|||
endcase //~case (exc_pc_mux_i)
|
||||
end
|
||||
|
||||
// NOP = addi x0, x0, 0
|
||||
assign instr_rdata_int = (force_nop_i == 1'b1) ? { {25 {1'b0}}, `OPCODE_OPIMM } : instr_rdata_i;
|
||||
|
||||
// PC selection and force NOP logic
|
||||
always_comb
|
||||
begin
|
||||
next_pc = current_pc_if_o;
|
||||
instr_rdata_int = instr_rdata_i;
|
||||
|
||||
unique case (pc_mux_sel_i)
|
||||
`PC_INCR: next_pc = current_pc_if_o + 32'd4; // PC is incremented and points the next instruction
|
||||
`PC_NO_INCR: next_pc = current_pc_if_o; // PC is not incremented
|
||||
`PC_EXCEPTION: next_pc = exc_pc; // PC that points to the exception
|
||||
`EXC_PC_REG: next_pc = exception_pc_reg_i; // restore the PC when exiting from interr/ecpetions
|
||||
`HWLOOP_ADDR: next_pc = pc_from_hwloop_i; // PC is taken from hwloop start addr
|
||||
default:
|
||||
begin
|
||||
next_pc = current_pc_if_o;
|
||||
// synopsis translate off
|
||||
$display("%t: Illegal pc_mux_sel value (%0d)!", $time, pc_mux_sel_i);
|
||||
// synopsis translate on
|
||||
end
|
||||
endcase // unique case (pc_mux_sel_i)
|
||||
|
||||
// if force NOP, do not increase PC
|
||||
if (force_nop_i == 1'b1) begin
|
||||
instr_rdata_int = { 25'b0, `OPCODE_OPIMM }; // addi x0 = x0 + 0
|
||||
next_pc = current_pc_if_o;
|
||||
end
|
||||
|
||||
if (jump_in_ex_i == 2'b01) begin
|
||||
next_pc = jump_target_i;
|
||||
end else if (jump_in_ex_i == 2'b10) begin
|
||||
if (branch_decision_i == 1'b1)
|
||||
next_pc = jump_target_i;
|
||||
else
|
||||
next_pc = current_pc_if_o;// + 32'd4; // TODO: Check if merged with previous adder (from PC mux)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// IF PC register //
|
||||
|
@ -159,24 +181,6 @@ module if_stage
|
|||
end
|
||||
end
|
||||
|
||||
`ifdef BRANCH_PREDICTION
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Save branch targets in case of a misprediction //
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
always_ff @(posedge clk, negedge rst_n)
|
||||
begin : SAVE_BRANCH_TARGET
|
||||
if (rst_n == 1'b0)
|
||||
begin : ASSERT_RESET
|
||||
correct_branch <= 32'b0;
|
||||
end
|
||||
else
|
||||
begin : DEASSERT_RESET
|
||||
if (wrong_branch_taken_i)
|
||||
correct_branch <= (take_branch_i) ? branch_taken : branch_not_taken;
|
||||
end
|
||||
end
|
||||
`endif
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// IF-ID PIPE: Pipeline that is frozen when the ID stage is stalled //
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -184,15 +188,15 @@ module if_stage
|
|||
begin : IF_ID_PIPE_REGISTERS
|
||||
if (rst_n == 1'b0)
|
||||
begin : ASSERT_RESET
|
||||
instr_rdata_id_o <= '0;
|
||||
current_pc_id_o <= '0;
|
||||
instr_rdata_id_o <= '0;
|
||||
current_pc_id_o <= '0;
|
||||
end
|
||||
else
|
||||
begin : DEASSERT_RESET
|
||||
if((stall_id_i == 1'b0) & (drop_instruction_i == 1'b0))
|
||||
if (stall_id_i == 1'b0)
|
||||
begin : ENABLED_PIPE
|
||||
instr_rdata_id_o <= instr_rdata_int;
|
||||
current_pc_id_o <= current_pc_if_o;
|
||||
instr_rdata_id_o <= instr_rdata_int;
|
||||
current_pc_id_o <= current_pc_if_o;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -170,6 +170,8 @@
|
|||
|
||||
|
||||
// synopsis translate off
|
||||
`define TRACE_EXECUTION
|
||||
|
||||
function void prettyPrintInstruction(input [31:0] instr, input [31:0] pc);
|
||||
string opcode;
|
||||
begin
|
||||
|
@ -268,9 +270,6 @@ endfunction // prettyPrintInstruction
|
|||
`define ALU_FL1 6'b11_0011
|
||||
`define ALU_CLB 6'b11_0001
|
||||
|
||||
// next PC and PC+4 computation for JAL/JALR in RiscV
|
||||
`define ALU_JAL 6'b11_1000
|
||||
|
||||
|
||||
// Vector Mode
|
||||
`define VEC_MODE32 2'b00
|
||||
|
@ -341,32 +340,22 @@ endfunction // prettyPrintInstruction
|
|||
|
||||
// operand c selection
|
||||
`define OP_C_REGC_OR_FWD 1'b0
|
||||
`define OP_C_CURRPC 1'b1
|
||||
`define OP_C_JT 1'b1
|
||||
|
||||
// immediate selection
|
||||
// - `define IMM_5N11 4'b0000
|
||||
// - `define IMM_21S 4'b0001
|
||||
// - `define IMM_8Z 4'b0010
|
||||
// - `define IMM_16Z 4'b0011
|
||||
// - `define IMM_16 4'b0100
|
||||
// - `define IMM_11S 4'b0101
|
||||
// - `define IMM_5N6S 4'b0110
|
||||
// - `define IMM_VEC 4'b0111
|
||||
// - `define IMM_HEX4 4'b1000
|
||||
`define IMM_I 3'b000
|
||||
`define IMM_S 3'b010
|
||||
// operand b immediate selection
|
||||
`define IMM_I 2'b00
|
||||
`define IMM_S 2'b01
|
||||
`define IMM_U 2'b10
|
||||
`define IMM_HEX4 2'b11
|
||||
/* not used:
|
||||
`define IMM_SB 3'b011
|
||||
`define IMM_U 3'b100
|
||||
`define IMM_UJ 3'b101
|
||||
`define IMM_C4 3'b110
|
||||
*/
|
||||
|
||||
// PC mux selector defines
|
||||
`define INCR_PC 3'b000
|
||||
`define NO_INCR 3'b001
|
||||
//`define PC_FROM_REGFILE 3'b010 Removed in RiscV
|
||||
`define PC_FROM_IMM 3'b010
|
||||
//`define PC_FROM_IMM 3'b011 Replaced in RiscV
|
||||
`define PC_FROM_ALU 3'b011
|
||||
`define PC_INCR 3'b000
|
||||
`define PC_NO_INCR 3'b001
|
||||
`define PC_EXCEPTION 3'b100
|
||||
`define EXC_PC_REG 3'b101
|
||||
`define HWLOOP_ADDR 3'b110
|
||||
|
@ -409,4 +398,4 @@ endfunction // prettyPrintInstruction
|
|||
// TCDM_ADDRES PRE CALCULATION --> Bring part of the alu_adder_o calculation in the ID stage
|
||||
//`define TCDM_ADDR_PRECAL
|
||||
|
||||
//`define BRANCH_PREDICTION
|
||||
//`define BRANCH_PREDICTION
|
|
@ -93,8 +93,8 @@ module riscv_core
|
|||
|
||||
// Jump and branch target and decision (EX->IF)
|
||||
logic [31:0] jump_target;
|
||||
logic jump_in_ex;
|
||||
logic branch_in_ex;
|
||||
logic [1:0] jump_in_id;
|
||||
logic [1:0] jump_in_ex;
|
||||
logic branch_decision;
|
||||
|
||||
|
||||
|
@ -289,6 +289,11 @@ module riscv_core
|
|||
.dbg_pc_from_npc ( dbg_npc ),
|
||||
.dbg_set_npc ( dbg_set_npc ),
|
||||
|
||||
// Jump and branch target and decision
|
||||
.jump_in_ex_i ( jump_in_ex ),
|
||||
.branch_decision_i ( branch_decision ),
|
||||
.jump_target_i ( jump_target ),
|
||||
|
||||
// pipeline stalls
|
||||
.stall_if_i ( stall_if ),
|
||||
.stall_id_i ( stall_id )
|
||||
|
@ -341,6 +346,9 @@ module riscv_core
|
|||
// Processor Enable
|
||||
.fetch_enable_i ( fetch_enable_i ),
|
||||
|
||||
.jump_in_id_o ( jump_in_id ),
|
||||
.jump_in_ex_i ( jump_in_ex ),
|
||||
|
||||
.core_busy_o ( core_busy_o ),
|
||||
|
||||
// Interface to instruction memory
|
||||
|
@ -357,7 +365,7 @@ module riscv_core
|
|||
.pc_from_regfile_o ( pc_from_regfile_id ),
|
||||
.current_pc_if_i ( current_pc_if ),
|
||||
.current_pc_id_i ( current_pc_id ),
|
||||
//.pc_from_immediate_o ( pc_from_immediate_id ),
|
||||
//.pc_from_immediate_o ( pc_from_immediate_id ), //TODO
|
||||
|
||||
.sr_flag_fw_i ( sr_flag_fw ),
|
||||
.sr_flag_i ( sr_flag ),
|
||||
|
@ -535,7 +543,6 @@ module riscv_core
|
|||
.regfile_rb_data_i ( regfile_rb_data_ex ),
|
||||
.sp_we_i ( sp_we_ex ),
|
||||
|
||||
|
||||
// Output of ex stage pipeline
|
||||
.regfile_wdata_wb_o ( result_wb ),
|
||||
.regfile_waddr_wb_o ( regfile_waddr_fw_wb_o ),
|
||||
|
@ -553,10 +560,12 @@ module riscv_core
|
|||
.sp_we_wb_o ( sp_we_wb ),
|
||||
.eoc_o ( eoc_wb ),
|
||||
|
||||
// From ID: Jump and Branch detection
|
||||
.jump_in_id_i ( jump_in_id ),
|
||||
|
||||
// To IF: Jump and branch target and decision
|
||||
.jump_target_o ( jump_target ),
|
||||
.jump_in_ex_o ( jump_in_ex ),
|
||||
.branch_in_ex_o ( branch_in_ex ),
|
||||
.branch_decision_o ( branch_decision ),
|
||||
|
||||
// To ID stage: Forwarding signals
|
||||
|
@ -812,7 +821,7 @@ module riscv_core
|
|||
instr = id_stage_i.instr_rdata_i[31:0];
|
||||
pc = id_stage_i.current_pc_id_i;
|
||||
|
||||
if (fetch_enable_i == 1'b1 && id_stage_i.stall_id_o == 1'b0)
|
||||
if (fetch_enable_i == 1'b1 && id_stage_i.stall_id_o == 1'b0 && id_stage_i.controller_i.ctrl_fsm_cs == id_stage_i.controller_i.DECODE)
|
||||
begin
|
||||
//$display("%h", instr);
|
||||
$fwrite(f, "%t:\t0x%h\t0x%h\t", $time, pc, instr);
|
||||
|
@ -883,7 +892,7 @@ module riscv_core
|
|||
|
||||
function void printRInstr(input string mnemonic);
|
||||
begin
|
||||
$fdisplay(f, "%s x%0d, x%d (0x%h), x%0d (0x%h)", mnemonic, instr[`REG_D],
|
||||
$fdisplay(f, "%s\tx%0d, x%d (0x%h), x%0d (0x%h)", mnemonic, instr[`REG_D],
|
||||
instr[`REG_S1], r[instr[`REG_S1]], instr[`REG_S2], r[instr[`REG_S2]]);
|
||||
end
|
||||
endfunction // printRInstr
|
||||
|
@ -892,7 +901,7 @@ module riscv_core
|
|||
logic [31:0] i_imm;
|
||||
begin
|
||||
i_imm = { {20 {instr[31]}}, instr[31:20] };
|
||||
$fdisplay(f, "%s x%0d, x%0d (0x%h), 0x%0d (imm)", mnemonic, instr[`REG_D],
|
||||
$fdisplay(f, "%s\tx%0d, x%0d (0x%h), 0x%0d (imm)", mnemonic, instr[`REG_D],
|
||||
instr[`REG_S1], r[instr[`REG_S1]], i_imm);
|
||||
end
|
||||
endfunction // printIInstr
|
||||
|
@ -901,7 +910,7 @@ module riscv_core
|
|||
logic [31:0] s_imm;
|
||||
begin
|
||||
s_imm = { {20 {instr[31]}}, instr[31:25], instr[11:7] };
|
||||
$fdisplay(f, "%s x%0d (0x%h), x%0d (0x%h), 0x%h (imm)", mnemonic,
|
||||
$fdisplay(f, "%s\tx%0d (0x%h), x%0d (0x%h), 0x%h (imm)", mnemonic,
|
||||
instr[`REG_S1], r[instr[`REG_S1]], instr[`REG_S2], r[instr[`REG_S2]],
|
||||
s_imm);
|
||||
end
|
||||
|
@ -911,7 +920,7 @@ module riscv_core
|
|||
logic [31:0] sb_imm;
|
||||
begin
|
||||
sb_imm = { {20 {instr[31]}}, instr[31], instr[7], instr[30:25], instr[11:8] };
|
||||
$fdisplay(f, "%s x%0d (0x%h), x%0d (0x%h), 0x%h (imm)", mnemonic,
|
||||
$fdisplay(f, "%s\tx%0d (0x%h), x%0d (0x%h), 0x%h (imm)", mnemonic,
|
||||
instr[`REG_S1], r[instr[`REG_S1]], instr[`REG_S2], r[instr[`REG_S2]],
|
||||
sb_imm);
|
||||
end
|
||||
|
@ -921,13 +930,13 @@ module riscv_core
|
|||
logic [31:0] uj_imm;
|
||||
begin
|
||||
uj_imm = { {20 {instr[31]}}, instr[19:12], instr[20], instr[30:21], 1'b0 };
|
||||
$fdisplay(f, "%s x%0d, 0x%h", mnemonic, instr[`REG_D], uj_imm);
|
||||
$fdisplay(f, "%s\tx%0d, 0x%h", mnemonic, instr[`REG_D], uj_imm);
|
||||
end
|
||||
endfunction // printUJInstr
|
||||
|
||||
function void printRDInstr(input string mnemonic);
|
||||
begin
|
||||
$fdisplay(f, "%s x%0d", mnemonic, instr[`REG_D]);
|
||||
$fdisplay(f, "%s\tx%0d", mnemonic, instr[`REG_D]);
|
||||
end
|
||||
endfunction // printRDInstr
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue