mirror of
https://github.com/openhwgroup/cva6.git
synced 2025-04-23 05:37:16 -04:00
Implement hardware break-points
This commit is contained in:
parent
b352a55106
commit
67b97d12da
2 changed files with 123 additions and 61 deletions
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue