diff --git a/controller.sv b/controller.sv index b3186ae0..08cc3d84 100644 --- a/controller.sv +++ b/controller.sv @@ -46,6 +46,7 @@ module controller input logic instr_ack_i, // Acknow from instr memory or cache (means that data is available) output logic [2:0] pc_mux_sel_o, // Selector in the Fetch stage to select the rigth PC (normal, jump ...) + output logic pc_set_o, // jump to address set by pc_mux_sel // ALU signals output logic [`ALU_OP_WIDTH-1:0] alu_operator_o, // Operator in the Ex stage for the ALU block @@ -99,6 +100,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 + input logic exc_pc_sel_i, // exception execution requested input logic illegal_c_insn_i, // compressed instruction decode failed output logic illegal_insn_o, // illegal instruction encountered output logic trap_insn_o, // trap instruction encountered @@ -142,7 +144,7 @@ module controller ); // FSM state encoding - enum logic [3:0] { RESET, BOOT_SET, SLEEP, FIRST_FETCH, DECODE, BRANCH, BRANCH_DELAY, + enum logic [3:0] { RESET, BOOT_SET, SLEEP, FIRST_FETCH, DECODE, BRANCH, FLUSH_EX, FLUSH_WB, DBG_FLUSH_EX, DBG_FLUSH_WB, DBG_SIGNAL, DBG_WAIT } ctrl_fsm_cs, ctrl_fsm_ns; @@ -166,6 +168,7 @@ module controller logic pipe_flush; logic trap_insn; + logic eret_insn; logic [1:0] jump_in_id; @@ -243,6 +246,7 @@ module controller illegal_insn_int = 1'b0; trap_insn = 1'b0; + eret_insn = 1'b0; pipe_flush = 1'b0; rega_used = 1'b0; @@ -789,8 +793,7 @@ module controller 32'h10_00_00_73: // ERET begin - // TODO: Handle in controller - //pc_mux_sel = `PC_ERET; + eret_insn = 1'b1; clear_isr_running_o = 1'b1; end @@ -960,6 +963,7 @@ module controller instr_req_o = 1'b1; pc_mux_sel_o = `PC_BOOT; + pc_set_o = 1'b0; ctrl_fsm_ns = ctrl_fsm_cs; @@ -987,6 +991,7 @@ module controller begin instr_req_o = 1'b1; pc_mux_sel_o = `PC_BOOT; + pc_set_o = 1'b1; ctrl_fsm_ns = FIRST_FETCH; end @@ -1015,8 +1020,10 @@ module controller // hwloop detected, jump to start address! // Attention: This has to be done in the DECODE and the FIRST_FETCH states - if (hwloop_jump_i == 1'b1) + if (hwloop_jump_i == 1'b1) begin pc_mux_sel_o = `PC_HWLOOP; + pc_set_o = 1'b1; + end end DECODE: @@ -1035,8 +1042,9 @@ module controller if (jump_in_id == `BRANCH_JALR || jump_in_id == `BRANCH_JAL) begin pc_mux_sel_o = `PC_JUMP; - if (~stall_id_o) - ctrl_fsm_ns = DECODE; + // we don't have to change our current state here as the prefetch + // buffer is automatically invalidated, thus the next instruction + // that is served to the ID stage is the one of the jump target end // handle hwloops @@ -1049,6 +1057,21 @@ module controller illegal_insn_o = 1'b1; end + if (exc_pc_sel_i) begin + pc_mux_sel_o = `PC_EXCEPTION; + pc_set_o = 1'b1; + + // we don't have to change our current state here as the prefetch + // buffer is automatically invalidated, thus the next instruction + // that is served to the ID stage is the one of the jump to the + // exception handler + end + + if (eret_insn) begin + pc_mux_sel_o = `PC_ERET; + pc_set_o = 1'b1; + end + // handle WFI instruction, flush pipeline and (potentially) go to // sleep if (pipe_flush || exc_pipe_flush_i) @@ -1107,25 +1130,6 @@ module controller end end - // "delay slot" of jump and branch - // inserts a nop by not decoding the instruction - BRANCH_DELAY: - begin - // if we want to debug, flush the pipeline - // the current_pc_if will take the value of the next instruction to - // be executed (NPC) - if (trap_hit_i) - begin - halt_if = 1'b1; - halt_id = 1'b1; - - ctrl_fsm_ns = DBG_FLUSH_EX; - end else begin - if (~stall_id_o) - ctrl_fsm_ns = DECODE; - end - end - DBG_FLUSH_EX: begin halt_if = 1'b1; @@ -1161,6 +1165,7 @@ module controller if(dbg_set_npc_i == 1'b1) begin halt_id = 1'b0; pc_mux_sel_o = `PC_DBG_NPC; + pc_set_o = 1'b1; ctrl_fsm_ns = DBG_WAIT; end diff --git a/exc_controller.sv b/exc_controller.sv index ac7dbc6f..b4e5136a 100644 --- a/exc_controller.sv +++ b/exc_controller.sv @@ -34,7 +34,6 @@ module exc_controller // to IF stage output logic exc_pc_sel_o, // influences next PC, if set exception PC is used output logic [1:0] exc_pc_mux_o, // Selector in the Fetch stage to select the rigth exception PC - output logic force_nop_o, // Force a Nop (Bubble) in the Fetch stage // hwloop signals output logic hwloop_enable_o, // '1' if pc is valid (interrupt related signal) @@ -78,7 +77,7 @@ module exc_controller logic clear_exc_reason; // disable hardware loops when nops are inserted or the controller is not active - assign hwloop_enable_o = (~force_nop_o) | (~core_busy_i); + assign hwloop_enable_o = (~core_busy_i); ///////////////////////////////////////////// // ____ _ // @@ -162,7 +161,6 @@ module exc_controller clear_exc_reason = 1'b0; save_pc_if_o = 1'b0; save_pc_id_o = 1'b0; - force_nop_o = 1'b0; pc_valid_o = 1'b1; exc_pc_sel_o = 1'b0; exc_pc_mux_o = `EXC_PC_NO_INCR; @@ -179,7 +177,6 @@ module exc_controller ExcIR: begin if (jump_in_id_i == 2'b00) begin // no delay slot - force_nop_o = 1'b1; exc_pc_sel_o = 1'b1; save_pc_if_o = 1'b1; // save current PC @@ -201,7 +198,6 @@ module exc_controller // Illegal instruction encountered, we directly jump to // the ISR without flushing the pipeline ExcIllegalInsn: begin - force_nop_o = 1'b1; exc_pc_sel_o = 1'b1; exc_pc_mux_o = `EXC_PC_ILLINSN; save_pc_id_o = 1'b1; // save current PC @@ -217,7 +213,6 @@ module exc_controller // Execute delay slot for IR NopDelayIR: begin - force_nop_o = 1'b1; exc_pc_sel_o = 1'b1; save_pc_if_o = 1'b1; // save current PC diff --git a/id_stage.sv b/id_stage.sv index 37c7c25b..84cc2a46 100644 --- a/id_stage.sv +++ b/id_stage.sv @@ -55,9 +55,9 @@ module id_stage output logic [31:0] jump_target_o, // IF and ID stage signals + output logic pc_set_o, output logic [2:0] pc_mux_sel_o, output logic [1:0] exc_pc_mux_o, - output logic force_nop_o, input logic illegal_c_insn_i, @@ -169,8 +169,6 @@ module id_stage logic exc_pc_sel; logic [2:0] pc_mux_sel_int; // selects next PC in if stage - logic force_nop_exc; - logic irq_present; // Signals running between controller and exception controller @@ -267,8 +265,7 @@ module id_stage logic [31:0] operand_c; - assign force_nop_o = force_nop_exc; - assign pc_mux_sel_o = (exc_pc_sel == 1'b1) ? `PC_EXCEPTION : pc_mux_sel_int; + assign pc_mux_sel_o = pc_mux_sel_int; assign instr = instr_rdata_i; @@ -538,6 +535,8 @@ module id_stage .instr_req_o ( instr_req_o ), .instr_gnt_i ( instr_gnt_i ), .instr_ack_i ( instr_ack_i ), + + .pc_set_o ( pc_set_o ), .pc_mux_sel_o ( pc_mux_sel_int ), // Alu signals @@ -592,6 +591,7 @@ module id_stage .irq_present_i ( irq_present ), // Exception Controller Signals + .exc_pc_sel_i ( exc_pc_sel ), .illegal_c_insn_i ( illegal_c_insn_i ), .illegal_insn_o ( illegal_insn ), .trap_insn_o ( trap_insn ), @@ -662,7 +662,6 @@ module id_stage // to IF stage .exc_pc_sel_o ( exc_pc_sel ), .exc_pc_mux_o ( exc_pc_mux_o ), - .force_nop_o ( force_nop_exc ), // hwloop signals .hwloop_enable_o ( hwloop_enable ), diff --git a/if_stage.sv b/if_stage.sv index 10b4d0b1..80873bad 100644 --- a/if_stage.sv +++ b/if_stage.sv @@ -60,7 +60,7 @@ module if_stage output logic [31:0] current_pc_id_o, // Forwarding ports - control signals - input logic force_nop_i, // insert a NOP in the pipe + input logic pc_set_i, // set the program counter to a new value input logic [31:0] exception_pc_reg_i, // address used to restore PC when the interrupt/exception is served input logic [2:0] pc_mux_sel_i, // sel for pc multiplexer input logic [1:0] exc_pc_mux_i, // select which exception to execute @@ -78,7 +78,6 @@ module if_stage // from debug unit input logic [31:0] dbg_npc_i, - input logic dbg_set_npc_i, // pipeline stall input logic stall_if_i, @@ -320,7 +319,7 @@ module if_stage end end else if (jump_in_id_i == `BRANCH_JAL || jump_in_id_i == `BRANCH_JALR - || dbg_set_npc_i + || pc_set_i || hwloop_jump_i) begin valid_o = 1'b0; diff --git a/riscv_core.sv b/riscv_core.sv index ccd11be7..24c84416 100644 --- a/riscv_core.sv +++ b/riscv_core.sv @@ -86,7 +86,7 @@ module riscv_core logic illegal_c_insn_id; // Illegal compressed instruction sent to ID stage logic [31:0] current_pc_if; // Current Program counter logic [31:0] current_pc_id; // Current Program counter - logic force_nop_id; + logic pc_set; logic [2:0] pc_mux_sel_id; // Mux selector for next PC logic [1:0] exc_pc_mux_id; // Mux selector for exception PC @@ -248,8 +248,8 @@ module riscv_core .current_pc_if_o ( current_pc_if ), // current pc in IF stage .current_pc_id_o ( current_pc_id ), // current pc in ID stage - // Forwrding ports - control signals - .force_nop_i ( force_nop_id ), // select incoming instr or NOP + // control signals + .pc_set_i ( pc_set ), .exception_pc_reg_i ( epcr ), // Exception PC register .pc_mux_sel_i ( pc_mux_sel_id ), // sel for pc multiplexer .exc_pc_mux_i ( exc_pc_mux_id ), // selector for exception multiplexer @@ -260,7 +260,6 @@ module riscv_core // from debug unit .dbg_npc_i ( dbg_npc ), - .dbg_set_npc_i ( dbg_set_npc ), // Jump and branch target and decision .jump_in_id_i ( jump_in_id ), @@ -308,9 +307,9 @@ module riscv_core .instr_gnt_i ( instr_grant_i ), .instr_ack_i ( instr_ack_int ), + .pc_set_o ( pc_set ), .pc_mux_sel_o ( pc_mux_sel_id ), .exc_pc_mux_o ( exc_pc_mux_id ), - .force_nop_o ( force_nop_id ), .illegal_c_insn_i ( illegal_c_insn_id ),