Work in progress: updates to handle stop/step/run from Debug Module

This commit is contained in:
rsnikhil
2020-01-08 20:17:50 -05:00
parent 0f04b9cbe1
commit cd779e1cbe
6 changed files with 603 additions and 11 deletions

View File

@@ -84,6 +84,8 @@ import Bypass::*;
import CsrFile :: *;
import Cur_Cycle :: *;
interface CoreReq;
method Action start(
Addr startpc,
@@ -138,6 +140,19 @@ interface Core;
// Bluespec: external interrupt to enter debug mode
method Action setDEIP (Bit #(1) v);
`ifdef INCLUDE_GDB_CONTROL
method Action halt_to_debug_mode_req;
(* always_ready *)
method Bool is_debug_halted;
method Action resume_from_debug_mode;
method Data csr_read (Bit #(12) csr_addr);
method Action csr_write (Bit #(12) csr_addr, Data data);
`endif
endinterface
// fixpoint to instantiate modules
@@ -158,7 +173,11 @@ module mkCore#(CoreId coreId)(Core);
outOfReset <= True;
endrule
Reg#(Bool) started <- mkReg(False);
Reg#(Bool) started <- mkReg(False); // only used for deadlock check
`ifdef INCLUDE_GDB_CONTROL
Reg#(Bool) rg_debug_halted <- mkReg (False);
`endif
// front end
FetchStage fetchStage <- mkFetchStage;
@@ -512,6 +531,21 @@ module mkCore#(CoreId coreId)(Core);
endinterface);
CommitStage commitStage <- mkCommitStage(commitInput);
(* mutually_exclusive = "coreFix.aluExe_0.doRegReadAlu, commitStage.rl_enter_debug_mode_flush" *)
(* mutually_exclusive = "coreFix.aluExe_1.doRegReadAlu, commitStage.rl_enter_debug_mode_flush" *)
(* mutually_exclusive = "coreFix.aluExe_0.doDispatchAlu, commitStage.rl_enter_debug_mode_flush" *)
(* mutually_exclusive = "coreFix.aluExe_1.doDispatchAlu, commitStage.rl_enter_debug_mode_flush" *)
(* mutually_exclusive = "coreFix.fpuMulDivExe_0.doFinishIntMul, commitStage.rl_enter_debug_mode_flush" *)
(* mutually_exclusive = "coreFix.fpuMulDivExe_0.doFinishIntDiv, commitStage.rl_enter_debug_mode_flush" *)
(* mutually_exclusive = "coreFix.fpuMulDivExe_0.doFinishFpFma, commitStage.rl_enter_debug_mode_flush" *)
(* mutually_exclusive = "coreFix.fpuMulDivExe_0.doFinishFpDiv, commitStage.rl_enter_debug_mode_flush" *)
(* mutually_exclusive = "coreFix.fpuMulDivExe_0.doFinishFpSqrt, commitStage.rl_enter_debug_mode_flush" *)
(* mutually_exclusive = "coreFix.fpuMulDivExe_0.doFinishFpSqrt, commitStage.rl_enter_debug_mode_flush" *)
rule rl_bogus_dummy (False);
// Just to allow the scheduling attributes above
endrule
// send rob enq time to reservation stations
(* fire_when_enabled, no_implicit_conditions *)
rule sendRobEnqTime;
@@ -903,6 +937,19 @@ module mkCore#(CoreId coreId)(Core);
endrule
`endif
`ifdef INCLUDE_GDB_CONTROL
// ================================================================
// Stopping into debug mode
rule rl_debug_halt_actions ((! rg_debug_halted) && commitStage.is_debug_halted);
$display ("%0d: %m.rl_debug_halt_actions", cur_cycle);
rg_debug_halted <= True;
endrule
`endif
// ================================================================
interface CoreReq coreReq;
method Action start(
Bit#(64) startpc,
@@ -910,6 +957,9 @@ module mkCore#(CoreId coreId)(Core);
);
fetchStage.start(startpc);
started <= True;
`ifdef INCLUDE_GDB_CONTROL
rg_debug_halted <= False;
`endif
mmio.setHtifAddrs(toHostAddr, fromHostAddr);
// start rename debug
commitStage.startRenameDebug;
@@ -980,5 +1030,38 @@ module mkCore#(CoreId coreId)(Core);
// Bluespec: external interrupt to enter debug mode
method Action setDEIP (v) = csrf.setDEIP (v);
endmodule
`ifdef INCLUDE_GDB_CONTROL
method Action halt_to_debug_mode_req () if (! rg_debug_halted);
$display ("%0d: %m.halt_to_debug_mode_req", cur_cycle);
started <= False;
fetchStage.stop;
commitStage.halt_to_debug_mode_req;
endmethod
method Bool is_debug_halted;
return rg_debug_halted;
endmethod
method Action resume_from_debug_mode if (rg_debug_halted);
let startpc = csrf.dpc_read;
fetchStage.resume_from_debug_mode (startpc);
commitStage.resume_from_debug_mode;
started <= True;
rg_debug_halted <= False;
$display ("%0d: %m.resume_from_debug_mode, dpc = 0x%0h", cur_cycle, startpc);
endmethod
// TODO_DEBUG: was part of method cond: commitStage.is_debug_halted &&
method Data csr_read (Bit #(12) csr_addr) if (rg_debug_halted);
return csrf.rd (unpack (csr_addr));
endmethod
// TODO_DEBUG: was part of method cond: commitStage.is_debug_halted &&
method Action csr_write (Bit #(12) csr_addr, Data data) if (rg_debug_halted);
csrf.csrInstWr (unpack (csr_addr), data);
endmethod
`endif
endmodule

View File

@@ -37,6 +37,8 @@ import GetPut::*;
import BuildVector::*;
//import TRNG::*;
import SoC_Map :: *;
interface CsrFile;
// Read
method Data rd(CSR csr);
@@ -90,6 +92,24 @@ interface CsrFile;
// terminate
method ActionValue#(void) terminate;
`ifdef INCLUDE_GDB_CONTROL
// Read dpc
method Addr dpc_read ();
// Update dpc
method Action dpc_write (Addr pc);
// Check whether to enter Debug Mode based on dcsr.{ebreakm, ebreaks, ebreaku}
method Bool dcsr_stop_for_break;
// Check whether to enter Debug Mode based on dcsr.step
method Bool dcsr_stop_for_step;
// Update 'cause' in DCSR
(* always_ready *)
method Action dcsr_cause_write (Bit #(3) dcsr_cause);
`endif
endinterface
// Fancy Reg functions
@@ -501,6 +521,30 @@ module mkCsrFile #(Data hartid)(CsrFile);
StatsCsr stats_module <- mkStatsCsr;
Reg#(Data) stats_csr = stats_module.reg_ifc;
`ifdef INCLUDE_GDB_CONTROL
// DCSR is 32b even in RV64
Bit #(32) dcsr_reset_value = {4'h4, // [31:28] xdebugver
12'h0, // [27:16] reserved
1'h0, // [15] ebreakm
1'h0, // [14] reserved
1'h0, // [13] ebreaks
1'h0, // [12] ebreaku
1'h0, // [11] stepie
1'h0, // [10] stopcount
1'h0, // [9] stoptime
3'h0, // [8:7] cause // WARNING: 0 is non-standard
1'h0, // [5] reserved
1'h1, // [4] mprven
1'h0, // [3] nmip // non-maskable interrupt pending
1'h0, // [2] step
2'h3}; // [1:0] prv (machine mode)
Reg #(Data) rg_dcsr <- mkReg (zeroExtend (dcsr_reset_value));
Reg #(Data) rg_dpc <- mkReg (truncate (soc_map_struct.pc_reset_value));
Reg #(Data) rg_dscratch0 <- mkRegU;
Reg #(Data) rg_dscratch1 <- mkRegU;
`endif
`ifdef SECURITY
// sanctum machine CSRs
@@ -607,6 +651,14 @@ module mkCsrFile #(Data hartid)(CsrFile);
CSRmspec: mspec_csr;
CSRtrng: trng_csr;
`endif
`ifdef INCLUDE_GDB_CONTROL
CSRdcsr: rg_dcsr; // TODO: take NMI into account (cf. Piccolo/Flute)
CSRdpc: rg_dpc;
CSRdscratch0: rg_dscratch0;
CSRdscratch1: rg_dscratch1;
`endif
default: readOnlyReg(64'b0);
endcase);
endfunction
@@ -856,4 +908,40 @@ module mkCsrFile #(Data hartid)(CsrFile);
method doPerfStats = stats_module.doPerfStats;
method sendDoStats = stats_module.sendDoStats;
method recvDoStats = stats_module.recvDoStats;
// ----------------
// Bluespec:
// Methods when Debug Module is present
`ifdef INCLUDE_GDB_CONTROL
// Read dpc
method Addr dpc_read ();
return rg_dpc;
endmethod
// Update dpc
method Action dpc_write (Addr pc);
rg_dpc <= pc;
endmethod
// Check whether to enter Debug Mode based on dcsr.{ebreakm, ebreaks, ebreaku}
method Bool dcsr_stop_for_break;
return case (prv_reg)
prvM: (rg_dcsr [15] == 1'b1);
prvS: (rg_dcsr [13] == 1'b1);
prvU: (rg_dcsr [12] == 1'b1);
endcase;
endmethod
// Check whether to enter Debug Mode based on dcsr.step
method Bool dcsr_stop_for_step;
return (rg_dcsr [2] == 1'b1);
endmethod
// Update 'cause' in DCSR
method Action dcsr_cause_write (Bit #(3) dcsr_cause);
rg_dcsr <= { 32'b0, rg_dcsr [31:9], dcsr_cause, rg_dcsr [5:2], prv_reg };
endmethod
`endif
endmodule

View File

@@ -92,6 +92,31 @@ import TV_Info :: *;
// ================================================================
// Major States of CPU
typedef enum {CPU_RESET1,
CPU_RESET2,
`ifdef INCLUDE_GDB_CONTROL
CPU_GDB_PAUSING, // On GDB breakpoint, while waiting for fence completion
`endif
CPU_DEBUG_MODE, // Stopped (normally for debugger)
CPU_RUNNING // Normal operation
} CPU_State
deriving (Eq, Bits, FShow);
function Bool fn_is_running (CPU_State cpu_state);
return ( (cpu_state != CPU_RESET1)
&& (cpu_state != CPU_RESET2)
`ifdef INCLUDE_GDB_CONTROL
&& (cpu_state != CPU_GDB_PAUSING)
&& (cpu_state != CPU_DEBUG_MODE)
`endif
);
endfunction
// ================================================================
(* synthesize *)
module mkProc (Proc_IFC);
@@ -108,6 +133,11 @@ module mkProc (Proc_IFC);
// Verbosity: 0=quiet; 1=instruction trace; 2=more detail
Reg #(Bit #(4)) cfg_verbosity <- mkConfigReg (0);
// ----------------
// Major CPU states
Reg #(CPU_State) rg_state <- mkReg (CPU_RESET1);
// ----------------
// Reset requests and responses (TODO: to be implemented)
@@ -258,6 +288,8 @@ module mkProc (Proc_IFC);
mmio_axi4_adapter.reset;
f_reset_rsps.enq (?);
rg_state <= CPU_RUNNING;
endrule
// ----------------
@@ -287,6 +319,122 @@ module mkProc (Proc_IFC);
end
endrule
// ================================================================
// ================================================================
// ================================================================
// DEBUGGER ACCESS
`ifdef INCLUDE_GDB_CONTROL
// ----------------
// Debug Module Run (resume) control
// Run command when in debug mode
rule rl_debug_run ((f_run_halt_reqs.first == True)
&& (! f_gpr_reqs.notEmpty)
&& (! f_fpr_reqs.notEmpty)
&& (! f_csr_reqs.notEmpty)
&& (rg_state == CPU_DEBUG_MODE));
// if (cfg_verbosity > 1)
$display ("%0d: %m.rl_debug_run", cur_cycle);
f_run_halt_reqs.deq;
core[0].resume_from_debug_mode;
rg_state <= CPU_RUNNING;
// Notify debugger that we've started running
f_run_halt_rsps.enq (True);
endrule
// Run command when already running
rule rl_debug_run_redundant ((f_run_halt_reqs.first == True)
&& (! f_gpr_reqs.notEmpty)
&& (! f_fpr_reqs.notEmpty)
&& (! f_csr_reqs.notEmpty)
&& fn_is_running (rg_state));
// if (cfg_verbosity > 1)
$display ("%0d: %m.rl_debug_run_redundant", cur_cycle);
f_run_halt_reqs.deq;
// Notify debugger that we're running
f_run_halt_rsps.enq (True);
endrule
// ----------------
// Debug Module Halt control
rule rl_debug_halt ((f_run_halt_reqs.first == False) && fn_is_running (rg_state));
// if (cfg_verbosity > 1)
$display ("%0d: %m.rl_debug_halt", cur_cycle);
f_run_halt_reqs.deq;
// Debugger 'halt' request (e.g., GDB '^C' command)
core[0].halt_to_debug_mode_req;
rg_state <= CPU_GDB_PAUSING;
endrule
rule rl_debug_halted ((rg_state == CPU_GDB_PAUSING) && core [0].is_debug_halted);
// Notify debugger that we've halted
f_run_halt_rsps.enq (False);
// Stop executing rules until ready to restart from debugger
rg_state <= CPU_DEBUG_MODE;
// if (cfg_verbosity > 1)
$display ("%0d: %m.rl_debug_halted", cur_cycle);
endrule
rule rl_debug_halt_redundant ((f_run_halt_reqs.first == False) && (! fn_is_running (rg_state)));
// if (cfg_verbosity > 1)
$display ("%0d: %m.rl_debug_halt_redundant", cur_cycle);
f_run_halt_reqs.deq;
// Notify debugger that we've 'halted'
f_run_halt_rsps.enq (False);
$display ("%0d: %m.rl_debug_halt_redundant: CPU already halted; state = ", cur_cycle, fshow (rg_state));
endrule
// ----------------
// Debug Module CSR read/write
rule rl_debug_read_csr ((rg_state == CPU_DEBUG_MODE) && (! f_csr_reqs.first.write));
let req <- pop (f_csr_reqs);
Bit #(12) csr_addr = req.address;
let data = core [0].csr_read (csr_addr);
let rsp = DM_CPU_Rsp {ok: True, data: data};
f_csr_rsps.enq (rsp);
// if (cur_verbosity > 1)
$display ("%m.rl_debug_read_csr: csr %0d => 0x%0h",
csr_addr, data);
endrule
rule rl_debug_write_csr ((rg_state == CPU_DEBUG_MODE) && f_csr_reqs.first.write);
let req <- pop (f_csr_reqs);
Bit #(12) csr_addr = req.address;
let data = req.data;
core [0].csr_write (csr_addr, data);
let rsp = DM_CPU_Rsp {ok: True, data: ?};
f_csr_rsps.enq (rsp);
// if (cur_verbosity > 1)
$display ("%m.rl_debug_write_csr: csr 0x%0h <= 0x%0h", csr_addr, data);
endrule
rule rl_debug_csr_access_busy (rg_state != CPU_DEBUG_MODE);
let req <- pop (f_csr_reqs);
let rsp = DM_CPU_Rsp {ok: False, data: ?};
f_csr_rsps.enq (rsp);
// if (cur_verbosity > 1)
$display ("%m.rl_debug_csr_access_busy");
endrule
`endif
// ================================================================
// ================================================================
// ================================================================
@@ -305,7 +453,7 @@ module mkProc (Proc_IFC);
mmioPlatform.start (tohostAddr, fromhostAddr);
$display ("Proc.start: startpc = 0x%0h, tohostAddr = 0x%0h, fromhostAddr = %0h",
$display ("%m.start: startpc = 0x%0h, tohostAddr = 0x%0h, fromhostAddr = %0h",
startpc, tohostAddr, fromhostAddr);
endmethod