diff --git a/src/commit_stage.sv b/src/commit_stage.sv index 213bde268..034bdb40b 100644 --- a/src/commit_stage.sv +++ b/src/commit_stage.sv @@ -151,5 +151,9 @@ module commit_stage ( exception_o = csr_exception_i; exception_o.tval = commit_instr_i.ex.tval; end + // If we halted the processor don't take any exceptions + if (halt_i) begin + exception_o.valid = 1'b0; + end end endmodule diff --git a/src/debug_unit.sv b/src/debug_unit.sv index 8aedcc260..300e23967 100755 --- a/src/debug_unit.sv +++ b/src/debug_unit.sv @@ -20,12 +20,13 @@ import ariane_pkg::*; module debug_unit ( - input logic clk_i, // Clock - input logic rst_ni, // Asynchronous reset active low + input logic clk_i, // Clock + input logic rst_ni, // Asynchronous reset active low - input logic [63:0] commit_pc_i, + input scoreboard_entry commit_instr_i, input logic commit_ack_i, - + input exception ex_i, // instruction caused an exception + output logic halt_o, // halt the hart // External Debug Interface input logic debug_req_i, output logic debug_gnt_o, @@ -39,6 +40,31 @@ module debug_unit ( input logic debug_resume_i ); + // select debug register source/destination + enum logic [2:0] {RD_NONE, RD_CSR, RD_GPR, RD_DBGA, RD_DBGS} rdata_sel_q, rdata_sel_n; + + enum logic [1:0] {RUNNING, HALT_REQ, SINGLE_STEP, HALTED} CS, NS; + + // debug interface registers, we need to give the read data back one cycle later along with the rvalid flag + logic rvalid_n, rvalid_q; + logic rdata_n, rdata_q; + // save previous PC + logic ppc_n, ppc_q; + // --------------- + // Debug Register + // --------------- + // enable exceptions which will cause a transfer to the debug mode + logic [63:0] dbg_ie_n, dbg_ie_q; + // cause register which caused transfer to debug mode + logic [63:0] dbg_cause_n, dbg_cause_q; + + // change debug mode + logic halt_req, resume_req; + logic ss_req, ss_resume_req; // request single step and resume execution from single step + + assign debug_rvalid_o = rvalid_q; + assign debug_rdata_o = rdata_q; + // | Address | Name | Description | // |---------------|-----------------|---------------------------------------------------------------------| @@ -49,20 +75,64 @@ module debug_unit ( // | 0x4000-0x7FFF | CSR | Control and Status Registers. Only accessible if the core is halted | always_comb begin : debug_ctrl + rdata_sel_n = RD_NONE; + + debug_gnt_o = 1'b0; + rdata_n = 'b0; + rvalid_n = 1'b0; + + halt_req = 1'b0; + ss_req = 1'b0; + ss_resume_req = 1'b0; + // update the previous PC if got a valid commit + ppc_n = (commit_ack_i) ? commit_instr_i.pc : ppc_q; + // debug registers + dbg_ie_n = dbg_ie_q; + dbg_cause_n = dbg_cause_q; // ---------- // Read // ---------- // we've got a new read request if (debug_req_i && !debug_we_i) begin - - + // we can immediately grant the request + debug_gnt_o = 1'b1; + // decode debug address + case (debug_addr_i) + DBG_CTRL: rdata_n = {32'b0, 15'b0, (CS == HALTED), 15'b0, (CS == SINGLE_STEP)}; + DBG_HIT: rdata_n = {63'b0, sshit}; + DBG_IE: rdata_n = dbg_ie_q; + DBG_CAUSE: rdata_n = dbg_cause_q; + DBG_NPC: rdata_n = commit_instr_i.pc; + DBG_PPC: rdata_n = ppc_q; + endcase // ---------- // Write // ---------- end else if (debug_req_i) begin + // we can also immediately grant + debug_gnt_o = 1'b1; + // decode debug address + case (debug_addr_i) + DBG_CTRL: begin + // check if requested a halt + halt_req = debug_wdata_i[16]; + resume_req = ~debug_wdata_i[16]; + // enable/disable single step + ss_req = debug_wdata_i[0]; + ss_resume_req = ~debug_wdata_i[0]; + DBG_HIT: + DBG_IE: dbg_ie_n = debug_wdata_i; + DBG_CAUSE: dbg_cause_n = debug_wdata_i; + end + endcase + end - + // if an exception occurred and it is enabled to trigger debug mode, halt the processor + if (ex_i.valid && (|(ex_i.cause & dbg_ie_q)) == 1'b1) begin + halt_req = 1'b1; + // save the cause why we entered the exception + dbg_cause_n = ex_i.cause; end end @@ -70,4 +140,66 @@ module debug_unit ( // HW Breakpoints // -------------------- -endmodule \ No newline at end of file + // -------------------- + // Stall Control + // -------------------- + always_comb begin + NS = CS; + // do not halt by default + halt_o = 1'b0; + case (CS) + // CPU is running normally + RUNNING: begin + // external debugger requested to halt the CPU + if (halt_req) begin + NS = HALT_REQ; + end + + end + // a halt was requested, we wait here until we get the next valid instruction + // in order to properly populate the npc and ppc counters + HALT_REQ: begin + // we've got a valid instruction in the commit stage so we can proceed to the halted state + if (commit_instr_i.valid) begin + NS = HALTED; + end + end + // we are in single step mode + SINGLE_STEP: begin + // resume from single steps + if (ss_resume_req) begin + NS = RUNNING; + end + end + + // CPU is halted, we are in debug mode + HALTED: begin + halt_o = 1'b1; + if (resume_req) + NS = RUNNING; + end + + endcase + end + + // -------------------- + // Registers + // -------------------- + always_ff @(posedge clk_i or negedge rst_ni) begin + if (~rst_ni) begin + CS <= RUNNING; + rdata_q <= '0; + rvalid_q <= 1'b0; + ppc_q <= 64'b0; + dbg_ie_q <= 64'b0; + dbg_cause_q <= 64'b0; + end else begin + CS <= NS; + rdata_q <= rdata_n; + rvalid_q <= rvalid_n; + ppc_q <= ppc_n; + dbg_ie_q <= dbg_ie_n; + dbg_cause_q <= dbg_cause_n; + end + end +endmodule