diff --git a/src_files.yml b/src_files.yml index ad924d7b..e74f43d7 100644 --- a/src_files.yml +++ b/src_files.yml @@ -12,7 +12,7 @@ zeroriscy: zeroriscy_debug_unit.sv, zeroriscy_decoder.sv, zeroriscy_exc_controller.sv, - zeroriscy_ex_stage.sv, + zeroriscy_ex_block.sv, zeroriscy_id_stage.sv, zeroriscy_if_stage.sv, zeroriscy_load_store_unit.sv, diff --git a/zeroriscy_controller.sv b/zeroriscy_controller.sv index fa86fc62..4fdb46eb 100644 --- a/zeroriscy_controller.sv +++ b/zeroriscy_controller.sv @@ -49,6 +49,7 @@ module zeroriscy_controller input logic illegal_insn_i, // decoder encountered an invalid instruction input logic mret_insn_i, // decoder encountered an eret instruction input logic pipe_flush_i, // decoder wants to do a pipe flush + input logic ebrk_insn_i, // decoder encountered an ebreak instruction // from IF/ID pipeline input logic instr_valid_i, // instruction coming from IF/ID pipeline is valid @@ -111,7 +112,7 @@ module zeroriscy_controller // FSM state encoding enum logic [3:0] { RESET, BOOT_SET, SLEEP, FIRST_FETCH, - DECODE, FLUSH, + DECODE, FLUSH, IRQ_TAKEN, DBG_SIGNAL, DBG_SIGNAL_SLEEP, DBG_WAIT, DBG_WAIT_BRANCH, DBG_WAIT_SLEEP } ctrl_fsm_cs, ctrl_fsm_ns; logic exc_req; @@ -227,15 +228,12 @@ module zeroriscy_controller ctrl_fsm_ns = DECODE; end - // handle exceptions if (ext_req_i) begin - pc_mux_o = PC_EXCEPTION; - pc_set_o = 1'b1; - exc_ack_o = 1'b1; - irq_ack_o = ext_req_i; - // TODO: This assumes that the pipeline is always flushed before - // going to sleep. - exc_save_if_o = 1'b1; + // This assumes that the pipeline is always flushed before + // going to sleep. + ctrl_fsm_ns = IRQ_TAKEN; + halt_if_o = 1'b1; + halt_id_o = 1'b1; end end @@ -266,51 +264,52 @@ module zeroriscy_controller end int_req_i: begin ctrl_fsm_ns = FLUSH; - halt_if_o = 1'b1; - halt_id_o = 1'b1; + halt_if_o = 1'b1; + halt_id_o = 1'b1; end mret_insn_i: begin ctrl_fsm_ns = FLUSH; - halt_if_o = 1'b1; - halt_id_o = 1'b1; + halt_if_o = 1'b1; + halt_id_o = 1'b1; + end + pipe_flush_i: begin + // handle WFI instruction, flush pipeline and (potentially) go to + // sleep + ctrl_fsm_ns = FLUSH; + halt_if_o = 1'b1; + halt_id_o = 1'b1; + end + ebrk_insn_i: begin + ctrl_fsm_ns = FLUSH; + halt_if_o = 1'b1; + halt_id_o = 1'b1; end default: begin - if (ext_req_i & ~instr_multicyle_i & ~branch_in_id_i) begin - ctrl_fsm_ns = FLUSH; + unique case (1'b1) + ext_req_i & ~instr_multicyle_i & ~branch_in_id_i: begin + ctrl_fsm_ns = IRQ_TAKEN; halt_if_o = 1'b1; halt_id_o = 1'b1; - end - // handle WFI instruction, flush pipeline and (potentially) go to - // sleep TODO: put it in unique case - else if (pipe_flush_i) begin - halt_if_o = 1'b1; - halt_id_o = 1'b1; - ctrl_fsm_ns = FLUSH; - end - else if (dbg_req_i & ~branch_taken_ex_i) - begin - halt_if_o = 1'b1; - if (id_ready_i) begin - ctrl_fsm_ns = DBG_SIGNAL; end - end + dbg_req_i & ~branch_taken_ex_i: begin + halt_if_o = 1'b1; + if (id_ready_i) begin + ctrl_fsm_ns = DBG_SIGNAL; + end + end + default:; + endcase end endcase end - else if (~instr_valid_i) + else //~instr_valid_i begin if (ext_req_i) begin - pc_mux_o = PC_EXCEPTION; - pc_set_o = 1'b1; - exc_ack_o = 1'b1; - exc_save_if_o = 1'b1; - irq_ack_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 + ctrl_fsm_ns = IRQ_TAKEN; + halt_if_o = 1'b1; + halt_id_o = 1'b1; end end end @@ -375,17 +374,7 @@ module zeroriscy_controller halt_id_o = 1'b1; if(fetch_enable_i) begin - if (dbg_req_i) begin - ctrl_fsm_ns = DBG_SIGNAL; - if(int_req_i) begin - //exceptions - pc_mux_o = PC_EXCEPTION; - pc_set_o = 1'b1; - exc_ack_o = 1'b1; - exc_save_id_o = 1'b1; - end - end else begin - ctrl_fsm_ns = DECODE; + ctrl_fsm_ns = dbg_req_i ? DBG_SIGNAL : DECODE; unique case (1'b1) int_req_i: begin pc_mux_o = PC_EXCEPTION; @@ -398,35 +387,33 @@ module zeroriscy_controller pc_set_o = 1'b1; exc_restore_id_o = 1'b1; end - ext_req_i: begin - pc_mux_o = PC_EXCEPTION; - pc_set_o = 1'b1; - exc_ack_o = 1'b1; - //the instruction in id has been already executed - exc_save_if_o = 1'b1; - irq_ack_o = 1'b1; - end default: begin - halt_if_o = 1'b0; + halt_if_o = dbg_req_i; end endcase - end + //end end else begin //~fetch_enable_i //mRET goes back to sleep - if(mret_insn_i) begin - //in order to restore the xPIE in xIE - exc_restore_id_o = 1'b1; - pc_mux_o = PC_ERET; - pc_set_o = 1'b1; - end - if (dbg_req_i) begin - ctrl_fsm_ns = DBG_SIGNAL_SLEEP; - end else begin - ctrl_fsm_ns = SLEEP; + if (mret_insn_i) begin + pc_mux_o = PC_ERET; + pc_set_o = 1'b1; + exc_restore_id_o = 1'b1; end + ctrl_fsm_ns = dbg_req_i ? DBG_SIGNAL_SLEEP : SLEEP; end end + IRQ_TAKEN: + begin + pc_mux_o = PC_EXCEPTION; + pc_set_o = 1'b1; + exc_ack_o = 1'b1; + //the instruction in id has been already executed or it was not valid + exc_save_if_o = 1'b1; + irq_ack_o = 1'b1; + ctrl_fsm_ns = DECODE; + end + default: begin instr_req_o = 1'b0; ctrl_fsm_ns = RESET; diff --git a/zeroriscy_core.sv b/zeroriscy_core.sv index 2381e58b..b0d65d99 100644 --- a/zeroriscy_core.sv +++ b/zeroriscy_core.sv @@ -304,7 +304,7 @@ module zeroriscy_core .exception_pc_reg_i ( mepc ), // exception return address .pc_mux_i ( pc_mux_id ), // sel for pc multiplexer .exc_pc_mux_i ( exc_pc_mux_id ), - .exc_vec_pc_mux_i ( irq_id_i ), + .exc_vec_pc_mux_i ( exc_cause[4:0] ), // from debug unit diff --git a/zeroriscy_decoder.sv b/zeroriscy_decoder.sv index 6d988785..05c281bf 100644 --- a/zeroriscy_decoder.sv +++ b/zeroriscy_decoder.sv @@ -90,9 +90,6 @@ module zeroriscy_decoder logic regfile_we; logic data_req; - logic ebrk_insn; - logic pipe_flush; - logic mult_int_en; logic div_int_en; logic branch_in_id; @@ -139,10 +136,10 @@ module zeroriscy_decoder data_load_event_o = 1'b0; illegal_insn_o = 1'b0; - ebrk_insn = 1'b0; + ebrk_insn_o = 1'b0; mret_insn_o = 1'b0; ecall_insn_o = 1'b0; - pipe_flush = 1'b0; + pipe_flush_o = 1'b0; unique case (instr_rdata_i[6:0]) @@ -494,7 +491,7 @@ module zeroriscy_decoder 12'h001: // ebreak begin // debugger trap - ebrk_insn = 1'b1; + ebrk_insn_o = 1'b1; end 12'h302: // mret @@ -505,7 +502,7 @@ module zeroriscy_decoder 12'h105: // wfi begin // flush pipeline - pipe_flush = 1'b1; + pipe_flush_o = 1'b1; end default: @@ -580,7 +577,5 @@ module zeroriscy_decoder assign csr_op_o = (deassert_we_i) ? CSR_OP_NONE : csr_op; assign jump_in_id_o = (deassert_we_i) ? 1'b0 : jump_in_id; assign branch_in_id_o = (deassert_we_i) ? 1'b0 : branch_in_id; - assign ebrk_insn_o = (deassert_we_i) ? 1'b0 : ebrk_insn; - assign pipe_flush_o = (deassert_we_i) ? 1'b0 : pipe_flush; endmodule // controller diff --git a/zeroriscy_ex_stage.sv b/zeroriscy_ex_block.sv similarity index 100% rename from zeroriscy_ex_stage.sv rename to zeroriscy_ex_block.sv diff --git a/zeroriscy_exc_controller.sv b/zeroriscy_exc_controller.sv index d2bb5b28..8e62e9aa 100644 --- a/zeroriscy_exc_controller.sv +++ b/zeroriscy_exc_controller.sv @@ -37,6 +37,8 @@ module zeroriscy_exc_controller output logic ext_req_o, input logic ack_i, + input logic ctr_decoding_i, + output logic trap_o, // to IF stage @@ -61,11 +63,12 @@ module zeroriscy_exc_controller ); - enum logic [1:0] { IDLE, WAIT_CONTROLLER_INT, WAIT_CONTROLLER_EXT } exc_ctrl_cs, exc_ctrl_ns; + enum logic [1:0] { IDLE, WAIT_CONTROLLER_INT, WAIT_CONTROLLER_EXT, WAIT_CONTROLLER_DBG } exc_ctrl_cs, exc_ctrl_ns; logic req_int, int_req_int, ext_req_int; logic [1:0] pc_mux_int, pc_mux_int_q; logic [5:0] cause_int, cause_int_q; + logic trap_int; // a trap towards the debug unit is generated when one of the // following conditions are true: @@ -74,19 +77,19 @@ module zeroriscy_exc_controller // - illegal instruction exception and IIE bit is set // - IRQ and INTE bit is set and no exception is currently running // - Debuger requests halt - assign trap_o = (dbg_settings_i[DBG_SETS_SSTE]) + assign trap_int = (dbg_settings_i[DBG_SETS_SSTE]) | (ecall_insn_i & dbg_settings_i[DBG_SETS_ECALL]) | (ebrk_insn_i & dbg_settings_i[DBG_SETS_EBRK]) | (illegal_insn_i & dbg_settings_i[DBG_SETS_EILL]) | (irq_enable_i & irq_i & dbg_settings_i[DBG_SETS_IRQ]); -// request for exception/interrupt -assign int_req_int = ecall_insn_i - | illegal_insn_i; + // request for exception/interrupt + assign int_req_int = ecall_insn_i + | illegal_insn_i; -assign ext_req_int = irq_enable_i & irq_i; + assign ext_req_int = irq_enable_i & irq_i; -assign req_int = int_req_int | ext_req_int; + assign req_int = int_req_int | ext_req_int; // Exception cause and ISR address selection always_comb @@ -131,7 +134,7 @@ assign req_int = int_req_int | ext_req_int; if (rst_n == 1'b0) begin cause_int_q <= '0; pc_mux_int_q <= '0; - end else if (exc_ctrl_cs == IDLE && req_int) begin + end else if (exc_ctrl_cs == IDLE && (ctr_decoding_i | ext_req_o)) begin // save cause and ISR when new irq request is first sent to controller cause_int_q <= cause_int; pc_mux_int_q <= pc_mux_int; @@ -140,8 +143,10 @@ assign req_int = int_req_int | ext_req_int; // Exception cause and mux output (with bypass) - assign cause_o = ((exc_ctrl_cs == IDLE && req_int) || ebrk_insn_i) ? cause_int : cause_int_q; - assign pc_mux_o = (exc_ctrl_cs == IDLE && req_int) ? pc_mux_int : pc_mux_int_q; +// assign cause_o = ((exc_ctrl_cs == IDLE && req_int) || ebrk_insn_i) ? cause_int : cause_int_q; +// assign pc_mux_o = (exc_ctrl_cs == IDLE && req_int) ? pc_mux_int : pc_mux_int_q; + assign cause_o = cause_int_q; + assign pc_mux_o = pc_mux_int_q; // Exception controller FSM always_comb @@ -150,35 +155,30 @@ assign req_int = int_req_int | ext_req_int; int_req_o = 1'b0; ext_req_o = 1'b0; save_cause_o = 1'b0; + trap_o = 1'b0; unique case (exc_ctrl_cs) IDLE: begin int_req_o = int_req_int; ext_req_o = ext_req_int; - if (int_req_int) begin - exc_ctrl_ns = WAIT_CONTROLLER_INT; - - if (ack_i) begin - save_cause_o = 1'b1; - exc_ctrl_ns = IDLE; - end - end else begin - if (ext_req_o) begin - exc_ctrl_ns = WAIT_CONTROLLER_EXT; - - if (ack_i) begin - save_cause_o = 1'b1; - exc_ctrl_ns = IDLE; - end - end - end + trap_o = dbg_settings_i[DBG_SETS_SSTE]; + unique case(1'b1) + int_req_int & ctr_decoding_i: + exc_ctrl_ns = WAIT_CONTROLLER_INT; + ebrk_insn_i & ctr_decoding_i: + exc_ctrl_ns = WAIT_CONTROLLER_DBG; + default: + if (ext_req_o) + exc_ctrl_ns = WAIT_CONTROLLER_EXT; + endcase end WAIT_CONTROLLER_INT: begin int_req_o = 1'b1; ext_req_o = 1'b0; + trap_o = trap_int; if (ack_i) begin save_cause_o = 1'b1; exc_ctrl_ns = IDLE; @@ -189,12 +189,19 @@ assign req_int = int_req_int | ext_req_int; begin int_req_o = 1'b0; ext_req_o = 1'b1; + trap_o = trap_int; if (ack_i) begin save_cause_o = 1'b1; exc_ctrl_ns = IDLE; end end + WAIT_CONTROLLER_DBG: + begin + exc_ctrl_ns = IDLE; + trap_o = trap_int; + end + default: begin exc_ctrl_ns = IDLE; diff --git a/zeroriscy_id_stage.sv b/zeroriscy_id_stage.sv index cd87c535..b49ee8b1 100644 --- a/zeroriscy_id_stage.sv +++ b/zeroriscy_id_stage.sv @@ -525,6 +525,7 @@ module zeroriscy_id_stage .illegal_insn_i ( illegal_insn_dec | illegal_reg_rv32e ), .mret_insn_i ( mret_insn_dec ), .pipe_flush_i ( pipe_flush_dec ), + .ebrk_insn_i ( ebrk_insn ), // from IF/ID pipeline .instr_valid_i ( instr_valid_i ), @@ -600,9 +601,9 @@ module zeroriscy_id_stage .int_req_o ( int_req ), .ext_req_o ( ext_req ), .ack_i ( exc_ack ), + .ctr_decoding_i ( is_decoding_o ), .trap_o ( dbg_trap_o ), - // to IF stage .pc_mux_o ( exc_pc_mux_o ), @@ -611,9 +612,9 @@ module zeroriscy_id_stage .irq_id_i ( irq_id_i ), .irq_enable_i ( irq_enable_i ), - .ebrk_insn_i ( is_decoding_o & ebrk_insn ), - .illegal_insn_i ( is_decoding_o & illegal_insn_dec ), - .ecall_insn_i ( is_decoding_o & ecall_insn_dec ), + .ebrk_insn_i ( ebrk_insn ), + .illegal_insn_i ( illegal_insn_dec ), + .ecall_insn_i ( ecall_insn_dec ), .cause_o ( exc_cause_o ), .save_cause_o ( save_exc_cause_o ), @@ -645,7 +646,7 @@ module zeroriscy_id_stage assign alu_operand_b_ex_o = alu_operand_b; assign csr_access_ex_o = csr_access; - assign csr_op_ex_o = id_ready_o ? csr_op : CSR_OP_NONE; + assign csr_op_ex_o = csr_op; assign branch_in_ex_o = branch_in_id; @@ -682,7 +683,7 @@ module zeroriscy_id_stage always_comb begin id_wb_fsm_ns = id_wb_fsm_cs; - regfile_we = regfile_we_id & (~halt_id); + regfile_we = regfile_we_id; load_stall = 1'b0; multdiv_stall = 1'b0; jump_stall = 1'b0; diff --git a/zeroriscy_if_stage.sv b/zeroriscy_if_stage.sv index 4a0e0871..17ab55bf 100644 --- a/zeroriscy_if_stage.sv +++ b/zeroriscy_if_stage.sv @@ -102,10 +102,8 @@ module zeroriscy_if_stage unique case (exc_pc_mux_i) EXC_PC_ILLINSN: exc_pc = { boot_addr_i[31:8], EXC_OFF_ILLINSN }; EXC_PC_ECALL: exc_pc = { boot_addr_i[31:8], EXC_OFF_ECALL }; - EXC_PC_LOAD: exc_pc = { boot_addr_i[31:8], EXC_OFF_LSUERR }; EXC_PC_IRQ: exc_pc = { boot_addr_i[31:8], 1'b0, exc_vec_pc_mux_i[4:0], 2'b0 }; - // TODO: Add case for EXC_PC_STORE as soon as it differs from load - + // TODO: Add case for EXC_PC_STORE and EXC_PC_LOAD as soon as they are supported default:; endcase end