Fix debug module reset state machine

dmactive should only go low when the debug module has successfully
reset. Approximate this by waiting for 1024 cycles, allowing any
register access requests and system bus requests to come back.
This commit is contained in:
Peter Rugg
2024-09-16 16:10:02 +01:00
parent 6fc7327b93
commit 1cfc58c2cc
3 changed files with 143 additions and 123 deletions

View File

@@ -26,6 +26,8 @@ DM_Addr max_DM_Addr = 'h5F;
typedef Bit #(32) DM_Word; typedef Bit #(32) DM_Word;
typedef Bit #(10) DM_Reset_Count;
// ================================================================ // ================================================================
// Debug Module address map // Debug Module address map

View File

@@ -47,7 +47,7 @@ import ProcTypes :: *;
// Interface // Interface
interface DM_Run_Control_IFC; interface DM_Run_Control_IFC;
method Bool dmactive; method Bool dmactive_cleared;
method Action reset; method Action reset;
// ---------------- // ----------------
@@ -111,6 +111,8 @@ module mkDM_Run_Control (DM_Run_Control_IFC);
Reg #(Bool) rg_dmcontrol_ndmreset <- mkRegU; Reg #(Bool) rg_dmcontrol_ndmreset <- mkRegU;
Reg #(Bool) rg_dmcontrol_dmactive <- mkReg (False); Reg #(Bool) rg_dmcontrol_dmactive <- mkReg (False);
Reg #(Bit#(20)) rg_dmcontrol_hartsel <- mkReg (0); Reg #(Bit#(20)) rg_dmcontrol_hartsel <- mkReg (0);
// Whether the user has attempted to clear dmactive since last reset
Reg #(Bool) rg_dmactive_cleared <- mkReg (False);
Bit#(20) core_num_sel = fromInteger(valueOf(CoreNum)); Bit#(20) core_num_sel = fromInteger(valueOf(CoreNum));
@@ -193,7 +195,6 @@ module mkDM_Run_Control (DM_Run_Control_IFC);
rg_dmcontrol_haltreq <= haltreq; rg_dmcontrol_haltreq <= haltreq;
rg_dmcontrol_hartreset <= hartreset; rg_dmcontrol_hartreset <= hartreset;
rg_dmcontrol_ndmreset <= ndmreset; rg_dmcontrol_ndmreset <= ndmreset;
rg_dmcontrol_dmactive <= dmactive;
rg_dmcontrol_hartsel <= hartsel; rg_dmcontrol_hartsel <= hartsel;
// Debug Module reset // Debug Module reset
@@ -214,88 +215,90 @@ module mkDM_Run_Control (DM_Run_Control_IFC);
$display (" dmactive has priority; ignoring hartreset"); $display (" dmactive has priority; ignoring hartreset");
end end
// No action here; other rules will fire (see method dmactive, Debug_Module.rl_reset) rg_dmactive_cleared <= True;
noAction;
end
// Ignore if NDM reset is in progress end else begin
else if (rg_ndm_reset_pending) begin rg_dmcontrol_dmactive <= True;
$display ("%0d: %m.dmcontrol_write 0x%0h: ndm reset in progress; ignoring this write",
cur_cycle, dm_word);
end
// Non-Debug-Module reset (platform reset) posedge: ignore // Ignore if NDM reset is in progress
else if ((! rg_dmcontrol_ndmreset) && ndmreset) begin if (rg_ndm_reset_pending) begin
if (verbosity != 0) $display ("%0d: %m.dmcontrol_write 0x%0h: ndm reset in progress; ignoring this write",
$display ("%0d: %m.dmcontrol_write 0x%08h: ndmreset: 0->1: ignoring", cur_cycle, dm_word);
cur_cycle, dm_word);
end
// Non-Debug-Module reset (platform reset) negedge: do it
else if (rg_dmcontrol_ndmreset && (! ndmreset)) begin
Bool running = (! haltreq);
if (verbosity != 0) begin
$display ("%0d: %m.dmcontrol_write 0x%08h: ndmreset: 1->0: resetting platform",
cur_cycle, dm_word);
$display (" Requested 'running' state = ", fshow (running));
end end
f_ndm_reset_reqs.enq (running); // Non-Debug-Module reset (platform reset) posedge: ignore
rg_ndm_reset_pending <= True; else if ((! rg_dmcontrol_ndmreset) && ndmreset) begin
if (verbosity != 0)
// Error-checking $display ("%0d: %m.dmcontrol_write 0x%08h: ndmreset: 0->1: ignoring",
if (hartreset) begin cur_cycle, dm_word);
$display (" WARNING: %m.dmcontrol_write 0x%08h:", dm_word);
$display (" Both ndmreset [1] and hartreset [29] are asserted");
$display (" ndmreset has priority; ignoring hartreset");
end end
end // Non-Debug-Module reset (platform reset) negedge: do it
else if (rg_dmcontrol_ndmreset && (! ndmreset)) begin
Bool running = (! haltreq);
if (verbosity != 0) begin
$display ("%0d: %m.dmcontrol_write 0x%08h: ndmreset: 1->0: resetting platform",
cur_cycle, dm_word);
$display (" Requested 'running' state = ", fshow (running));
end
// Hart reset f_ndm_reset_reqs.enq (running);
else if (hartreset) begin rg_ndm_reset_pending <= True;
Bool running = (! haltreq);
f_harts_reset_reqs[hartsel].enq (running); // Error-checking
rg_harts_hasreset[hartsel] <= True; if (hartreset) begin
$display (" WARNING: %m.dmcontrol_write 0x%08h:", dm_word);
$display (" Both ndmreset [1] and hartreset [29] are asserted");
$display (" ndmreset has priority; ignoring hartreset");
end
// Deassert platform reset
if (verbosity != 0) begin
$display ("%0d: %m.dmcontrol_write 0x%08h: hartreset=1: resetting hart",
cur_cycle, dm_word);
$display (" Requested 'running' state = ", fshow (running));
end end
end
// run/halt commands // Hart reset
else begin else if (hartreset) begin
// Deassert hart reset Bool running = (! haltreq);
if ((verbosity != 0) && rg_dmcontrol_hartreset) f_harts_reset_reqs[hartsel].enq (running);
$display ("%0d: %m.dmcontrol_write 0x%08h: clearing hartreset", rg_harts_hasreset[hartsel] <= True;
cur_cycle, dm_word);
if (hasel) // Deassert platform reset
$display ("%0d:ERROR: %m.dmcontrol_write 0x%08h: hasel is not supported", if (verbosity != 0) begin
cur_cycle, dm_word); $display ("%0d: %m.dmcontrol_write 0x%08h: hartreset=1: resetting hart",
cur_cycle, dm_word);
if (hartsel >= core_num_sel) $display (" Requested 'running' state = ", fshow (running));
$display ("%0d:WARNING: %m.dmcontrol_write 0x%08h: hartsel 0x%0h refers to non-existent hart", end
cur_cycle, dm_word, hartsel);
if (haltreq && resumereq) begin
$display ("%0d:ERROR: %m.dmcontrol_write 0x%08h: haltreq=1 and resumereq=1",
cur_cycle, dm_word);
$display (" This behavior is 'undefined' in the spec; ignoring");
end end
// Resume hart(s) if not running
else if (resumereq && (! rg_harts_running[hartsel])) begin // run/halt commands
f_harts_run_halt_reqs[hartsel].enq (True); else begin
rg_harts_resumeack[hartsel] <= False; // Deassert hart reset
$display ("%0d: %m.dmcontrol_write: hart %0d resume request", cur_cycle, hartsel); if ((verbosity != 0) && rg_dmcontrol_hartreset)
end $display ("%0d: %m.dmcontrol_write 0x%08h: clearing hartreset",
// Halt hart(s) cur_cycle, dm_word);
else if (haltreq && rg_harts_running[hartsel]) begin
f_harts_run_halt_reqs[hartsel].enq (False); if (hasel)
$display ("%0d: %m.dmcontrol_write: hart %0d halt request", cur_cycle, hartsel); $display ("%0d:ERROR: %m.dmcontrol_write 0x%08h: hasel is not supported",
cur_cycle, dm_word);
if (hartsel >= core_num_sel)
$display ("%0d:WARNING: %m.dmcontrol_write 0x%08h: hartsel 0x%0h refers to non-existent hart",
cur_cycle, dm_word, hartsel);
if (haltreq && resumereq) begin
$display ("%0d:ERROR: %m.dmcontrol_write 0x%08h: haltreq=1 and resumereq=1",
cur_cycle, dm_word);
$display (" This behavior is 'undefined' in the spec; ignoring");
end
// Resume hart(s) if not running
else if (resumereq && (! rg_harts_running[hartsel])) begin
f_harts_run_halt_reqs[hartsel].enq (True);
rg_harts_resumeack[hartsel] <= False;
$display ("%0d: %m.dmcontrol_write: hart %0d resume request", cur_cycle, hartsel);
end
// Halt hart(s)
else if (haltreq && rg_harts_running[hartsel]) begin
f_harts_run_halt_reqs[hartsel].enq (False);
$display ("%0d: %m.dmcontrol_write: hart %0d halt request", cur_cycle, hartsel);
end
end end
end end
endaction endaction
@@ -355,8 +358,8 @@ module mkDM_Run_Control (DM_Run_Control_IFC);
// ---------------------------------------------------------------- // ----------------------------------------------------------------
// INTERFACE // INTERFACE
method Bool dmactive; method Bool dmactive_cleared;
return rg_dmcontrol_dmactive; return rg_dmactive_cleared;
endmethod endmethod
method Action reset; method Action reset;
@@ -375,7 +378,9 @@ module mkDM_Run_Control (DM_Run_Control_IFC);
rg_dmcontrol_haltreq <= False; rg_dmcontrol_haltreq <= False;
rg_dmcontrol_hartreset <= False; rg_dmcontrol_hartreset <= False;
rg_dmcontrol_ndmreset <= False; rg_dmcontrol_ndmreset <= False;
rg_dmcontrol_dmactive <= True; // DM module is now active rg_dmcontrol_dmactive <= False; // Debug module stays inactive so debugger can confirm it has reset
rg_dmactive_cleared <= False;
writeVReg(rg_harts_hasreset, replicate(False)); writeVReg(rg_harts_hasreset, replicate(False));
writeVReg(rg_harts_resumeack, replicate(False)); writeVReg(rg_harts_resumeack, replicate(False));

View File

@@ -150,6 +150,8 @@ module mkDebug_Module (Debug_Module_IFC);
// Local verbosity: 0 = quiet; 1 = print DMI transactions // Local verbosity: 0 = quiet; 1 = print DMI transactions
Integer verbosity = 0; Integer verbosity = 0;
Reg #(Maybe#(DM_Reset_Count)) rg_reset_count <- mkReg(Valid(~0));
// The three parts // The three parts
DM_Run_Control_IFC dm_run_control <- mkDM_Run_Control; DM_Run_Control_IFC dm_run_control <- mkDM_Run_Control;
DM_Abstract_Commands_IFC dm_abstract_commands <- mkDM_Abstract_Commands; DM_Abstract_Commands_IFC dm_abstract_commands <- mkDM_Abstract_Commands;
@@ -158,13 +160,22 @@ module mkDebug_Module (Debug_Module_IFC);
FIFO#(DM_Addr) f_read_addr <- mkFIFO1; FIFO#(DM_Addr) f_read_addr <- mkFIFO1;
// ================================================================ // ================================================================
// Reset all three parts when dm_run_control.dmactive is low // Reset all three parts: triggered when dm_run_control.dmactive is low
rule rl_reset (! dm_run_control.dmactive); rule rl_reset_start (dm_run_control.dmactive_cleared && rg_reset_count == Invalid);
$display ("%0d: Debug_Module reset", cur_cycle); rg_reset_count <= Valid(~0);
endrule
rule rl_reset_wait (rg_reset_count matches tagged Valid .c &&& c != 0);
rg_reset_count <= Valid(c - 1);
endrule
rule rl_reset_done (rg_reset_count == Valid(0));
$display ("%0d: Debug_Module reset complete", cur_cycle);
dm_run_control.reset; dm_run_control.reset;
dm_abstract_commands.reset; dm_abstract_commands.reset;
dm_system_bus.reset; dm_system_bus.reset;
rg_reset_count <= Invalid;
endrule endrule
// ================================================================ // ================================================================
@@ -174,7 +185,7 @@ module mkDebug_Module (Debug_Module_IFC);
// Facing GDB/DMI (Debug Module Interface) // Facing GDB/DMI (Debug Module Interface)
interface DMI dmi; interface DMI dmi;
method Action read_addr (DM_Addr dm_addr) if (dm_run_control.dmactive); method Action read_addr (DM_Addr dm_addr);
f_read_addr.enq(dm_addr); f_read_addr.enq(dm_addr);
if (verbosity != 0) if (verbosity != 0)
@@ -241,58 +252,60 @@ module mkDebug_Module (Debug_Module_IFC);
return dm_word; return dm_word;
endmethod endmethod
method Action write (DM_Addr dm_addr, DM_Word dm_word) if (dm_run_control.dmactive); method Action write (DM_Addr dm_addr, DM_Word dm_word);
Bool handled = False; Bool handled = False;
if ( (dm_addr == dm_addr_dmcontrol) if (rg_reset_count == Invalid) begin
|| (dm_addr == dm_addr_dmstatus) if ( (dm_addr == dm_addr_dmcontrol)
|| (dm_addr == dm_addr_hartinfo) || (dm_addr == dm_addr_dmstatus)
|| (dm_addr == dm_addr_haltsum0) || (dm_addr == dm_addr_hartinfo)
|| (dm_addr == dm_addr_hawindowsel) || (dm_addr == dm_addr_haltsum0)
|| (dm_addr == dm_addr_hawindow) || (dm_addr == dm_addr_hawindowsel)
|| (dm_addr == dm_addr_devtreeaddr0) || (dm_addr == dm_addr_hawindow)
|| (dm_addr == dm_addr_authdata) || (dm_addr == dm_addr_devtreeaddr0)
|| (dm_addr == dm_addr_verbosity)) begin || (dm_addr == dm_addr_authdata)
|| (dm_addr == dm_addr_verbosity)) begin
dm_run_control.write (dm_addr, dm_word); dm_run_control.write (dm_addr, dm_word);
handled = True; handled = True;
end end
if ( (dm_addr == dm_addr_dmcontrol) if ( (dm_addr == dm_addr_dmcontrol)
|| (dm_addr == dm_addr_abstractcs) || (dm_addr == dm_addr_abstractcs)
|| (dm_addr == dm_addr_command) || (dm_addr == dm_addr_command)
|| (dm_addr == dm_addr_data0) || (dm_addr == dm_addr_data0)
|| (dm_addr == dm_addr_data1) || (dm_addr == dm_addr_data1)
|| (dm_addr == dm_addr_data2) || (dm_addr == dm_addr_data2)
|| (dm_addr == dm_addr_data3) || (dm_addr == dm_addr_data3)
|| (dm_addr == dm_addr_data4) || (dm_addr == dm_addr_data4)
|| (dm_addr == dm_addr_data5) || (dm_addr == dm_addr_data5)
|| (dm_addr == dm_addr_data6) || (dm_addr == dm_addr_data6)
|| (dm_addr == dm_addr_data7) || (dm_addr == dm_addr_data7)
|| (dm_addr == dm_addr_data8) || (dm_addr == dm_addr_data8)
|| (dm_addr == dm_addr_data9) || (dm_addr == dm_addr_data9)
|| (dm_addr == dm_addr_data10) || (dm_addr == dm_addr_data10)
|| (dm_addr == dm_addr_data11) || (dm_addr == dm_addr_data11)
|| (dm_addr == dm_addr_abstractauto) || (dm_addr == dm_addr_abstractauto)
|| (dm_addr == dm_addr_progbuf0)) begin || (dm_addr == dm_addr_progbuf0)) begin
dm_abstract_commands.write (dm_addr, dm_word); dm_abstract_commands.write (dm_addr, dm_word);
handled = True; handled = True;
end end
if ( (dm_addr == dm_addr_sbcs) if ( (dm_addr == dm_addr_sbcs)
|| (dm_addr == dm_addr_sbaddress0) || (dm_addr == dm_addr_sbaddress0)
|| (dm_addr == dm_addr_sbaddress1) || (dm_addr == dm_addr_sbaddress1)
|| (dm_addr == dm_addr_sbaddress2) || (dm_addr == dm_addr_sbaddress2)
|| (dm_addr == dm_addr_sbdata0) || (dm_addr == dm_addr_sbdata0)
|| (dm_addr == dm_addr_sbdata1) || (dm_addr == dm_addr_sbdata1)
|| (dm_addr == dm_addr_sbdata2) || (dm_addr == dm_addr_sbdata2)
|| (dm_addr == dm_addr_sbdata3)) begin || (dm_addr == dm_addr_sbdata3)) begin
dm_system_bus.write (dm_addr, dm_word); dm_system_bus.write (dm_addr, dm_word);
handled = True; handled = True;
end end
end
if (! handled) begin if (! handled) begin
// TODO: set error status? // TODO: set error status?