diff --git a/include/ariane_pkg.sv b/include/ariane_pkg.sv index 0b051a593..b6e364505 100644 --- a/include/ariane_pkg.sv +++ b/include/ariane_pkg.sv @@ -311,25 +311,12 @@ package ariane_pkg; DBG_HIT = 15'h4, DBG_IE = 15'h8, DBG_CAUSE = 15'hC, - DBG_BPCTRL0 = 15'h40, - DBG_BPDATA0 = 15'h44, - DBG_BPCTRL1 = 15'h48, - DBG_BPDATA1 = 15'h4C, - DBG_BPCTRL2 = 15'h50, - DBG_BPDATA2 = 15'h54, - DBG_BPCTRL3 = 15'h58, - DBG_BPDATA3 = 15'h5C, - DBG_BPCTRL4 = 15'h60, - DBG_BPDATA4 = 15'h64, - DBG_BPCTRL5 = 15'h68, - DBG_BPDATA5 = 15'h6C, - DBG_BPCTRL6 = 15'h70, - DBG_BPDATA6 = 15'h74, - DBG_BPCTRL7 = 15'h78, - DBG_BPDATA7 = 15'h7C, - DBG_GPR = 15'h4xx, - DBG_CSR = 15'h5xx, + DBG_BPCTRL = 15'b????000, + DBG_BPDATA = 15'b?????00, + DBG_GPR = 15'h4??, + DBG_CSR = 15'h5??, DBG_NPC = 15'h2000, DBG_PPC = 15'h2004 } debug_reg_t; + endpackage diff --git a/src/debug_unit.sv b/src/debug_unit.sv index 099a334e0..39b258223 100755 --- a/src/debug_unit.sv +++ b/src/debug_unit.sv @@ -39,6 +39,10 @@ module debug_unit ( output logic debug_csr_we_o, output logic [63:0] debug_csr_wdata_o, input logic [63:0] debug_csr_rdata_i, + // CPU Control + output logic [63:0] debug_pc_o, + output logic debug_set_pc_o, + // HWPB // External Debug Interface input logic debug_req_i, output logic debug_gnt_o, @@ -59,7 +63,7 @@ module debug_unit ( logic rvalid_n, rvalid_q; logic rdata_n, rdata_q; // save previous PC - logic ppc_n, ppc_q; + logic dbg_ppc_n, dbg_ppc_q; // --------------- // Debug Register // --------------- @@ -69,15 +73,21 @@ module debug_unit ( logic [63:0] dbg_cause_n, dbg_cause_q; // single step mode logic dbg_ss_n, dbg_ss_q; - logic dbg_ssth_n, dbg_ssth_q; + logic [63:0] dbg_hit_n, dbg_hit_q; + // hardware breakpoints + logic [7:0][3:0] dbg_hwbp_ctrl_n, dbg_hwbp_ctrl_q; + logic [7:0][63:0] dbg_hwbp_data_n, dbg_hwbp_data_q; + // ---------------------- + // Debug Control Signals + // ---------------------- // change debug mode logic halt_req, resume_req; logic stepped_single; - + // assigns, we can output a couple of signals directly assign debug_rvalid_o = rvalid_q; assign debug_rdata_o = rdata_q; - assign debug_halted_o = (CS == HALTED); + // | Address | Name | Description | // |---------------|-----------------|---------------------------------------------------------------------| // | 0x0000-0x007F | Debug Registers | Always accessible, even when the core is running | @@ -85,20 +95,21 @@ module debug_unit ( // | 0x0500-0x05FF | FPR (f0-f31) | Reserved. Not used in the Ariane. | // | 0x2000-0x20FF | Debug Registers | Only accessible if the core is halted | // | 0x4000-0x7FFF | CSR | Control and Status Registers. Only accessible if the core is halted | - always_comb begin : debug_ctrl - debug_gnt_o = 1'b0; - rdata_n = 'b0; - rvalid_n = 1'b0; + debug_gnt_o = 1'b0; + rdata_n = 'b0; + rvalid_n = 1'b0; - halt_req = 1'b0; + halt_req = 1'b0; // update the previous PC if got a valid commit - ppc_n = (commit_ack_i) ? commit_instr_i.pc : ppc_q; + dbg_ppc_n = (commit_ack_i) ? commit_instr_i.pc : dbg_ppc_q; // debug registers - dbg_ie_n = dbg_ie_q; - dbg_cause_n = dbg_cause_q; - dbg_ss_n = dbg_ss_q; - dbg_ssth_n = dbg_ssth_q; + dbg_ie_n = dbg_ie_q; + dbg_cause_n = dbg_cause_q; + dbg_ss_n = dbg_ss_q; + dbg_hit_n = dbg_hit_q; + dbg_hwbp_ctrl_n = dbg_hwbp_ctrl_q; + dbg_hwbp_data_n = dbg_hwbp_data_q; // GPR defaults debug_gpr_req_o = 1'b0; debug_gpr_addr_o = debug_addr_i[6:2]; @@ -109,9 +120,13 @@ module debug_unit ( debug_csr_addr_o = debug_addr_i[13:2]; debug_csr_we_o = 1'b0; debug_csr_wdata_o = 64'b0; + // change ctrl flow + debug_pc_o = 64'b0; + debug_set_pc_o = 1'b0; + // we did one single step, set the sticky bit if (stepped_single) - dbg_ssth_n = 1'b1; + dbg_hit_n = 1'b1; // ---------- // Read @@ -121,13 +136,24 @@ module debug_unit ( // we can immediately grant the request debug_gnt_o = 1'b1; // decode debug address - casex (debug_addr_i) - DBG_CTRL: rdata_n = {32'b0, 15'b0, debug_halted_o, 15'b0, dbg_ss_q}; - DBG_HIT: rdata_n = {63'b0, dbg_ssth_q}; - 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; + casez (debug_addr_i) + DBG_CTRL: rdata_n = {32'b0, 15'b0, debug_halted_o, 15'b0, dbg_ss_q}; + DBG_HIT: rdata_n = {63'b0, dbg_hit_q}; + DBG_IE: rdata_n = dbg_ie_q; + DBG_CAUSE: rdata_n = dbg_cause_q; + // all breakpoints are implemented + DBG_BPCTRL: rdata_n = {57'b0, dbg_hwbp_ctrl_q[debug_addr_i[5:3]], 2'b0, 1'b1}; + DBG_BPDATA: rdata_n = dbg_hwbp_data_q[debug_addr_i[5:3]]; + + DBG_NPC: begin + if (debug_halted_o) + rdata_n = commit_instr_i.pc; + end + + DBG_PPC: begin + if (debug_halted_o) + rdata_n = dbg_ppc_q; + end DBG_GPR: begin if (debug_halted_o) begin @@ -151,7 +177,7 @@ module debug_unit ( // we can also immediately grant debug_gnt_o = 1'b1; // decode debug address - case (debug_addr_i) + casez (debug_addr_i) DBG_CTRL: begin // check if requested a halt halt_req = debug_wdata_i[16]; @@ -159,10 +185,22 @@ module debug_unit ( // enable/disable single step dbg_ss_n = debug_wdata_i[0]; end - DBG_HIT: dbg_ssth_n = debug_wdata_i[0]; - DBG_IE: dbg_ie_n = debug_wdata_i; + DBG_HIT: dbg_hit_n = {debug_wdata_i[15:8], debug_wdata_i[0]}; + DBG_IE: dbg_ie_n = debug_wdata_i; DBG_CAUSE: dbg_cause_n = debug_wdata_i; + // Only triggering on instruction fetch is allowed at the moment + DBG_BPCTRL: dbg_hwbp_ctrl_n[debug_addr_i[5:3]] = {3'b0, debug_wdata_i[1]}; + DBG_BPDATA: dbg_hwbp_data_n[debug_addr_i[5:3]] = debug_wdata_i; + + DBG_NPC: begin + // Change CTRL Flow to debug PC + debug_pc_o = debug_wdata_i; + debug_set_pc_o = 1'b1; + end + // PPC is read-only + DBG_PPC:; + DBG_GPR: begin if (debug_halted_o) begin debug_gpr_req_o = 1'b1; @@ -187,12 +225,22 @@ module debug_unit ( // save the cause why we entered the exception dbg_cause_n = ex_i.cause; end + // -------------------- + // HW Breakpoints + // -------------------- + // check all possible breakpoints + for (logic [7:0] i = 0; i < 8; i++) begin + // check if a breakpoint is triggering, therefore check if it is enabled + if (dbg_hwbp_ctrl_q[1]) begin + // check if the PC is matching and the processor is currently retiring the instruction + if (commit_instr_i.pc == dbg_hwbp_data_q && commit_ack_i) begin + halt_req = 1'b1; + dbg_hit_n[15:8] = i; + end + end + end end - // -------------------- - // HW Breakpoints - // -------------------- - // -------------------- // Stall Control // -------------------- @@ -204,7 +252,9 @@ module debug_unit ( case (CS) // CPU is running normally RUNNING: begin - // external debugger requested to halt the CPU + // 1. external debugger requested to halt the CPU + // 2. cross-trigger requested a halt + // 3. a break-point hit if (halt_req || debug_halt_i) begin NS = HALT_REQ; end @@ -236,7 +286,7 @@ module debug_unit ( NS = RUNNING; // resume from single step, check if single stepping is enabled and if the sticky bit is cleared - if (dbg_ss_q && !dbg_ssth_q) begin + if (dbg_ss_q && !dbg_hit_q) begin NS = SINGLE_STEP; end end @@ -249,19 +299,44 @@ module debug_unit ( // -------------------- 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; + CS <= RUNNING; + rdata_q <= '0; + rvalid_q <= 1'b0; + dbg_ppc_q <= 64'b0; + dbg_ie_q <= 64'b0; + dbg_cause_q <= 64'b0; + dbg_hwbp_ctrl_q <= '0; + dbg_hwbp_data_q <= '0; + dbg_ss_q <= 1'b0; + dbg_hit_q <= 1'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; + CS <= NS; + rdata_q <= rdata_n; + rvalid_q <= rvalid_n; + dbg_ppc_q <= dbg_ppc_n; + dbg_ie_q <= dbg_ie_n; + dbg_cause_q <= dbg_cause_n; + dbg_ss_q <= dbg_ss_n; + dbg_hit_q <= dbg_hit_n; + dbg_hwbp_ctrl_q <= dbg_hwbp_ctrl_n; + dbg_hwbp_data_q <= dbg_hwbp_data_n; end end + + //-------------- + // Assertions + //-------------- + + // check that no registers are accessed when we are not in debug mode + assert property ( + @(posedge clk_i) (debug_req_i) |-> ((debug_halted_o == 1'b1) || + ((debug_addr_i[14] != 1'b1) && + (debug_addr_i[13:7] != 5'b0_1001) && + (debug_addr_i[13:7] != 5'b0_1000)) ) ) + else $warning("Trying to access internal debug registers while core is not stalled"); + + // check that all accesses are word-aligned + assert property ( + @(posedge clk_i) (debug_req_i) |-> (debug_addr_i[1:0] == 2'b00) ); + endmodule