diff --git a/controller.sv b/controller.sv index 3ac1e51b..015602b6 100644 --- a/controller.sv +++ b/controller.sv @@ -52,6 +52,7 @@ module riscv_controller input logic regc_used_i, // register C is used // from IF/ID pipeline + input logic instr_valid_i, // instruction coming from IF/ID pipeline is valid input logic [31:0] instr_rdata_i, // Instruction read from instr memory/cache: (sampled in the if stage) // from prefetcher @@ -125,7 +126,8 @@ module riscv_controller // FSM state encoding enum logic [3:0] { RESET, BOOT_SET, SLEEP, FIRST_FETCH, - DECODE, BRANCH_DELAY, + DECODE, + JUMP_EXC, FLUSH_EX, FLUSH_WB, DBG_WAIT_BRANCH, DBG_SIGNAL, DBG_WAIT } ctrl_fsm_cs, ctrl_fsm_ns; @@ -249,93 +251,104 @@ module riscv_controller DECODE: begin - is_decoding_o = 1'b1; + is_decoding_o = 1'b0; - // decode and execute instructions only if the current conditional - // branch in the EX stage is either not taken, or there is no - // conditional branch in the EX stage - if ((jump_in_ex_i == `BRANCH_COND && ~branch_decision_i) || - (jump_in_ex_i != `BRANCH_COND)) - begin // now analyze the current instruction in the ID stage + // TODO: integrate this with the next loop, rename branch_decision + // into branch_taken and remove the jump_in_ex signal completely, + // there is no need to propagate it into the controller + if (instr_valid_i) begin - // handle unconditional jumps - // we can jump directly since we know the address already - // we don't need to worry about conditional branches here as they - // will be evaluated in the EX stage - if (jump_in_dec_i == `BRANCH_JALR || jump_in_dec_i == `BRANCH_JAL) begin - pc_mux_sel_o = `PC_JUMP; + // decode and execute instructions only if the current conditional + // branch in the EX stage is either not taken, or there is no + // conditional branch in the EX stage + if ((jump_in_ex_i == `BRANCH_COND && ~branch_decision_i) || + (jump_in_ex_i != `BRANCH_COND)) + begin // now analyze the current instruction in the ID stage + is_decoding_o = 1'b1; - // if there is a jr stall, wait for it to be gone - if (~jr_stall_o) - pc_set_o = 1'b1; + // handle unconditional jumps + // we can jump directly since we know the address already + // we don't need to worry about conditional branches here as they + // will be evaluated in the EX stage + if (jump_in_dec_i == `BRANCH_JALR || jump_in_dec_i == `BRANCH_JAL) begin + pc_mux_sel_o = `PC_JUMP; - // 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 + // if there is a jr stall, wait for it to be gone + if (~jr_stall_o) + pc_set_o = 1'b1; - // handle hwloops - if (hwloop_jump_i) begin - pc_mux_sel_o = `PC_HWLOOP; - pc_set_o = 1'b1; - end + // 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 exceptions - if (exc_req_i) begin - pc_mux_sel_o = `PC_EXCEPTION; - pc_set_o = 1'b1; - exc_ack_o = 1'b1; + // handle hwloops + if (hwloop_jump_i) begin + pc_mux_sel_o = `PC_HWLOOP; + pc_set_o = 1'b1; + end - save_pc_id_o = 1'b1; + if (eret_insn_i) begin + pc_mux_sel_o = `PC_ERET; + pc_set_o = 1'b1; + end - // 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_i) begin - pc_mux_sel_o = `PC_ERET; - pc_set_o = 1'b1; - - // go back to sleep if core was woken up for this interrupt - if (fetch_enable_i == 1'b0) begin + // handle WFI instruction, flush pipeline and (potentially) go to + // sleep + // also handles eret when the core should go back to sleep + if (pipe_flush_i || (eret_insn_i && (~fetch_enable_i))) + begin halt_if_o = 1'b1; halt_id_o = 1'b1; ctrl_fsm_ns = FLUSH_EX; end - end - // handle WFI instruction, flush pipeline and (potentially) go to - // sleep - if (pipe_flush_i) - begin - halt_if_o = 1'b1; - halt_id_o = 1'b1; + // handle exceptions + if (exc_req_i) begin + // to not loose the hwloop, we to into a special state where we + // save the new PC + if (hwloop_jump_i) + begin + ctrl_fsm_ns = JUMP_EXC; + end else begin + pc_mux_sel_o = `PC_EXCEPTION; + pc_set_o = 1'b1; + exc_ack_o = 1'b1; - ctrl_fsm_ns = FLUSH_EX; - end + halt_id_o = 1'b1; // we don't want to propagate this instruction to EX + save_pc_id_o = 1'b1; - // take care of debug - // branch conditional will be handled in next state - if (trap_hit_i) - begin - // halt pipeline immediately - halt_if_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 + end - // make sure the current instruction has been executed - // before changing state to non-decode - if (id_valid_i) begin - if (jump_in_id_i == `BRANCH_COND) - ctrl_fsm_ns = DBG_WAIT_BRANCH; - else - ctrl_fsm_ns = DBG_SIGNAL; + // take care of debug + // branch conditional will be handled in next state + if (trap_hit_i) + begin + // halt pipeline immediately + halt_if_o = 1'b1; + + // make sure the current instruction has been executed + // before changing state to non-decode + if (id_valid_i) begin + if (jump_in_id_i == `BRANCH_COND) + ctrl_fsm_ns = DBG_WAIT_BRANCH; + else + ctrl_fsm_ns = DBG_SIGNAL; + end end end end - else - begin + + // TODO: make sure this is not done multiple times in a row!!! + // maybe with an assertion? + // handle conditional branches + if (jump_in_ex_i == `BRANCH_COND && branch_decision_i) begin // there is a branch in the EX stage that is taken pc_mux_sel_o = `PC_BRANCH; pc_set_o = 1'b1; @@ -349,26 +362,9 @@ module riscv_controller begin ctrl_fsm_ns = DBG_SIGNAL; end - else - begin - if (if_valid_i) - ctrl_fsm_ns = DECODE; - else // change to special state when the new instruction is not yet ready - ctrl_fsm_ns = BRANCH_DELAY; - end end end - // a branch was executed, but the instruction cache was not ready to - // serve a new instruction - BRANCH_DELAY: - begin - is_decoding_o = 1'b0; - - if (if_valid_i) - ctrl_fsm_ns = DECODE; - end - // a branch was in ID when a debug trap is hit DBG_WAIT_BRANCH: begin @@ -406,7 +402,7 @@ module riscv_controller end if(dbg_stall_i == 1'b0) begin - ctrl_fsm_ns = BRANCH_DELAY; + ctrl_fsm_ns = DECODE; end end @@ -437,6 +433,19 @@ module riscv_controller end end + // go to an exception handler after a jump + JUMP_EXC: + begin + // we can just save the IF PC, since it propagated through the + // prefetcher + save_pc_if_o = 1'b1; + pc_mux_sel_o = `PC_EXCEPTION; + pc_set_o = 1'b1; + exc_ack_o = 1'b1; + + ctrl_fsm_ns = DECODE; + end + default: begin instr_req_o = 1'b0; ctrl_fsm_ns = RESET; diff --git a/id_stage.sv b/id_stage.sv index 54744ca1..6a5ecdc1 100644 --- a/id_stage.sv +++ b/id_stage.sv @@ -44,11 +44,11 @@ module riscv_id_stage output logic core_busy_o, output logic is_decoding_o, - // Interface to instruction memory + // Interface to IF stage + input logic instr_valid_i, input logic [31:0] instr_rdata_i, // comes from pipeline of IF stage output logic instr_req_o, - input logic id_execute_i, // Jumps and branches output logic [1:0] jump_in_id_o, @@ -57,7 +57,7 @@ module riscv_id_stage output logic [31:0] jump_target_o, // IF and ID stage signals - output logic clear_id_execute_o, + output logic clear_instr_valid_o, output logic pc_set_o, output logic [2:0] pc_mux_sel_o, output logic [1:0] exc_pc_mux_o, @@ -317,12 +317,9 @@ module riscv_id_stage regfile_waddr_id : regfile_addr_ra_id; - // ID execute signal control - // This signal is used to detect when an instruction first enters the ID - // stage. Based on this hardware loops are decremented and it's also useful - // for exceptions, i.e. to suppress the illegal instruction signal during - // an if stall of a jump. - assign clear_id_execute_o = (~jr_stall) | (|hwloop_end_addr); + // kill instruction in the IF/ID stage by setting the instr_valid_id control + // signal to 0 for instructions that are done + assign clear_instr_valid_o = id_ready_o; /////////////////////////////////////////////// @@ -644,6 +641,7 @@ module riscv_id_stage .regc_used_i ( regc_used_dec ), // from IF/ID pipeline + .instr_valid_i ( instr_valid_i ), .instr_rdata_i ( instr ), // from prefetcher @@ -796,7 +794,7 @@ module riscv_id_stage .hwloop_regid_i ( hwloop_regid ), // from controller - .stall_id_i ( id_execute_i ), + .stall_id_i ( instr_valid_i ), // to hwloop controller .hwloop_start_addr_o ( hwloop_start_addr ), @@ -942,6 +940,6 @@ module riscv_id_stage // stall control assign id_ready_o = (~misaligned_stall) & (~jr_stall) & (~load_stall) & ex_ready_i; - assign id_valid_o = (~halt_id) & if_ready_i & id_ready_o; + assign id_valid_o = (~halt_id) & id_ready_o; endmodule diff --git a/if_stage.sv b/if_stage.sv index d026009b..796cf500 100644 --- a/if_stage.sv +++ b/if_stage.sv @@ -55,7 +55,7 @@ module riscv_if_stage input logic [RDATA_WIDTH-1:0] instr_rdata_i, // Output of IF Pipeline stage - output logic id_execute_o, // execute current instruction in ID + output logic instr_valid_id_o, // instruction in IF/ID pipeline is valid output logic [31:0] instr_rdata_id_o, // read instruction is sampled and sent to ID stage for decoding output logic is_compressed_id_o, // compressed decoder thinks this is a compressed instruction output logic illegal_c_insn_id_o, // compressed decoder thinks this is an invalid instruction @@ -63,7 +63,7 @@ module riscv_if_stage output logic [31:0] current_pc_id_o, // Forwarding ports - control signals - input logic clear_id_execute_i, // clear execute bit + input logic clear_instr_valid_i, // clear instruction valid bit in IF/ID 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 @@ -396,7 +396,7 @@ module riscv_if_stage begin : IF_ID_PIPE_REGISTERS if (rst_n == 1'b0) begin - id_execute_o <= 1'b0; + instr_valid_id_o <= 1'b0; instr_rdata_id_o <= '0; illegal_c_insn_id_o <= 1'b0; is_compressed_id_o <= 1'b0; @@ -404,12 +404,12 @@ module riscv_if_stage end else begin - if (clear_id_execute_i) - id_execute_o <= 1'b0; + if (clear_instr_valid_i) + instr_valid_id_o <= 1'b0; if (if_valid_o) - begin : ENABLED_PIPE - id_execute_o <= 1'b0; + begin + instr_valid_id_o <= 1'b1; instr_rdata_id_o <= instr_decompressed; illegal_c_insn_id_o <= illegal_c_insn; is_compressed_id_o <= instr_compressed_int; diff --git a/riscv_core.sv b/riscv_core.sv index 873ee84a..e8c58813 100644 --- a/riscv_core.sv +++ b/riscv_core.sv @@ -85,14 +85,14 @@ module riscv_core // IF/ID signals - logic id_execute; + logic instr_valid_id; logic [31:0] instr_rdata_id; // Instruction sampled inside IF stage logic is_compressed_id; 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 clear_id_execute; + logic clear_instr_valid; 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 @@ -258,7 +258,7 @@ module riscv_core .instr_rdata_i ( instr_rdata_i ), // outputs to ID stage - .id_execute_o ( id_execute ), + .instr_valid_id_o ( instr_valid_id ), .instr_rdata_id_o ( instr_rdata_id ), .is_compressed_id_o ( is_compressed_id ), .illegal_c_insn_id_o ( illegal_c_insn_id ), @@ -266,7 +266,7 @@ module riscv_core .current_pc_id_o ( current_pc_id ), // control signals - .clear_id_execute_i ( clear_id_execute ), + .clear_instr_valid_i ( clear_instr_valid ), .pc_set_i ( pc_set ), .exception_pc_reg_i ( epcr ), // exception return address .pc_mux_sel_i ( pc_mux_sel_id ), // sel for pc multiplexer @@ -322,11 +322,10 @@ module riscv_core .is_decoding_o ( is_decoding ), // Interface to instruction memory + .instr_valid_i ( instr_valid_id ), .instr_rdata_i ( instr_rdata_id ), .instr_req_o ( instr_req_int ), - .id_execute_i ( id_execute ), - // Jumps and branches .jump_in_id_o ( jump_in_id ), .jump_in_ex_o ( jump_in_ex ), @@ -334,7 +333,7 @@ module riscv_core .jump_target_o ( jump_target_id ), // IF and ID control signals - .clear_id_execute_o ( clear_id_execute ), + .clear_instr_valid_o ( clear_instr_valid ), .pc_set_o ( pc_set ), .pc_mux_sel_o ( pc_mux_sel_id ), .exc_pc_mux_o ( exc_pc_mux_id ),