Work in progress on Debug Module integration. Got further on start/step/halt

This commit is contained in:
rsnikhil
2020-01-12 22:25:14 -05:00
parent 1278927f51
commit 27c3c7cb4d
8 changed files with 364 additions and 334 deletions

View File

@@ -86,6 +86,12 @@ import CsrFile :: *;
import Cur_Cycle :: *;
`ifdef SECURITY
`define SECURITY_OR_INCLUDE_GDB_CONTROL
`elsif INCLUDE_GDB_CONTROL
`define SECURITY_OR_INCLUDE_GDB_CONTROL
`endif
interface CoreReq;
method Action start(
Addr startpc,
@@ -142,16 +148,15 @@ interface Core;
method Action setDEIP (Bit #(1) v);
`ifdef INCLUDE_GDB_CONTROL
method Action halt_to_debug_mode_req;
method Action debug_halt;
(* always_ready *)
method Bool is_debug_halted;
method Action resume_from_debug_mode;
method Action debug_resume;
method Data csr_read (Bit #(12) csr_addr);
method Action csr_write (Bit #(12) csr_addr, Data data);
`endif
endinterface
@@ -164,6 +169,15 @@ interface CoreFixPoint;
interface Reg#(Bool) doStatsIfc;
endinterface
typedef enum {
`ifdef INCLUDE_GDB_CONTROL
CORE_HALTING,
CORE_HALTED,
`endif
CORE_RUNNING
} Core_Run_State
deriving (Bits, Eq, FShow);
(* synthesize *)
module mkCore#(CoreId coreId)(Core);
let verbose = False;
@@ -173,10 +187,10 @@ module mkCore#(CoreId coreId)(Core);
outOfReset <= True;
endrule
Reg#(Bool) started <- mkReg(False); // only used for deadlock check
Reg#(Bool) started <- mkReg(False);
`ifdef INCLUDE_GDB_CONTROL
Reg#(Bool) rg_debug_halted <- mkReg (False);
Reg #(Core_Run_State) rg_core_run_state <- mkReg (CORE_RUNNING);
`endif
// front end
@@ -403,13 +417,15 @@ module mkCore#(CoreId coreId)(Core);
Reg#(Bool) flush_tlbs <- mkReg(False);
Reg#(Bool) update_vm_info <- mkReg(False);
Reg#(Bool) flush_reservation <- mkReg(False);
`ifdef SECURITY
`ifdef SECURITY_OR_INCLUDE_GDB_CONTROL
Reg#(Bool) flush_caches <- mkReg(False);
Reg#(Bool) flush_brpred <- mkReg(False);
`else
Reg#(Bool) flush_caches <- mkReadOnlyReg(False);
Reg#(Bool) flush_brpred <- mkReadOnlyReg(False);
`endif
`ifdef SELF_INV_CACHE
Reg#(Bool) reconcile_i <- mkReg(False);
`else
@@ -508,16 +524,48 @@ module mkCore#(CoreId coreId)(Core);
method stqEmpty = lsq.stqEmpty;
method lsqSetAtCommit = lsq.setAtCommit;
method tlbNoPendingReq = iTlb.noPendingReq && dTlb.noPendingReq;
method setFlushTlbs = flush_tlbs._write(True);
method setUpdateVMInfo = update_vm_info._write(True);
method setFlushReservation = flush_reservation._write(True);
method setFlushBrPred = flush_brpred._write(True);
method setFlushCaches = flush_caches._write(True);
method setFlushTlbs;
action
flush_tlbs <= True;
// $display ("%0d: %m.commitInput.setFlushTlbs", cur_cycle);
endaction
endmethod
method setUpdateVMInfo;
action
update_vm_info <= True;
// $display ("%0d: %m.commitInput.setUpdateVMInfo", cur_cycle);
endaction
endmethod
method setFlushReservation;
action
flush_reservation <= True;
// $display ("%0d: %m.commitInput.setFlushReservation", cur_cycle);
endaction
endmethod
method setFlushBrPred;
action
flush_brpred <= True;
// $display ("%0d: %m.commitInput.setFlushBrPred", cur_cycle);
endaction
endmethod
method setFlushCaches;
action
flush_caches <= True;
// $display ("%0d: %m.commitInput.setFlushCaches", cur_cycle);
endaction
endmethod
method setReconcileI = reconcile_i._write(True);
method setReconcileD = reconcile_d._write(True);
method killAll = coreFix.killAll;
method redirectPc = fetchStage.redirect;
method setFetchWaitRedirect = fetchStage.setWaitRedirect;
method setFetchWaitFlush = fetchStage.setWaitFlush;
method incrementEpoch = epochManager.incrementEpoch;
method commitCsrInstOrInterrupt = csrInstOrInterruptInflight_commit._write(False);
method doStats = coreFix.doStatsIfc._read;
@@ -531,21 +579,6 @@ 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;
@@ -575,11 +608,13 @@ module mkCore#(CoreId coreId)(Core);
if (flush_reservation) begin
flush_reservation <= False;
dMem.resetLinkAddr;
// $display ("%0d: %m.rule prepareCachesAndTlbs: flushing reservation", cur_cycle);
end
if (flush_tlbs) begin
flush_tlbs <= False;
iTlb.flush;
dTlb.flush;
// $display ("%0d: %m.rule prepareCachesAndTlbs: flushing iTlb and dTlb", cur_cycle);
end
if (update_vm_info) begin
update_vm_info <= False;
@@ -588,10 +623,11 @@ module mkCore#(CoreId coreId)(Core);
iTlb.updateVMInfo(vmI);
dTlb.updateVMInfo(vmD);
l2Tlb.updateVMInfo(vmI, vmD);
// $display ("%0d: %m.rule prepareCachesAndTlbs: updating VMInfo", cur_cycle);
end
endrule
`ifdef SECURITY
`ifdef SECURITY_OR_INCLUDE_GDB_CONTROL
// Use wires to capture flush regs and empty signals. This is ok because
// there cannot be any activity to make empty -> not-empty or need-flush ->
// no-need-flush when we are trying to flush.
@@ -600,6 +636,7 @@ module mkCore#(CoreId coreId)(Core);
rule setDoFlushCaches(flush_caches && fetchStage.emptyForFlush && lsq.noWrongPathLoads);
doFlushCaches.send;
$display ("%0d: %m.rl_setDoFlushCaches", cur_cycle);
endrule
rule setDoFlushBrPred(flush_brpred && fetchStage.emptyForFlush);
@@ -612,6 +649,7 @@ module mkCore#(CoreId coreId)(Core);
flush_caches <= False;
iMem.flush;
dMem.flush;
$display ("%0d: %m.rule flushCaches (imem and dmem)", cur_cycle);
endrule
// security flush branch predictors: wait for wrong path inst fetches to
@@ -619,6 +657,7 @@ module mkCore#(CoreId coreId)(Core);
rule flushBrPred(doFlushBrPred);
flush_brpred <= False;
fetchStage.flush_predictors;
$display ("%0d: %m.rule flushBrPred", cur_cycle);
endrule
`endif
@@ -663,9 +702,12 @@ module mkCore#(CoreId coreId)(Core);
`endif // SELF_INV_CACHE
rule readyToFetch(
`ifdef INCLUDE_GDB_CONTROL
(rg_core_run_state == CORE_RUNNING) &&
`endif
!flush_reservation && !flush_tlbs && !update_vm_info
&& iTlb.flush_done && dTlb.flush_done
`ifdef SECURITY
`ifdef SECURITY_OR_INCLUDE_GDB_CONTROL
&& !flush_caches && !flush_brpred
&& iMem.flush_done && dMem.flush_done
&& fetchStage.flush_predictors_done
@@ -680,6 +722,50 @@ module mkCore#(CoreId coreId)(Core);
fetchStage.done_flushing();
endrule
`ifdef INCLUDE_GDB_CONTROL
rule rl_debug_halting((rg_core_run_state == CORE_HALTING) &&
!flush_reservation && !flush_tlbs && !update_vm_info
&& iTlb.flush_done && dTlb.flush_done
&& !flush_caches && !flush_brpred
&& iMem.flush_done && dMem.flush_done
&& fetchStage.flush_predictors_done
`ifdef SELF_INV_CACHE
&& !reconcile_i && iMem.reconcile_done
`ifdef SYSTEM_SELF_INV_L1D
&& !reconcile_d
`endif
`endif
&& commitStage.is_debug_halted
);
fetchStage.done_flushing();
rg_core_run_state <= CORE_HALTED;
$display ("%0d: %m.rl_debug_halting", cur_cycle);
endrule
`endif
/*
`ifdef INCLUDE_GDB_CONTROL
// TODO: DELETE AFTER DEBUGGING
rule rl_flushing_conditions (rg_core_run_state == CORE_HALTING);
$display ("%0d: %m.rl_done_flushing_for_debug_halt", cur_cycle);
$display (" !flush_reservation = %0d, !flush_tlbs = %0d, !update_vm_info = %0d",
!flush_reservation, !flush_tlbs, !update_vm_info);
$display (" iTlb.flush_done = %0d, dTlb.flush_done = %0d", iTlb.flush_done, dTlb.flush_done);
$display (" !flush_caches = %0d !flush_brpred = %0d", !flush_caches, !flush_brpred);
$display (" iMem.flush_done = %0d dMem.flush_done = %0d", iMem.flush_done, dMem.flush_done);
$display (" fetchStage.flush_predictors_done = %0d", fetchStage.flush_predictors_done);
`ifdef SELF_INV_CACHE
$display (" !reconcile_i = %0d, iMem.reconcide_done = %0d", !reconcile_i, iMem.reconcile_done);
`ifdef SYSTEM_SELF_INV_L1D
$display (" reconcile_d = %0d", reconcile_d);
`endif
`endif
endrule
`endif
*/
`ifdef PERF_COUNT
// incr cycle count
(* fire_when_enabled, no_implicit_conditions *)
@@ -937,19 +1023,6 @@ 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,
@@ -958,7 +1031,7 @@ module mkCore#(CoreId coreId)(Core);
fetchStage.start(startpc);
started <= True;
`ifdef INCLUDE_GDB_CONTROL
rg_debug_halted <= False;
rg_core_run_state <= CORE_RUNNING;
`endif
mmio.setHtifAddrs(toHostAddr, fromHostAddr);
// start rename debug
@@ -1032,34 +1105,34 @@ module mkCore#(CoreId coreId)(Core);
method Action setDEIP (v) = csrf.setDEIP (v);
`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);
method Action debug_halt () if (started && (rg_core_run_state == CORE_RUNNING));
$display ("%0d: %m.debug_halt", cur_cycle);
started <= False;
fetchStage.stop;
commitStage.halt_to_debug_mode_req;
renameStage.debug_halt; // start the halt protocol
rg_core_run_state <= CORE_HALTING;
endmethod
method Bool is_debug_halted;
return rg_debug_halted;
return (rg_core_run_state == CORE_HALTED);
endmethod
method Action resume_from_debug_mode if (rg_debug_halted);
method Action debug_resume () if (rg_core_run_state == CORE_HALTED);
renameStage.debug_resume;
commitStage.debug_resume;
let startpc = csrf.dpc_read;
fetchStage.resume_from_debug_mode (startpc);
commitStage.resume_from_debug_mode;
started <= True;
rg_debug_halted <= False;
fetchStage.redirect (startpc);
$display ("%0d: %m.resume_from_debug_mode, dpc = 0x%0h", cur_cycle, startpc);
started <= True;
rg_core_run_state <= CORE_RUNNING;
$display ("%0d: %m.debug_resume, 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);
method Data csr_read (Bit #(12) csr_addr) if (rg_core_run_state == CORE_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);
method Action csr_write (Bit #(12) csr_addr, Data data) if (rg_core_run_state == CORE_HALTED);
csrf.csrInstWr (unpack (csr_addr), data);
endmethod
`endif

View File

@@ -101,10 +101,10 @@ interface CsrFile;
method Action dpc_write (Addr pc);
// Check whether to enter Debug Mode based on dcsr.{ebreakm, ebreaks, ebreaku}
method Bool dcsr_stop_for_break;
method Bit #(1) dcsr_break_bit;
// Check whether to enter Debug Mode based on dcsr.step
method Bool dcsr_stop_for_step;
// Read dcsr[2], the step bit
method Bit #(1) dcsr_step_bit;
// Update 'cause' in DCSR
(* always_ready *)
@@ -539,10 +539,11 @@ module mkCsrFile #(Data hartid)(CsrFile);
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;
// RV64: dcsr's upper 32b zeroExtended/ignored
Reg #(Data) rg_dcsr <- mkConfigReg (zeroExtend (dcsr_reset_value));
Reg #(Data) rg_dpc <- mkConfigReg (truncate (soc_map_struct.pc_reset_value));
Reg #(Data) rg_dscratch0 <- mkConfigRegU;
Reg #(Data) rg_dscratch1 <- mkConfigRegU;
`endif
`ifdef SECURITY
@@ -925,17 +926,17 @@ module mkCsrFile #(Data hartid)(CsrFile);
endmethod
// Check whether to enter Debug Mode based on dcsr.{ebreakm, ebreaks, ebreaku}
method Bool dcsr_stop_for_break;
method Bit #(1) dcsr_break_bit;
return case (prv_reg)
prvM: (rg_dcsr [15] == 1'b1);
prvS: (rg_dcsr [13] == 1'b1);
prvU: (rg_dcsr [12] == 1'b1);
prvM: rg_dcsr [15];
prvS: rg_dcsr [13];
prvU: rg_dcsr [12];
endcase;
endmethod
// Check whether to enter Debug Mode based on dcsr.step
method Bool dcsr_stop_for_step;
return (rg_dcsr [2] == 1'b1);
method Bit #(1) dcsr_step_bit;
return rg_dcsr [2];
endmethod
// Update 'cause' in DCSR

View File

@@ -77,42 +77,29 @@ import SoC_Map :: *;
import AXI4_Types :: *;
import Fabric_Defs :: *;
`ifdef INCLUDE_TANDEM_VERIF
import TV_Info :: *;
`endif
`ifdef INCLUDE_GDB_CONTROL
import DM_CPU_Req_Rsp :: *;
`endif
`ifdef INCLUDE_TANDEM_VERIF
import TV_Info :: *;
`endif
`ifdef EXTERNAL_DEBUG_MODULE
`undef INCLUDE_GDB_CONTROL
`endif
// ================================================================
// CPU run-states
// TODO: Reset from GDB etc.
// Major States of CPU
typedef enum {CPU_RESET1,
CPU_RESET2,
typedef enum {CPU_RUNNING // Normal operation
`ifdef INCLUDE_GDB_CONTROL
CPU_GDB_PAUSING, // On GDB breakpoint, while waiting for fence completion
,
CPU_ENTERING_DEBUG_MODE, // On GDB breakpoint, while waiting for fence completion
CPU_DEBUG_MODE // Halted for debugger
`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
);
return (cpu_state == CPU_RUNNING);
endfunction
// ================================================================
@@ -134,9 +121,9 @@ module mkProc (Proc_IFC);
Reg #(Bit #(4)) cfg_verbosity <- mkConfigReg (0);
// ----------------
// Major CPU states
// CPU run/debug states
Reg #(CPU_State) rg_state <- mkReg (CPU_RESET1);
Reg #(CPU_State) rg_state <- mkReg (CPU_RUNNING);
// ----------------
// Reset requests and responses (TODO: to be implemented)
@@ -144,21 +131,14 @@ module mkProc (Proc_IFC);
FIFOF #(Bit #(0)) f_reset_reqs <- mkFIFOF;
FIFOF #(Bit #(0)) f_reset_rsps <- mkFIFOF;
`ifdef INCLUDE_GDB_CONTROL
// ----------------
// Communication to/from External debug module (TODO: to be implemented)
`ifdef INCLUDE_GDB_CONTROL
// Debugger run-control
FIFOF #(Bool) f_run_halt_reqs <- mkFIFOF;
FIFOF #(Bool) f_run_halt_rsps <- mkFIFOF;
// Stop-request from debugger (e.g., GDB ^C or Dsharp 'stop')
Reg #(Bool) rg_stop_req <- mkReg (False);
// Count instrs after step-request from debugger (via dcsr.step)
Reg #(Bit #(1)) rg_step_count <- mkReg (0);
// Debugger GPR read/write request/response
FIFOF #(DM_CPU_Req #(5, XLEN)) f_gpr_reqs <- mkFIFOF1;
FIFOF #(DM_CPU_Rsp #(XLEN)) f_gpr_rsps <- mkFIFOF1;
@@ -288,8 +268,6 @@ module mkProc (Proc_IFC);
mmio_axi4_adapter.reset;
f_reset_rsps.enq (?);
rg_state <= CPU_RUNNING;
endrule
// ----------------
@@ -339,7 +317,7 @@ module mkProc (Proc_IFC);
$display ("%0d: %m.rl_debug_run", cur_cycle);
f_run_halt_reqs.deq;
core[0].resume_from_debug_mode;
core[0].debug_resume;
rg_state <= CPU_RUNNING;
// Notify debugger that we've started running
@@ -365,18 +343,18 @@ module mkProc (Proc_IFC);
// Debug Module Halt control
rule rl_debug_halt ((f_run_halt_reqs.first == False) && fn_is_running (rg_state));
// if (cfg_verbosity > 1)
// 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;
core[0].debug_halt;
rg_state <= CPU_GDB_PAUSING;
rg_state <= CPU_ENTERING_DEBUG_MODE;
endrule
rule rl_debug_halted ((rg_state == CPU_GDB_PAUSING) && core [0].is_debug_halted);
rule rl_debug_halted ((rg_state == CPU_ENTERING_DEBUG_MODE) && 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
@@ -401,7 +379,7 @@ module mkProc (Proc_IFC);
// ----------------
// Debug Module CSR read/write
rule rl_debug_read_csr ((rg_state == CPU_DEBUG_MODE) && (! f_csr_reqs.first.write));
rule rl_debug_csr_read ((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);
@@ -412,7 +390,7 @@ module mkProc (Proc_IFC);
csr_addr, data);
endrule
rule rl_debug_write_csr ((rg_state == CPU_DEBUG_MODE) && f_csr_reqs.first.write);
rule rl_debug_csr_write ((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;
@@ -432,7 +410,6 @@ module mkProc (Proc_IFC);
// if (cur_verbosity > 1)
$display ("%m.rl_debug_csr_access_busy");
endrule
`endif
// ================================================================
@@ -453,7 +430,7 @@ module mkProc (Proc_IFC);
mmioPlatform.start (tohostAddr, fromhostAddr);
$display ("%m.start: startpc = 0x%0h, tohostAddr = 0x%0h, fromhostAddr = %0h",
$display ("Proc.start: startpc = 0x%0h, tohostAddr = 0x%0h, fromhostAddr = %0h",
startpc, tohostAddr, fromhostAddr);
endmethod

View File

@@ -88,6 +88,7 @@ interface CommitInput;
method Action killAll;
method Action redirectPc(Addr trap_pc);
method Action setFetchWaitRedirect;
method Action setFetchWaitFlush;
method Action incrementEpoch;
// record if we commit a CSR inst or interrupt
method Action commitCsrInstOrInterrupt;
@@ -116,14 +117,8 @@ interface CommitStage;
interface Get#(RenameErrInfo) renameErr;
`ifdef INCLUDE_GDB_CONTROL
// Request halt into debug mode
method Action halt_to_debug_mode_req;
(* always_ready *)
// Becomes true when pipeline is halted
method Bool is_debug_halted;
method Action resume_from_debug_mode;
method Action debug_resume;
`endif
endinterface
@@ -136,17 +131,16 @@ typedef struct {
Trap trap;
} CommitTrap deriving(Bits, Eq, FShow);
// Bluespec: for debugger run-control
typedef enum {
Run_State_RUNNING // Normal state
`ifdef INCLUDE_GDB_CONTROL
, Run_State_DEBUGGER_HALT // When ready to halt for debugger after stop/step
, Run_State_DEBUGGER_HALT_FLUSH // When flushing state during debugger halt
, Run_State_DEBUGGER_HALTED // When halted for debugger
`endif
typedef enum {
RUN_STATE_RUNNING, // Normal state
RUN_STATE_DEBUGGER_HALTED // When halted for debugger
} Run_State
deriving (Eq, FShow, Bits);
`endif
module mkCommitStage#(CommitInput inIfc)(CommitStage);
Bool verbose = False;
@@ -154,15 +148,9 @@ module mkCommitStage#(CommitInput inIfc)(CommitStage);
Integer verbosity = 1;
Reg #(Bit #(64)) rg_instret <- mkReg (0);
// Bluespec: for debugger run-control
Reg #(Run_State) rg_run_state <- mkReg (Run_State_RUNNING);
`ifdef INCLUDE_GDB_CONTROL
// rg_stop_req is set True when debugger requests a stop (e.g., GDB ^C)
Reg #(Bool) rg_stop_req <- mkReg (False);
// When going into debug mode, these hold the cause for the break and the resume-PC
Reg #(Bit #(3)) rg_debug_cause <- mkRegU;
Reg #(Addr) rg_debug_pc <- mkRegU;
Reg #(Run_State) rg_run_state <- mkReg (RUN_STATE_RUNNING);
`endif
// func units
@@ -375,22 +363,44 @@ module mkCommitStage#(CommitInput inIfc)(CommitStage);
endfunction
`ifdef INCLUDE_GDB_CONTROL
// ================================================================
// Bluespec: debugger run-control
// Every time an instruction commits, we check this boolean
// to decide whether we continue running of stop.
// Maintain system consistency when halting into debug mode
// This code is patterned after 'makeSystemConsistent' above
function Action makeSystemConsistent_for_debug_mode;
action
inIfc.setFlushTlbs;
// We halt after committing an instruction if:
// the debugger requested a stop
// or dcsr.step is True
// notify TLB to keep update of CSR changes
inIfc.setUpdateVMInfo;
// always wait store buffer and SQ to be empty
when(inIfc.stbEmpty && inIfc.stqEmpty, noAction);
// We wait TLB to finish all requests and become sync with memory.
// Notice that currently TLB is read only, so TLB is always in sync
// with memory (i.e., there is no write to commit to memory). Since all
// insts have been killed, nothing can be issued to D TLB at this time.
// Since fetch stage is set to wait for redirect, fetch1 stage is
// stalled, and nothing can be issued to I TLB at this time.
// Therefore, we just need to make sure that I and D TLBs are not
// handling any miss req. Besides, when I and D TLBs do not have any
// miss req, L2 TLB must be idling.
when(inIfc.tlbNoPendingReq, noAction);
// yield load reservation in cache
inIfc.setFlushReservation;
Maybe #(Bit #(3)) m_debug_stop_step_cause = ( rg_stop_req
? tagged Valid 3 // Debug Module haltreq
: (csrf.dcsr_stop_for_step
? tagged Valid 4 // dcsr.step
: tagged Invalid));
inIfc.setFlushBrPred;
inIfc.setFlushCaches;
// ================================================================
`ifdef SELF_INV_CACHE
// reconcile I$
if(reconcileI) begin
inIfc.setReconcileI;
end
`ifdef SYSTEM_SELF_INV_L1D
// FIXME is this reconcile of D$ necessary?
inIfc.setReconcileD;
`endif
`endif
endaction
endfunction
`endif
// TODO Currently we don't check spec bits == 0 when we commit an
@@ -400,12 +410,11 @@ module mkCommitStage#(CommitInput inIfc)(CommitStage);
rule doCommitTrap_flush(
`ifdef INCLUDE_GDB_CONTROL
(rg_run_state == Run_State_RUNNING) &&& // Bluespec: debugger run-control
(rg_run_state == RUN_STATE_RUNNING) &&&
`endif
!isValid(commitTrap) &&&
rob.deqPort[0].deq_data.trap matches tagged Valid .trap
);
$display ("%0d: %m.CommitStage.rule_doCommitTrap_flush", cur_cycle);
rob.deqPort[0].deq;
let x = rob.deqPort[0].deq_data;
if(verbose) $display("[doCommitTrap] ", fshow(x));
@@ -463,15 +472,12 @@ module mkCommitStage#(CommitInput inIfc)(CommitStage);
doAssert(x.spec_bits == 0, "cannot have spec bits");
endrule
// This rule's condition is enabled only by the previous rule, doCommitTrap_flush
rule doCommitTrap_handle(
`ifdef INCLUDE_GDB_CONTROL
(rg_run_state == Run_State_RUNNING) &&& // Bluespec: debugger run-control
(rg_run_state == RUN_STATE_RUNNING) &&&
`endif
commitTrap matches tagged Valid .trap);
$display ("%0d: %m.CommitStage.rule_doCommitTrap_handle", cur_cycle);
// reset commitTrap
commitTrap <= Invalid;
@@ -480,44 +486,58 @@ module mkCommitStage#(CommitInput inIfc)(CommitStage);
inIfc.commitCsrInstOrInterrupt;
end
`ifdef INCLUDE_GDB_CONTROL
if ((trap.trap == tagged Exception Breakpoint) && csrf.dcsr_stop_for_break) begin
// Don't handle the trap
rg_run_state <= Run_State_DEBUGGER_HALTED;
// Record debug CSRs for later Debugger query and later resumption
csrf.dcsr_cause_write (1); // EBREAK dcsr.cause
csrf.dpc_write (trap.pc); // Where we'll resume on 'continue'
end
else begin
// Handle the trap and redirect
let new_pc <- csrf.trap(trap.trap, trap.pc, trap.addr);
inIfc.redirectPc (new_pc);
Bool debugger_halt = False;
if (m_debug_stop_step_cause matches tagged Valid .cause) begin
rg_run_state <= Run_State_DEBUGGER_HALTED;
// Record debug CSRs for later Debugger query and later resumption
csrf.dcsr_cause_write (cause);
csrf.dpc_write (new_pc); // Where we'll resume on 'continue'
`ifdef INCLUDE_GDB_CONTROL
if ((trap.trap == tagged Interrupt DebugHalt)
|| (trap.trap == tagged Interrupt DebugStep)
|| ((trap.trap == tagged Exception Breakpoint) && (csrf.dcsr_break_bit == 1'b1)))
begin
debugger_halt = True;
// Flush everything (tlbs, caches, reservation, branch predictor);
// reconcilei and I; update VM info.
makeSystemConsistent_for_debug_mode;
// Save values in debugger CSRs
Bit #(3) dcsr_cause = ( (trap.trap == tagged Interrupt DebugHalt)
? 3
: ( (trap.trap == tagged Interrupt DebugStep)
? 4
: 1));
csrf.dcsr_cause_write (dcsr_cause);
csrf.dpc_write (trap.pc);
// Tell fetch stage to wait for redirect
// Note: rule doCommitTrap_flush may have done this already; redundant call is ok.
inIfc.setFetchWaitRedirect;
inIfc.setFetchWaitFlush;
// Go to quiescent state until debugger resumes execution
rg_run_state <= RUN_STATE_DEBUGGER_HALTED;
$display ("%0d: %m.commitStage.doCommitTrap_handle; debugger halt:", cur_cycle);
end
end
`else
// trap handling & redirect
let new_pc <- csrf.trap(trap.trap, trap.pc, trap.addr);
inIfc.redirectPc(new_pc);
`endif
// system consistency
// TODO spike flushes TLB here, but perhaps it is because spike's TLB
// does not include prv info, and it has to flush when prv changes.
// XXX As approximation, Trap may cause context switch, so flush for
// security
makeSystemConsistent(False, True, False);
if (! debugger_halt) begin
// trap handling & redirect
let new_pc <- csrf.trap(trap.trap, trap.pc, trap.addr);
inIfc.redirectPc(new_pc);
// system consistency
// TODO spike flushes TLB here, but perhaps it is because spike's TLB
// does not include prv info, and it has to flush when prv changes.
// XXX As approximation, Trap may cause context switch, so flush for
// security
makeSystemConsistent(False, True, False);
end
endrule
// commit misspeculated load
rule doCommitKilledLd(
`ifdef INCLUDE_GDB_CONTROL
(rg_run_state == Run_State_RUNNING) &&& // Bluespec: debugger run-control
(rg_run_state == RUN_STATE_RUNNING) &&&
`endif
!isValid(commitTrap) &&&
!isValid(rob.deqPort[0].deq_data.trap) &&&
@@ -529,19 +549,7 @@ module mkCommitStage#(CommitInput inIfc)(CommitStage);
// kill everything, redirect, and increment epoch
inIfc.killAll;
`ifdef INCLUDE_GDB_CONTROL
// Bluespec: debug run-control
doAssert (x.iType != Ebreak, "CommitStage.rule_doCommitKilledLd iType should not be Ebreak");
if (m_debug_stop_step_cause matches tagged Valid .cause) begin
rg_run_state <= Run_State_DEBUGGER_HALT_FLUSH;
rg_debug_pc <= x.pc;
rg_debug_cause <= cause;
end
else
`endif
inIfc.redirectPc(x.pc); // original (no debugger)
inIfc.redirectPc(x.pc);
inIfc.incrementEpoch;
// the killed Ld should have claimed phy reg, we should not commit it;
@@ -566,7 +574,7 @@ module mkCommitStage#(CommitInput inIfc)(CommitStage);
// commit system inst
rule doCommitSystemInst(
`ifdef INCLUDE_GDB_CONTROL
(rg_run_state == Run_State_RUNNING) && // Bluespec: debugger run-control
(rg_run_state == RUN_STATE_RUNNING) &&
`endif
!isValid(commitTrap) &&
!isValid(rob.deqPort[0].deq_data.trap) &&
@@ -617,18 +625,7 @@ module mkCommitStage#(CommitInput inIfc)(CommitStage);
else if(x.iType == Mret) begin
next_pc <- csrf.mret;
end
`ifdef INCLUDE_GDB_CONTROL
// Bluespec: debug run-control
doAssert (x.iType != Ebreak, "CommitStage.rule_doCommitSystemInst iType should not be Ebreak");
if (m_debug_stop_step_cause matches tagged Valid .cause) begin
rg_run_state <= Run_State_DEBUGGER_HALT_FLUSH;
rg_debug_pc <= next_pc;
rg_debug_cause <= cause;
end
else
`endif
inIfc.redirectPc(next_pc); // original (no debugger)
inIfc.redirectPc(next_pc);
// rename stage only sends out system inst when ROB is empty, so no
// need to flush ROB again
@@ -685,9 +682,6 @@ module mkCommitStage#(CommitInput inIfc)(CommitStage);
// Lr/Sc/Amo/MMIO cannot proceed to executed until we notify LSQ that it
// has reached the commit stage
rule notifyLSQCommit(
`ifdef INCLUDE_GDB_CONTROL
(rg_run_state == Run_State_RUNNING) && // Bluespec: debugger run-control
`endif
!isValid(commitTrap) &&
!isValid(rob.deqPort[0].deq_data.trap) &&
!isValid(rob.deqPort[0].deq_data.ldKilled) &&
@@ -707,7 +701,7 @@ module mkCommitStage#(CommitInput inIfc)(CommitStage);
// commit normal: fire when at least one commit can be done
rule doCommitNormalInst(
`ifdef INCLUDE_GDB_CONTROL
(rg_run_state == Run_State_RUNNING) && // Bluespec: debugger run-control
(rg_run_state == RUN_STATE_RUNNING) &&
`endif
!isValid(commitTrap) &&
!isValid(rob.deqPort[0].deq_data.trap) &&
@@ -720,10 +714,6 @@ module mkCommitStage#(CommitInput inIfc)(CommitStage);
// 2. inst is not ready to commit
Bool stop = False;
// Bluespec: debugger run-control
// 3. one instr is committed and debugger halt is requested (due to stop or step)
Bool stop_for_debugger = False;
// We merge writes on FPU csr and apply writes at the end of the rule
Bit#(5) fflags = 0;
Bool will_dirty_fpu_state = False;
@@ -748,8 +738,7 @@ module mkCommitStage#(CommitInput inIfc)(CommitStage);
// compute what actions to take
for(Integer i = 0; i < valueof(SupSize); i = i+1) begin
if(!stop && (! stop_for_debugger) && rob.deqPort[i].canDeq) begin
if(!stop && rob.deqPort[i].canDeq) begin
let x = rob.deqPort[i].deq_data;
let inst_tag = rob.deqPort[i].getDeqInstTag;
@@ -802,35 +791,6 @@ module mkCommitStage#(CommitInput inIfc)(CommitStage);
comUserInstCnt = comUserInstCnt + 1; // user space inst
end
`ifdef INCLUDE_GDB_CONTROL
if (m_debug_stop_step_cause matches tagged Valid .cause
&&& (comInstCnt != 0))
begin
$display ("%0d: %m.CommitStage.rule_doCommitNormalInst: Stopping for debugger", cur_cycle);
stop_for_debugger = True;
// Compute next PC in case of debugger stop.
// Note: AluExePipeline.rule_doFinishAlu does inIfc.rob_setExecuted (... x.controlFlow)
// which updates the rob entry's ppc_vaddr_csrData field with actual
// branch/jump targets, which we retrieve here.
Addr next_pc = ?;
if (x.ppc_vaddr_csrData matches tagged PPC .addr
&&& ((x.iType == J) || (x.iType == Jr) || (x.iType == Br)))
// JAL, JALR, BRANCH
next_pc = addr;
else if (x.orig_inst [1:0] == 2'b11)
// RV32I RV64I
next_pc = x.pc + 4;
else
// RVC
next_pc = x.pc + 2;
rg_run_state <= Run_State_DEBUGGER_HALT_FLUSH;
rg_debug_pc <= next_pc;
rg_debug_cause <= cause;
end
`endif
`ifdef PERF_COUNT
// performance counter
case(x.iType)
@@ -846,7 +806,7 @@ module mkCommitStage#(CommitInput inIfc)(CommitStage);
`endif
end
end
end // for-loop for superscalar width
end
rg_instret <= rg_instret + instret;
// write FPU csr
@@ -894,48 +854,6 @@ module mkCommitStage#(CommitInput inIfc)(CommitStage);
`endif
endrule
`ifdef INCLUDE_GDB_CONTROL
// ================================================================
// Rules to move into debug mode
// This rule is like rule doCommitTrap_flush, i.e., a debugger-halt is like an interrupt
rule rl_enter_debug_mode_flush (rg_run_state == Run_State_DEBUGGER_HALT_FLUSH);
$write ("%0d: %m.commitStage.rl_enter_debug_mode:", cur_cycle);
if (rg_debug_cause == 1) $display (" EBREAK");
else if (rg_debug_cause == 3) $display (" Debugger halt request");
else if (rg_debug_cause == 4) $display (" Halt after step");
else $display (" Unknown cause %0d", rg_debug_cause);
// flush everything. Only increment epoch and stall fetch when we haven
// not done it yet (we may have already done them at rename stage)
inIfc.killAll;
inIfc.incrementEpoch;
inIfc.setFetchWaitRedirect;
rg_run_state <= Run_State_DEBUGGER_HALT;
endrule
// This rule is like rule doCommitTrap_handle, except we don't redirect
rule rl_enter_debug_mode_halt (rg_run_state == Run_State_DEBUGGER_HALT);
// system consistency
// TODO spike flushes TLB here, but perhaps it is because spike's TLB
// does not include prv info, and it has to flush when prv changes.
// XXX As approximation, Trap may cause context switch, so flush for
// security
makeSystemConsistent(False, True, False);
// Record debug CSRs for later Debugger query and later resumption
csrf.dcsr_cause_write (rg_debug_cause); // reason for entering debug mode
csrf.dpc_write (rg_debug_pc); // Where we'll resume on 'continue'
// Go to HALTED state where no rule fires.
// To re-start, mkCore must call restart method.
rg_run_state <= Run_State_DEBUGGER_HALTED;
endrule
// ================================================================
`endif
method Data getPerf(ComStagePerfType t);
return (case(t)
`ifdef PERF_COUNT
@@ -986,21 +904,13 @@ module mkCommitStage#(CommitInput inIfc)(CommitStage);
`endif
`ifdef INCLUDE_GDB_CONTROL
// Request halt into debug mode
method Action halt_to_debug_mode_req () if (rg_run_state == Run_State_RUNNING);
$display ("%0d: %m.commitStage.halt_to_debug_mode_req", cur_cycle);
rg_stop_req <= True;
endmethod
// Becomes true when pipeline is halted
method Bool is_debug_halted;
return (rg_run_state == Run_State_DEBUGGER_HALTED);
return (rg_run_state == RUN_STATE_DEBUGGER_HALTED);
endmethod
method Action resume_from_debug_mode () if (rg_run_state == Run_State_DEBUGGER_HALTED);
$display ("%0d: %m.commitStage.resume_from_debug_mode", cur_cycle);
rg_stop_req <= False;
rg_run_state <= Run_State_RUNNING;
method Action debug_resume () if (rg_run_state == RUN_STATE_DEBUGGER_HALTED);
rg_run_state <= RUN_STATE_RUNNING;
$display ("%0d: %m.commitStage.debug_resume", cur_cycle);
endmethod
`endif

View File

@@ -50,7 +50,7 @@ import CCTypes::*;
import L1CoCache::*;
import MMIOInst::*;
import Cur_Cycle :: *;
import Cur_Cycle :: *;
// ================================================================
// For fv_decode_C function and related types and definitions
@@ -76,6 +76,9 @@ interface FetchStage;
// redirection methods
method Action setWaitRedirect;
method Action redirect(Addr pc);
`ifdef INCLUDE_GDB_CONTROL
method Action setWaitFlush;
`endif
method Action done_flushing();
method Action train_predictors(
Addr pc, Addr next_pc, IType iType, Bool taken,
@@ -92,10 +95,6 @@ interface FetchStage;
// performance
interface Perf#(DecStagePerfType) perf;
`ifdef INCLUDE_GDB_CONTROL
method Action resume_from_debug_mode (Addr new_pc);
`endif
endinterface
typedef struct {
@@ -990,7 +989,6 @@ module mkFetchStage(FetchStage);
interface mmioIfc = mmio.toCore;
method Action start(Addr start_pc);
$display ("%0d: %m.start (start_pc = 0x%0h)", cur_cycle, start_pc);
pc_reg[0] <= start_pc;
started <= True;
waitForRedirect <= False;
@@ -998,7 +996,6 @@ module mkFetchStage(FetchStage);
endmethod
method Action stop();
started <= False;
$display ("%0d: %m.stop", cur_cycle);
endmethod
method Action setWaitRedirect;
@@ -1017,6 +1014,14 @@ module mkFetchStage(FetchStage);
// we conservatively set wait for flush TODO make this an input parameter
waitForFlush <= True;
endmethod
`ifdef INCLUDE_GDB_CONTROL
method Action setWaitFlush;
waitForFlush <= True;
$display ("%0d.%m.FetchStage.setWaitFlush", cur_cycle);
endmethod
`endif
method Action done_flushing() if (waitForFlush);
// signal that the pipeline can resume fetching
waitForFlush <= False;
@@ -1103,24 +1108,5 @@ module mkFetchStage(FetchStage);
method Bool respValid = perfReqQ.notEmpty;
`endif
endinterface
`ifdef INCLUDE_GDB_CONTROL
method Action resume_from_debug_mode (Addr new_pc);
if (verbose)
$display("resume_from_debug_mode: newpc %h, old f_main_epoch %d, new f_main_epoch %d",
new_pc, f_main_epoch, f_main_epoch + 1);
pc_reg[pc_redirect_port] <= new_pc;
f_main_epoch <= (f_main_epoch == fromInteger(valueOf(NumEpochs)-1)) ? 0 : f_main_epoch + 1;
ehr_pending_straddle[1] <= tagged Invalid;
// redirect comes, stop stalling for redirect
waitForRedirect <= False;
setWaitRedirect_redirect_conflict.wset(?); // conflict with setWaitForRedirect
// this redirect may be caused by a trap/system inst in commit stage
// we conservatively set wait for flush TODO make this an input parameter
// TODO: do we need this? waitForFlush <= True;
endmethod
`endif
endmodule

View File

@@ -36,6 +36,7 @@
`define a True
`define f True
`define d True
`define c True
//`define NUM_CORES 1 // defined in make file

View File

@@ -48,6 +48,8 @@ import ReservationStationMem::*;
import ReservationStationFpuMulDiv::*;
import SplitLSQ::*;
import Cur_Cycle :: *;
typedef struct {
FetchDebugState fetch;
EpochDebugState epoch;
@@ -83,6 +85,11 @@ interface RenameStage;
// deadlock check
interface Get#(RenameStuck) renameInstStuck;
interface Get#(RenameStuck) renameCorrectPathStuck;
`ifdef INCLUDE_GDB_CONTROL
method Action debug_halt;
method Action debug_resume;
`endif
endinterface
module mkRenameStage#(RenameInput inIfc)(RenameStage);
@@ -153,6 +160,23 @@ module mkRenameStage#(RenameInput inIfc)(RenameStage);
endrule
`endif
`ifdef INCLUDE_GDB_CONTROL
// Is set to Valid DebugHalt on debugger halt request
// Is set to Valid DebugStep on dcsr[stepbit]==1 and one instruction has been processed.
// Note (step): 1st instruction is guaranteed architectural, cannot possibly be speculative.
// Note (step): 1st instruction may trap; we halt pointing at the trap vector
Reg #(Maybe #(Interrupt)) rg_m_halt_req <- mkReg (tagged Invalid);
function Action fa_step_check;
action
if (csrf.dcsr_step_bit == 1'b1) begin
rg_m_halt_req <= tagged Valid DebugStep;
$display ("%0d: %m.fa_step_check: rg_m_halt_req <= tagged Valid DebugStep", cur_cycle);
end
endaction
endfunction
`endif
// kill wrong path inst
// XXX we have to make this a separate rule instead of merging it with rename correct path
// This is because the rename correct path rule is conflict with other rules that redirect
@@ -234,6 +258,13 @@ module mkRenameStage#(RenameInput inIfc)(RenameStage);
&& (mstatus_tw == 1'b1)
&& (csrf.decodeInfo.prv < prvM));
`ifdef INCLUDE_GDB_CONTROL
if (rg_m_halt_req matches tagged Valid .cause) begin
// Stop due to debugger halt or step
trap = tagged Valid (tagged Interrupt cause);
end else
`endif
if (isValid(x.cause)) begin
// previously found exception
trap = tagged Valid (tagged Exception fromMaybe(?, x.cause));
@@ -273,6 +304,14 @@ module mkRenameStage#(RenameInput inIfc)(RenameStage);
&& rob.isEmpty // stall for ROB empty
);
fetchStage.pipelines[0].deq;
`ifdef INCLUDE_GDB_CONTROL
fa_step_check;
if (firstTrap == tagged Valid (tagged Interrupt DebugHalt))
$display ("%0d: %m.doRenaming_Trap: DebugHalt", cur_cycle);
else if (firstTrap == tagged Valid (tagged Interrupt DebugStep))
$display ("%0d: %m.doRenaming_Trap: DebugStep", cur_cycle);
`endif
let x = fetchStage.pipelines[0].first;
let pc = x.pc;
let orig_inst = x.orig_inst;
@@ -379,6 +418,9 @@ module mkRenameStage#(RenameInput inIfc)(RenameStage);
&& rob.isEmpty // stall for ROB empty
);
fetchStage.pipelines[0].deq;
`ifdef INCLUDE_GDB_CONTROL
fa_step_check;
`endif
let x = fetchStage.pipelines[0].first;
let pc = x.pc;
let orig_inst = x.orig_inst;
@@ -522,6 +564,9 @@ module mkRenameStage#(RenameInput inIfc)(RenameStage);
&& rob.isEmpty // stall for ROB empty to process mem inst
);
fetchStage.pipelines[0].deq;
`ifdef INCLUDE_GDB_CONTROL
fa_step_check;
`endif
let x = fetchStage.pipelines[0].first;
let pc = x.pc;
let orig_inst = x.orig_inst;
@@ -685,6 +730,11 @@ module mkRenameStage#(RenameInput inIfc)(RenameStage);
// (c) It is system inst (we handle system inst in a separate rule)
// (d) It does not have enough resource
Bool stop = False;
`ifdef INCLUDE_GDB_CONTROL
// (e) One rename has been done and dcsr.step is set
Bool debug_step = False;
`endif
// We automatically stop after an inst cannot be deq from fetch stage
// because canDeq signal for sup-fifo is consecutive
@@ -733,6 +783,13 @@ module mkRenameStage#(RenameInput inIfc)(RenameStage);
Addr fallthrough_pc = ((orig_inst[1:0] == 2'b11) ? pc + 4 : pc + 2);
`ifdef INCLUDE_GDB_CONTROL
if ((i != 0) && (csrf.dcsr_step_bit == 1'b1)) begin
stop = True;
debug_step = True;
end
`endif
// check for wrong path, if wrong path, don't process it, leave to the other rule in next cycle
if(!epochManager.checkEpoch[i].check(main_epoch)) begin
stop = True;
@@ -986,6 +1043,11 @@ module mkRenameStage#(RenameInput inIfc)(RenameStage);
end
end
`ifdef INCLUDE_GDB_CONTROL
if (debug_step)
rg_m_halt_req <= tagged Valid DebugStep;
`endif
// only fire this rule if we make some progress
// otherwise this rule may block other rules forever
when(doCorrectPath, noAction);
@@ -1026,4 +1088,17 @@ module mkRenameStage#(RenameInput inIfc)(RenameStage);
default: 0;
endcase);
endmethod
`ifdef INCLUDE_GDB_CONTROL
method Action debug_halt () if (rg_m_halt_req == tagged Invalid);
rg_m_halt_req <= tagged Valid DebugHalt;
$display ("%0d: %m.renameStage.debug_halt", cur_cycle);
endmethod
method Action debug_resume () if (rg_m_halt_req != tagged Invalid);
rg_m_halt_req <= tagged Invalid;
$display ("%0d: %m.renameStage.debug_resume", cur_cycle);
endmethod
`endif
endmodule

View File

@@ -99,7 +99,7 @@ typedef struct {
instance DefaultValue#(RiscVISASubset);
function RiscVISASubset defaultValue = RiscVISASubset {
s: True, u: True,
m: `m , a: `a , f: `f , d: `d
m: `m , a: `a , f: `f , d: `d, c: `c
};
endinstance
@@ -454,13 +454,20 @@ typedef enum {
MachineTimer = 4'd7,
UserExternal = 4'd8,
SupervisorExternel = 4'd9,
MachineExternal = 4'd11,
MachineExternal = 4'd11
`ifdef INCLUDE_GDB_CONTROL
, DebugHalt = 4'd14, // Debugger halt command (^C in GDB)
DebugStep = 4'd15 // dcsr.step is set and 1 instr has been processed
`endif
DebugExternal = 4'd14 // Bluespec: for debug mode
} Interrupt deriving(Bits, Eq, FShow);
// typedef 12 InterruptNum;
typedef 15 InterruptNum; // Bluespec: extended to 15 bits for debug interrupt
`ifdef INCLUDE_GDB_CONTROL
typedef 16 InterruptNum; // With debugger
`else
typedef 12 InterruptNum; // Without debugger
`endif
// Traps are either an exception or an interrupt
typedef union tagged {