Merge remote-tracking branch 'origin/Debug_Module'

Debug Module mostly working (except resume-after-breakpoint).
This commit is contained in:
rsnikhil
2020-01-16 14:41:22 -05:00
12 changed files with 900 additions and 135 deletions

View File

@@ -84,6 +84,25 @@ import Bypass::*;
import CsrFile :: *;
// ================================================================
// Toooba
import Cur_Cycle :: *;
import FIFOF :: *;
import GetPut_Aux :: *;
`ifdef INCLUDE_GDB_CONTROL
import DM_CPU_Req_Rsp :: *;
`endif
// ================================================================
`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,
@@ -138,6 +157,15 @@ interface Core;
// Bluespec: external interrupt to enter debug mode
method Action setDEIP (Bit #(1) v);
`ifdef INCLUDE_GDB_CONTROL
interface Server #(Bool, Bool) hart0_run_halt_server;
interface Server #(DM_CPU_Req #(5, 64), DM_CPU_Rsp #(64)) hart0_gpr_mem_server;
`ifdef ISA_F
interface Server #(DM_CPU_Req #(5, 64), DM_CPU_Rsp #(64)) hart0_fpr_mem_server;
`endif
interface Server #(DM_CPU_Req #(12, 64), DM_CPU_Rsp #(64)) hart0_csr_mem_server;
`endif
endinterface
// fixpoint to instantiate modules
@@ -149,6 +177,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;
@@ -160,6 +197,11 @@ module mkCore#(CoreId coreId)(Core);
Reg#(Bool) started <- mkReg(False);
`ifdef INCLUDE_GDB_CONTROL
// Using a ConfigReg since scheduling of reads/writes not critical (TODO: verify this)
Reg #(Core_Run_State) rg_core_run_state <- mkConfigReg (CORE_RUNNING);
`endif
// front end
FetchStage fetchStage <- mkFetchStage;
ITlb iTlb = fetchStage.iTlbIfc;
@@ -384,13 +426,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
@@ -477,6 +521,9 @@ module mkCore#(CoreId coreId)(Core);
`endif
endmethod
method doStats = coreFix.doStatsIfc._read;
`ifdef INCLUDE_GDB_CONTROL
method Bool core_is_running = (rg_core_run_state == CORE_RUNNING);
`endif
endinterface);
RenameStage renameStage <- mkRenameStage(renameInput);
@@ -489,16 +536,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;
@@ -541,11 +620,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;
@@ -554,10 +635,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.
@@ -566,6 +648,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);
@@ -578,6 +661,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
@@ -585,6 +669,7 @@ module mkCore#(CoreId coreId)(Core);
rule flushBrPred(doFlushBrPred);
flush_brpred <= False;
fetchStage.flush_predictors;
$display ("%0d: %m.rule flushBrPred", cur_cycle);
endrule
`endif
@@ -629,9 +714,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
@@ -644,8 +732,36 @@ module mkCore#(CoreId coreId)(Core);
`endif
);
fetchStage.done_flushing();
`ifdef INCLUDE_GDB_CONTROL
if (commitStage.is_debug_halted) begin
started <= False;
rg_core_run_state <= CORE_HALTING;
$display ("%0d: %m.rule readyToFetch: halting for debug mode", cur_cycle);
end
`endif
endrule
/*
rule rl_readyToFetch_conds_debug
$display ("%0d: %m.rl_readyToFetch_conds_debug:", 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);
`ifdef SECURITY_OR_INCLUDE_GDB_CONTROL
$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);
`endif
`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
*/
`ifdef PERF_COUNT
// incr cycle count
(* fire_when_enabled, no_implicit_conditions *)
@@ -903,6 +1019,268 @@ module mkCore#(CoreId coreId)(Core);
endrule
`endif
`ifdef INCLUDE_GDB_CONTROL
// ================================================================
// DEBUG MODULE INTERFACE
Bool show_DM_interactions = True; // for debugging the interactions
// ----------------------------------------------------------------
// Debug Module GPR read/write
FIFOF #(DM_CPU_Req #(5, 64)) f_gpr_reqs <- mkFIFOF1;
FIFOF #(DM_CPU_Rsp #(64)) f_gpr_rsps <- mkFIFOF1;
rule rl_debug_gpr_read ( (rg_core_run_state == CORE_HALTED)
&& f_gpr_reqs.notEmpty
&& (! f_gpr_reqs.first.write));
let req <- pop (f_gpr_reqs);
Bit #(5) regnum = req.address;
let arch_regs = ArchRegs {src1: tagged Valid (tagged Gpr regnum),
src2: tagged Invalid,
src3: tagged Invalid,
dst: tagged Invalid};
let rename_result = regRenamingTable.rename[0].getRename (arch_regs);
let phy_rindx = fromMaybe (?, rename_result.phy_regs.src1);
let data_out = rf.read [debuggerPort].rd1 (phy_rindx);
let rsp = DM_CPU_Rsp {ok: True, data: data_out};
f_gpr_rsps.enq (rsp);
if (show_DM_interactions)
$display ("%0d: %m.rl_debug_read_gpr: reg %0d => 0x%0h", cur_cycle, regnum, data_out);
endrule
rule rl_debug_gpr_write ( (rg_core_run_state == CORE_HALTED)
&& f_gpr_reqs.notEmpty
&& f_gpr_reqs.first.write);
let req <- pop (f_gpr_reqs);
Bit #(5) regnum = req.address;
let data_in = req.data;
let arch_regs = ArchRegs {src1: tagged Valid (tagged Gpr regnum),
src2: tagged Invalid,
src3: tagged Invalid,
dst: tagged Invalid};
let rename_result = regRenamingTable.rename[0].getRename (arch_regs);
let phy_rindx = fromMaybe (?, rename_result.phy_regs.src1);
rf.write [debuggerPort].wr (phy_rindx, data_in);
let rsp = DM_CPU_Rsp {ok: True, data: ?};
f_gpr_rsps.enq (rsp);
if (show_DM_interactions)
$display ("%0d: %m.rl_debug_gpr_write: reg %0d <= 0x%0h (phy_rindx = %0d)",
cur_cycle, regnum, data_in, phy_rindx);
endrule
rule rl_debug_gpr_access_busy (rg_core_run_state == CORE_RUNNING);
let req <- pop (f_gpr_reqs);
let rsp = DM_CPU_Rsp {ok: False, data: ?};
f_gpr_rsps.enq (rsp);
if (show_DM_interactions)
$display ("%0d: %m.rl_debug_gpr_access_busy", cur_cycle);
endrule
`ifdef ISA_F
// ----------------------------------------------------------------
// Debug Module FPR read/write
FIFOF #(DM_CPU_Req #(5, 64)) f_fpr_reqs <- mkFIFOF1;
FIFOF #(DM_CPU_Rsp #(64)) f_fpr_rsps <- mkFIFOF1;
rule rl_debug_fpr_read ( (rg_core_run_state == CORE_HALTED)
&& (! f_gpr_reqs.notEmpty) // prioritize gpr reqs
&& (! f_fpr_reqs.first.write));
let req <- pop (f_fpr_reqs);
Bit #(5) regnum = req.address;
let arch_regs = ArchRegs {src1: tagged Valid (tagged Fpu regnum),
src2: tagged Invalid,
src3: tagged Invalid,
dst: tagged Invalid};
let rename_result = regRenamingTable.rename[0].getRename (arch_regs);
let phy_rindx = fromMaybe (?, rename_result.phy_regs.src1);
let data_out = rf.read [debuggerPort].rd1 (phy_rindx);
let rsp = DM_CPU_Rsp {ok: True, data: data_out};
f_fpr_rsps.enq (rsp);
if (show_DM_interactions)
$display ("%0d: %m.rl_debug_read_fpr: reg %0d => 0x%0h", cur_cycle, regnum, data_out);
endrule
rule rl_debug_fpr_write ( (rg_core_run_state == CORE_HALTED)
&& (! f_gpr_reqs.notEmpty) // prioritize gpr reqs
&& f_fpr_reqs.first.write);
let req <- pop (f_fpr_reqs);
Bit #(5) regnum = req.address;
let data_in = req.data;
let arch_regs = ArchRegs {src1: tagged Valid (tagged Fpu regnum),
src2: tagged Invalid,
src3: tagged Invalid,
dst: tagged Invalid};
let rename_result = regRenamingTable.rename[0].getRename (arch_regs);
let phy_rindx = fromMaybe (?, rename_result.phy_regs.src1);
rf.write [debuggerPort].wr (phy_rindx, data_in);
let rsp = DM_CPU_Rsp {ok: True, data: ?};
f_fpr_rsps.enq (rsp);
if (show_DM_interactions)
$display ("%0d: %m.rl_debug_write_fpr: reg %0d <= 0x%0h (phy_rindx %0d)",
cur_cycle, regnum, data_in, phy_rindx);
endrule
rule rl_debug_fpr_access_busy ( (rg_core_run_state == CORE_RUNNING)
&& f_fpr_reqs.notEmpty);
let req <- pop (f_fpr_reqs);
let rsp = DM_CPU_Rsp {ok: False, data: ?};
f_fpr_rsps.enq (rsp);
if (show_DM_interactions)
$display ("%0d: %m.rl_debug_fpr_access_busy", cur_cycle);
endrule
`endif
// ----------------------------------------------------------------
// Debug Module CSR read/write
// Debugger CSR read/write request/response
FIFOF #(DM_CPU_Req #(12, 64)) f_csr_reqs <- mkFIFOF1;
FIFOF #(DM_CPU_Rsp #(64)) f_csr_rsps <- mkFIFOF1;
rule rl_debug_csr_read ( (rg_core_run_state == CORE_HALTED)
&& (! f_csr_reqs.first.write));
let req <- pop (f_csr_reqs);
Bit #(12) csr_addr = req.address;
let data_out = csrf.rd (unpack (csr_addr));
let rsp = DM_CPU_Rsp {ok: True, data: data_out};
f_csr_rsps.enq (rsp);
if (show_DM_interactions)
$display ("%0d: %m.rl_debug_read_csr: csr %0d => 0x%0h", cur_cycle, csr_addr, data_out);
endrule
rule rl_debug_csr_write ( (rg_core_run_state == CORE_HALTED)
&& f_csr_reqs.first.write);
let req <- pop (f_csr_reqs);
Bit #(12) csr_addr = req.address;
let data_in = req.data;
csrf.csrInstWr (unpack (csr_addr), data_in);
let rsp = DM_CPU_Rsp {ok: True, data: ?};
f_csr_rsps.enq (rsp);
if (show_DM_interactions)
$display ("%0d: %m.rl_debug_write_csr: csr 0x%0h <= 0x%0h", cur_cycle, csr_addr, data_in);
endrule
rule rl_debug_csr_access_busy (rg_core_run_state == CORE_RUNNING);
let req <- pop (f_csr_reqs);
let rsp = DM_CPU_Rsp {ok: False, data: ?};
f_csr_rsps.enq (rsp);
if (show_DM_interactions)
$display ("%0d: %m.rl_debug_csr_access_busy", cur_cycle);
endrule
// ----------------------------------------------------------------
// Debug Module run-halt control
FIFOF #(Bool) f_run_halt_reqs <- mkFIFOF;
FIFOF #(Bool) f_run_halt_rsps <- mkFIFOF;
Reg #(Bool) rg_sent_halt_rsp <- mkReg (False);
// ----------------
// Debug Module Halt control
rule rl_debug_halt_req ( (rg_core_run_state == CORE_RUNNING)
&& (f_run_halt_reqs.first == False));
f_run_halt_reqs.deq;
// Debugger 'halt' request (e.g., GDB '^C' command)
// This is initiated just like an interrupt.
renameStage.debug_halt_req;
rg_sent_halt_rsp <= False;
if (show_DM_interactions)
$display ("%0d: %m.rl_debug_halt_req", cur_cycle);
endrule
rule rl_debug_halt_req_already_halted ( (rg_core_run_state != CORE_RUNNING)
&& (f_run_halt_reqs.first == False));
f_run_halt_reqs.deq;
// Notify debugger that we've 'halted'
f_run_halt_rsps.enq (False);
if (show_DM_interactions)
$display ("%0d: %m.rl_debug_halt_req_already_halted", cur_cycle);
endrule
// Monitors when we've reached halted state while running
// (due to halt, step or EBREAK) and notifies DM
rule rl_debug_halted (rg_core_run_state == CORE_HALTING);
// Notify debugger that we've halted
f_run_halt_rsps.enq (False);
rg_core_run_state <= CORE_HALTED;
if (show_DM_interactions)
$display ("%0d: %m.rl_debug_halted", cur_cycle);
endrule
// ----------------
// Debug Module Resume (run) control
// Resume command when in debug mode
rule rl_debug_resume ( (rg_core_run_state == CORE_HALTED)
&& (f_run_halt_reqs.first == True)
// prioritise gpr/fpr/csr read/write requests before resuming
&& (! f_gpr_reqs.notEmpty)
`ifdef ISA_F
&& (! f_fpr_reqs.notEmpty)
`endif
&& (! f_csr_reqs.notEmpty));
f_run_halt_reqs.deq;
let startpc = csrf.dpc_read;
fetchStage.redirect (startpc);
renameStage.debug_resume;
commitStage.debug_resume;
started <= True;
rg_core_run_state <= CORE_RUNNING;
// Notify debugger that we've started running
f_run_halt_rsps.enq (True);
if (show_DM_interactions)
$display ("%0d: %m.debug_resume, dpc = 0x%0h", cur_cycle, startpc);
endrule
// Run command when already running
rule rl_debug_run_redundant ( (rg_core_run_state == CORE_RUNNING)
&& (f_run_halt_reqs.first == True));
f_run_halt_reqs.deq;
// Notify debugger that we're running
f_run_halt_rsps.enq (True);
if (show_DM_interactions)
$display ("%0d: %m.rl_debug_run_redundant", cur_cycle);
endrule
// ================================================================
`endif
interface CoreReq coreReq;
method Action start(
Bit#(64) startpc,
@@ -910,6 +1288,9 @@ module mkCore#(CoreId coreId)(Core);
);
fetchStage.start(startpc);
started <= True;
`ifdef INCLUDE_GDB_CONTROL
rg_core_run_state <= CORE_RUNNING;
`endif
mmio.setHtifAddrs(toHostAddr, fromHostAddr);
// start rename debug
commitStage.startRenameDebug;
@@ -980,5 +1361,14 @@ module mkCore#(CoreId coreId)(Core);
// Bluespec: external interrupt to enter debug mode
method Action setDEIP (v) = csrf.setDEIP (v);
endmodule
`ifdef INCLUDE_GDB_CONTROL
interface Server hart0_run_halt_server = toGPServer (f_run_halt_reqs, f_run_halt_rsps);
interface Server hart0_gpr_mem_server = toGPServer (f_gpr_reqs, f_gpr_rsps);
`ifdef ISA_F
interface Server hart0_fpr_mem_server = toGPServer (f_fpr_reqs, f_fpr_rsps);
`endif
interface Server hart0_csr_mem_server = toGPServer (f_csr_reqs, f_csr_rsps);
`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 Bit #(1) dcsr_break_bit;
// Read dcsr[2], the step bit
method Bit #(1) dcsr_step_bit;
// Update 'cause' in DCSR
(* always_ready *)
method Action dcsr_cause_write (Bit #(3) dcsr_cause);
`endif
endinterface
// Fancy Reg functions
@@ -501,6 +521,31 @@ 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)
// 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
// sanctum machine CSRs
@@ -607,6 +652,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 +909,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 Bit #(1) dcsr_break_bit;
return case (prv_reg)
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 Bit #(1) dcsr_step_bit;
return rg_dcsr [2];
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

@@ -77,17 +77,12 @@ import SoC_Map :: *;
import AXI4_Types :: *;
import Fabric_Defs :: *;
`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
`ifdef INCLUDE_GDB_CONTROL
import DM_CPU_Req_Rsp :: *;
`endif
// ================================================================
@@ -114,37 +109,6 @@ module mkProc (Proc_IFC);
FIFOF #(Bit #(0)) f_reset_reqs <- mkFIFOF;
FIFOF #(Bit #(0)) f_reset_rsps <- mkFIFOF;
// ----------------
// 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;
`ifdef ISA_F
// Debugger FPR read/write request/response
FIFOF #(DM_CPU_Req #(5, FLEN)) f_fpr_reqs <- mkFIFOF1;
FIFOF #(DM_CPU_Rsp #(FLEN)) f_fpr_rsps <- mkFIFOF1;
`endif
// Debugger CSR read/write request/response
FIFOF #(DM_CPU_Req #(12, XLEN)) f_csr_reqs <- mkFIFOF1;
FIFOF #(DM_CPU_Rsp #(XLEN)) f_csr_rsps <- mkFIFOF1;
`endif
// ----------------
// Tandem Verification (TODO: to be implemented)
@@ -185,16 +149,11 @@ module mkProc (Proc_IFC);
tlbToMem[i] = core[i].tlbToMem;
end
// Stub out memLoader (TODO: can be Debug Module's access)
let memLoaderStub = interface MemLoaderMemClient;
interface memReq = nullFifoDeq;
interface respSt = nullFifoEnq;
endinterface;
mkLLCDmaConnect(llc.dma, memLoaderStub, tlbToMem);
// Note: mkLLCDmaConnect is Toooba version, different from riscy-ooo version
let llc_mem_server <- mkLLCDmaConnect(llc.dma, tlbToMem);
// ================================================================
// interface LLC to AXI4
// interface Back-side of LLC to AXI4
LLC_AXI4_Adapter_IFC llc_axi4_adapter <- mkLLC_AXi4_Adapter (llc.to_mem);
@@ -360,25 +319,23 @@ module mkProc (Proc_IFC);
// Optional interface to Debug Module
`ifdef INCLUDE_GDB_CONTROL
// run-control, other
interface Server hart0_server_run_halt = toGPServer (f_run_halt_reqs, f_run_halt_rsps);
// run/halt, gpr, mem and csr control goes to core
interface Server hart0_run_halt_server = core [0].hart0_run_halt_server;
interface Server hart0_gpr_mem_server = core[0].hart0_gpr_mem_server;
`ifdef ISA_F
interface Server hart0_fpr_mem_server = core[0].hart0_fpr_mem_server;
`endif
interface Server hart0_csr_mem_server = core[0].hart0_csr_mem_server;
// mem access goes to LLC (stays coherent with CPU pipeline).
interface debug_module_mem_server = llc_mem_server;
// We don't implement 'other' functionality
interface Put hart0_put_other_req;
method Action put (Bit #(4) req);
cfg_verbosity <= req;
endmethod
endinterface
// GPR access
interface Server hart0_gpr_mem_server = toGPServer (f_gpr_reqs, f_gpr_rsps);
`ifdef ISA_F
// FPR access
interface Server hart0_fpr_mem_server = toGPServer (f_fpr_reqs, f_fpr_rsps);
`endif
// CSR access
interface Server hart0_csr_mem_server = toGPServer (f_csr_reqs, f_csr_rsps);
`endif
endmodule: mkProc

View File

@@ -85,20 +85,16 @@ interface Proc_IFC;
// Optional interface to Debug Module
`ifdef INCLUDE_GDB_CONTROL
// run-control, other
interface Server #(Bool, Bool) hart0_server_run_halt;
interface Put #(Bit #(4)) hart0_put_other_req;
// GPR access
interface Server #(Bool, Bool) hart0_run_halt_server;
interface Server #(DM_CPU_Req #(5, XLEN), DM_CPU_Rsp #(XLEN)) hart0_gpr_mem_server;
`ifdef ISA_F
// FPR access
interface Server #(DM_CPU_Req #(5, FLEN), DM_CPU_Rsp #(FLEN)) hart0_fpr_mem_server;
`endif
// CSR access
interface Server #(DM_CPU_Req #(12, XLEN), DM_CPU_Rsp #(XLEN)) hart0_csr_mem_server;
interface AXI4_Slave_IFC #(Wd_Id, Wd_Addr, Wd_Data, Wd_User) debug_module_mem_server;
// Non-standard
interface Put #(Bit #(4)) hart0_put_other_req;
`endif
endinterface

View File

@@ -206,7 +206,7 @@ module mkCoreW (CoreW_IFC #(N_External_Interrupt_Sources));
`ifdef INCLUDE_GDB_CONTROL
`ifndef EXTERNAL_DEBUG_MODULE
// DM to CPU connections for run-control and other misc requests
mkConnection (debug_module.hart0_client_run_halt, proc.hart0_server_run_halt);
mkConnection (debug_module.hart0_client_run_halt, proc.hart0_run_halt_server);
mkConnection (debug_module.hart0_get_other_req, proc.hart0_put_other_req);
`endif
`endif
@@ -230,8 +230,8 @@ module mkCoreW (CoreW_IFC #(N_External_Interrupt_Sources));
rg_fromhost_addr);
endrule
rule rl_hart0_server_run_halt;
let tmp <- proc.hart0_server_run_halt.response.get;
rule rl_hart0_run_halt_server;
let tmp <- proc.hart0_run_halt_server.response.get;
endrule
Reg#(Bool) hart0_halt <- mkReg(False);
@@ -409,10 +409,7 @@ module mkCoreW (CoreW_IFC #(N_External_Interrupt_Sources));
// Slaves on the local 2x3 fabric
// default slave is taken out directly to the Core interface
mkConnection (fabric_2x3.v_to_slaves [plic_slave_num], plic.axi4_slave);
// TODO: This slave can be connected to mkLLCDmaConnect for Debug Module System Bus Access
AXI4_Slave_IFC #(Wd_Id, Wd_Addr, Wd_Data, Wd_User) dummy_slave = dummy_AXI4_Slave_ifc;
mkConnection (fabric_2x3.v_to_slaves [near_mem_io_slave_num], dummy_slave);
mkConnection (fabric_2x3.v_to_slaves [near_mem_io_slave_num], proc.debug_module_mem_server);
// ================================================================
// Connect external interrupt lines from PLIC to CPU
@@ -557,8 +554,8 @@ module mkFabric_2x3 (Fabric_2x3_IFC);
// Any addr is legal, and there is only one slave to service it.
function Tuple2 #(Bool, Slave_Num_2x3) fn_addr_to_slave_num_2x3 (Fabric_Addr addr);
if ( (soc_map.m_near_mem_io_addr_base <= addr)
&& (addr < soc_map.m_near_mem_io_addr_lim))
if ( (soc_map.m_mem0_controller_addr_base <= addr)
&& (addr < soc_map.m_mem0_controller_addr_lim))
return tuple2 (True, near_mem_io_slave_num);
else if ( (soc_map.m_plic_addr_base <= addr)

View File

@@ -39,6 +39,8 @@ import StoreBuffer::*;
import VerificationPacket::*;
import RenameDebugIF::*;
import Cur_Cycle :: *;
typedef struct {
// info about the inst blocking at ROB head
Addr pc;
@@ -86,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;
@@ -112,6 +115,12 @@ interface CommitStage;
// rename debug
method Action startRenameDebug;
interface Get#(RenameErrInfo) renameErr;
`ifdef INCLUDE_GDB_CONTROL
method Bool is_debug_halted;
method Action debug_resume;
`endif
endinterface
// we apply actions the end of commit rule
@@ -122,6 +131,16 @@ typedef struct {
Trap trap;
} CommitTrap deriving(Bits, Eq, FShow);
`ifdef INCLUDE_GDB_CONTROL
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;
@@ -129,6 +148,11 @@ module mkCommitStage#(CommitInput inIfc)(CommitStage);
Integer verbosity = 1;
Reg #(Bit #(64)) rg_instret <- mkReg (0);
`ifdef INCLUDE_GDB_CONTROL
Reg #(Run_State) rg_run_state <- mkReg (RUN_STATE_RUNNING);
`endif
// func units
ReorderBufferSynth rob = inIfc.robIfc;
RegRenamingTable regRenamingTable = inIfc.rtIfc;
@@ -338,12 +362,56 @@ module mkCommitStage#(CommitInput inIfc)(CommitStage);
endaction
endfunction
`ifdef INCLUDE_GDB_CONTROL
// Maintain system consistency when halting into debug mode
// This code is patterned after 'makeSystemConsistent' above
function Action makeSystemConsistent_for_debug_mode;
action
inIfc.setFlushTlbs;
// 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;
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
// instruction. This is because killings of wrong path instructions are
// done in a single cycle. However, when we make killings distributed or
// pipelined, then we need to check spec bits at commit port.
rule doCommitTrap_flush(
`ifdef INCLUDE_GDB_CONTROL
(rg_run_state == RUN_STATE_RUNNING) &&&
`endif
!isValid(commitTrap) &&&
rob.deqPort[0].deq_data.trap matches tagged Valid .trap
);
@@ -404,7 +472,12 @@ module mkCommitStage#(CommitInput inIfc)(CommitStage);
doAssert(x.spec_bits == 0, "cannot have spec bits");
endrule
rule doCommitTrap_handle(commitTrap matches tagged Valid .trap);
rule doCommitTrap_handle(
`ifdef INCLUDE_GDB_CONTROL
(rg_run_state == RUN_STATE_RUNNING) &&&
`endif
commitTrap matches tagged Valid .trap);
// reset commitTrap
commitTrap <= Invalid;
@@ -413,20 +486,59 @@ module mkCommitStage#(CommitInput inIfc)(CommitStage);
inIfc.commitCsrInstOrInterrupt;
end
// trap handling & redirect
let new_pc <- csrf.trap(trap.trap, trap.pc, trap.addr);
inIfc.redirectPc(new_pc);
Bool debugger_halt = False;
// 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);
`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
`endif
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) &&&
`endif
!isValid(commitTrap) &&&
!isValid(rob.deqPort[0].deq_data.trap) &&&
rob.deqPort[0].deq_data.ldKilled matches tagged Valid .killBy
@@ -461,6 +573,9 @@ module mkCommitStage#(CommitInput inIfc)(CommitStage);
// commit system inst
rule doCommitSystemInst(
`ifdef INCLUDE_GDB_CONTROL
(rg_run_state == RUN_STATE_RUNNING) &&
`endif
!isValid(commitTrap) &&
!isValid(rob.deqPort[0].deq_data.trap) &&
!isValid(rob.deqPort[0].deq_data.ldKilled) &&
@@ -585,6 +700,9 @@ 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) &&
`endif
!isValid(commitTrap) &&
!isValid(rob.deqPort[0].deq_data.trap) &&
!isValid(rob.deqPort[0].deq_data.ldKilled) &&
@@ -736,7 +854,6 @@ module mkCommitStage#(CommitInput inIfc)(CommitStage);
`endif
endrule
method Data getPerf(ComStagePerfType t);
return (case(t)
`ifdef PERF_COUNT
@@ -785,4 +902,16 @@ module mkCommitStage#(CommitInput inIfc)(CommitStage);
endmethod
interface renameErr = nullGet;
`endif
`ifdef INCLUDE_GDB_CONTROL
method Bool is_debug_halted;
return (rg_run_state == RUN_STATE_DEBUGGER_HALTED);
endmethod
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
endmodule

View File

@@ -50,6 +50,8 @@ import CCTypes::*;
import L1CoCache::*;
import MMIOInst::*;
import Cur_Cycle :: *;
// ================================================================
// For fv_decode_C function and related types and definitions
@@ -74,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,
@@ -1009,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;

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;
@@ -75,6 +77,9 @@ interface RenameInput;
method Bool checkDeadlock;
// performance
method Bool doStats;
`ifdef INCLUDE_GDB_CONTROL
method Bool core_is_running;
`endif
endinterface
interface RenameStage;
@@ -83,6 +88,11 @@ interface RenameStage;
// deadlock check
interface Get#(RenameStuck) renameInstStuck;
interface Get#(RenameStuck) renameCorrectPathStuck;
`ifdef INCLUDE_GDB_CONTROL
method Action debug_halt_req;
method Action debug_resume;
`endif
endinterface
module mkRenameStage#(RenameInput inIfc)(RenameStage);
@@ -153,6 +163,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.renameStage.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 +261,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));
@@ -271,8 +305,19 @@ module mkRenameStage#(RenameInput inIfc)(RenameStage);
&& epochManager.checkEpoch[0].check(fetchStage.pipelines[0].first.main_epoch) // correct path
&& isValid(firstTrap) // take trap
&& rob.isEmpty // stall for ROB empty
`ifdef INCLUDE_GDB_CONTROL
&& inIfc.core_is_running
`endif
);
fetchStage.pipelines[0].deq;
`ifdef INCLUDE_GDB_CONTROL
fa_step_check;
if (firstTrap == tagged Valid (tagged Interrupt DebugHalt))
$display ("%0d: %m.renameStage.doRenaming_Trap: DebugHalt", cur_cycle);
else if (firstTrap == tagged Valid (tagged Interrupt DebugStep))
$display ("%0d: %m.renameStage.doRenaming_Trap: DebugStep", cur_cycle);
`endif
let x = fetchStage.pipelines[0].first;
let pc = x.pc;
let orig_inst = x.orig_inst;
@@ -377,8 +422,14 @@ module mkRenameStage#(RenameInput inIfc)(RenameStage);
&& !isValid(firstTrap) // not trap
&& firstReplay // system inst needs replay
&& rob.isEmpty // stall for ROB empty
`ifdef INCLUDE_GDB_CONTROL
&& inIfc.core_is_running
`endif
);
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;
@@ -520,8 +571,14 @@ module mkRenameStage#(RenameInput inIfc)(RenameStage);
// turn off speculation for mem inst only, and first inst is mem
&& (specNonMem && firstMem)
&& rob.isEmpty // stall for ROB empty to process mem inst
`ifdef INCLUDE_GDB_CONTROL
&& inIfc.core_is_running
`endif
);
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;
@@ -677,6 +734,9 @@ module mkRenameStage#(RenameInput inIfc)(RenameStage);
&& (!specNone || rob.isEmpty)
// don't process mem inst if we don't allow speculation for mem inst only
&& !(specNonMem && firstMem)
`endif
`ifdef INCLUDE_GDB_CONTROL
&& inIfc.core_is_running
`endif
);
// we stop superscalar rename when an instruction cannot be processed:
@@ -685,6 +745,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 +798,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 +1058,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 +1103,17 @@ module mkRenameStage#(RenameInput inIfc)(RenameStage);
default: 0;
endcase);
endmethod
`ifdef INCLUDE_GDB_CONTROL
method Action debug_halt_req () if (rg_m_halt_req == tagged Invalid);
rg_m_halt_req <= tagged Valid DebugHalt;
$display ("%0d: %m.renameStage.renameStage.debug_halt_req", cur_cycle);
endmethod
method Action debug_resume () if (rg_m_halt_req != tagged Invalid);
rg_m_halt_req <= tagged Invalid;
$display ("%0d: %m.renameStage.renameStage.debug_resume", cur_cycle);
endmethod
`endif
endmodule

View File

@@ -35,8 +35,8 @@ typedef TDiv#(SupSize, 2) FpuMulDivExeNum;
// Phy RFile
// write: Alu < FpuMulDiv < Mem
// read: Alu, FpuMulDiv, Mem
typedef TAdd#(1, TAdd#(FpuMulDivExeNum, AluExeNum)) RFileWrPortNum;
typedef TAdd#(1, TAdd#(FpuMulDivExeNum, AluExeNum)) RFileRdPortNum;
typedef TAdd#(2, TAdd#(FpuMulDivExeNum, AluExeNum)) RFileWrPortNum;
typedef TAdd#(2, TAdd#(FpuMulDivExeNum, AluExeNum)) RFileRdPortNum;
// sb lazy lookup num: same as RFile read, becaues all pipelines recv bypass
typedef RFileRdPortNum SbLazyLookupPortNum;
@@ -65,6 +65,7 @@ Integer memWrAggrPort = 1 + valueof(FpuMulDivExeNum) + valueof(AluExeNum);
function Integer aluRdPort(Integer i) = i;
function Integer fpuMulDivRdPort(Integer i) = valueof(AluExeNum) + i;
Integer memRdPort = valueof(FpuMulDivExeNum) + valueof(AluExeNum);
Integer debuggerPort = memRdPort + 1;
// ports for correct spec, ordering doesn't matter
typedef TAdd#(2, AluExeNum) CorrectSpecPortNum;

View File

@@ -1,4 +1,16 @@
// This file is a modified version of: RISCY_OOO/procs/lib/LLCDmaConnect.bsv
// The original module had, as 2nd parameter, MemLoaderMemClient memLoader
// The memLoader assumed only write-transactions (to load memory), and
// discarded load responses.
// Here, the module instead offers an AXI4_Slave interface to be
// connected to the AXI4_Master of the Debug Module.
// This axi4_slave accepts and responds to both read and write transactions.
// Modifications Copyright (c) 2020 Bluespec, Inc.
// Original copyright:
// Copyright (c) 2017 Massachusetts Institute of Technology
//
// Permission is hereby granted, free of charge, to any person
@@ -26,6 +38,7 @@ import GetPut::*;
import Vector::*;
import BuildVector::*;
import FIFO::*;
import FIFOF::*;
import Assert::*;
import Types::*;
@@ -37,6 +50,10 @@ import MemLoader::*;
import CrossBar::*;
import MemLoader::*;
import AXI4_Types :: *;
import Fabric_Defs :: *;
import Semi_FIFOF :: *;
typedef struct {
CoreId core;
TlbMemReqId id;
@@ -48,15 +65,44 @@ typedef union tagged {
TlbDmaReqId Tlb;
} LLCDmaReqId deriving(Bits, Eq, FShow);
module mkLLCDmaConnect#(
// For writing, position a 4-byte value and 4-bit byte-enable into a 64-byte line and 64-bit line-byte-enable
function Tuple3 #(Addr, Line, LineByteEn) fn_line_and_byteen_from_word (Addr addr, Bit #(64) data);
Vector #(16, Bit #(32)) line_words = replicate (0);
Vector #(16, Bit #(4)) line_word_byteens = replicate (0);
Bit #(4) word_index = addr [5:2];
line_words [word_index] = ((addr [2] == 0) ? data [31:0] : data [63:32]);
line_word_byteens [word_index] = 4'b1111;
Addr line_addr = { addr [63:6], 6'b0 };
return tuple3 (line_addr,
unpack (pack (line_words)),
unpack (pack (line_word_byteens)));
endfunction
// For reading, extract a 4-byte value from a 64-byte line
function Bit #(64) fn_word_from_line (Line line, Bit #(4) word_in_line);
Vector #(16, Bit #(32)) line_words = unpack (pack (line));
Bit #(32) w = line_words [word_in_line];
Bit #(64) dw = ((word_in_line [0] == 0) ? { 32'b0, w } : { w, 32'b0 });
return dw;
endfunction
module mkLLCDmaConnect #(
DmaServer#(LLCDmaReqId) llc,
MemLoaderMemClient memLoader,
// MemLoaderMemClient memLoader, // REPLACED BY AXI4_Slave_interface
Vector#(CoreNum, TlbMemClient) tlb
)(Empty) provisos (
)(AXI4_Slave_IFC #(Wd_Id, Wd_Addr, Wd_Data, Wd_User)) provisos (
Alias#(dmaRqT, DmaRq#(LLCDmaReqId))
);
Bool verbose = False;
Integer verbosity = 0;
// When debugger reads a word, request a line from LLC, and remember word-in-line here
FIFOF #(Bit #(4)) f_word_in_line <- mkFIFOF;
// Slave transactor for requests from Debug Module
AXI4_Slave_Xactor_IFC #(Wd_Id, Wd_Addr, Wd_Data, Wd_User) axi4_slave_xactor <- mkAXI4_Slave_Xactor;
// helper functions for cross bar
function XBarDstInfo#(Bit#(0), Tuple2#(CoreId, TlbMemReq)) getTlbDst(CoreId core, TlbMemReq r);
return XBarDstInfo {idx: 0, data: tuple2(core, r)};
@@ -83,24 +129,46 @@ module mkLLCDmaConnect#(
};
endfunction
// send req to LLC
rule sendMemLoaderReqToLLC;
memLoader.memReq.deq;
let r = memLoader.memReq.first;
dmaRqT req = DmaRq {
addr: r.addr,
byteEn: r.byteEn,
data: r.data,
id: MemLoader (r.id)
};
llc.memReq.enq(req);
if(verbose) begin
$display("[LLCDmaConnnect sendMemLoaderReqToLLC] ",
fshow(r), " ; ", fshow(req));
end
rule sendMemLoaderReqToLLC_wr; // write requests
let wr_addr <- pop_o (axi4_slave_xactor.o_wr_addr);
let wr_data <- pop_o (axi4_slave_xactor.o_wr_data);
match { .line_addr, .line_data, .line_byteen } = fn_line_and_byteen_from_word (wr_addr.awaddr, wr_data.wdata);
dmaRqT req = DmaRq {addr: line_addr,
byteEn: line_byteen,
data: line_data,
id: tagged MemLoader (?) // TODO: change uniformly to wr_addr.awid
};
llc.memReq.enq(req);
if (verbosity != 0) begin
$display("[LLCDmaConnect sendMemLoaderReqToLLC_wr]");
$display (" ", fshow (wr_addr));
$display (" ", fshow (wr_data));
$display (" ", fshow (req));
end
endrule
(* descending_urgency = "sendMemLoaderReqToLLC, sendTlbReqToLLC" *)
rule sendMemLoaderReqToLLC_rd; // read requests
let rd_addr <- pop_o (axi4_slave_xactor.o_rd_addr);
Addr line_addr = { rd_addr.araddr [63:6], 6'b0 };
dmaRqT req = DmaRq {addr: line_addr,
byteEn: replicate (False),
data: ?,
id: MemLoader (?) // TODO: change uniformly to rd_addr.awid
};
llc.memReq.enq(req);
Bit #(4) word_in_line = rd_addr.araddr [5:2];
f_word_in_line.enq (word_in_line);
if (verbosity != 0) begin
$display("[LLCDmaConnect sendMemLoaderReqToLLC_rd]");
$display (" ", fshow (rd_addr));
$display (" ", fshow (req));
end
endrule
(* descending_urgency = "sendMemLoaderReqToLLC_wr, sendTlbReqToLLC" *)
(* descending_urgency = "sendMemLoaderReqToLLC_rd, sendTlbReqToLLC" *)
rule sendTlbReqToLLC;
let {c, r} <- toGet(tlbQ).get;
let req = getTlbDmaReq(c, r);
@@ -112,12 +180,22 @@ module mkLLCDmaConnect#(
// send Ld resp from LLC
rule sendLdRespToMemLoader(llc.respLd.first.id matches tagged MemLoader .id);
llc.respLd.deq;
if(verbose) begin
$display("[LLCDmaConnect sendLdRespToMemLoader] ",
fshow(llc.respLd.first));
end
doAssert(False, "No mem loader ld");
let resp = llc.respLd.first;
llc.respLd.deq;
let word_in_line = f_word_in_line.first;
f_word_in_line.deq;
AXI4_Rd_Data #(Wd_Id, Wd_Data, Wd_User)
rd_data = AXI4_Rd_Data {rid: 0, // TODO: change uniformly to Fabric_Id
rdata: fn_word_from_line (resp.data, word_in_line),
rresp: axi4_resp_okay,
rlast: True,
ruser: ?};
axi4_slave_xactor.i_rd_data.enq (rd_data);
if (verbosity != 0) begin
$display ("[LLCDmaConnect sendLdRespToMemLoader]");
$display (" ", fshow (resp));
$display (" ", fshow (rd_data));
end
endrule
rule sendLdRespToTlb(llc.respLd.first.id matches tagged Tlb .id);
@@ -135,12 +213,19 @@ module mkLLCDmaConnect#(
// send St resp from LLC
rule sendStRespToMemLoader(llc.respSt.first matches tagged MemLoader .id);
llc.respSt.deq;
memLoader.respSt.enq(id);
if(verbose) begin
$display("[LLCDmaConnect sendStRespToMemLoader] ",
fshow(llc.respSt.first));
end
let resp = llc.respSt.first;
llc.respSt.deq;
AXI4_Wr_Resp #(Wd_Id, Wd_User)
wr_resp = AXI4_Wr_Resp {bid: 0, // TODO: change uniformly to Fabric_id
bresp: axi4_resp_okay,
buser: ?};
axi4_slave_xactor.i_wr_resp.enq (wr_resp);
if (verbosity != 0) begin
$display ("[LLCDmaConnect sendStRespToMemLoader]");
$display (" ", fshow (resp));
$display (" ", fshow (wr_resp));
end
endrule
rule sendStRespToTlb(llc.respSt.first matches tagged Tlb .id);
@@ -150,4 +235,6 @@ module mkLLCDmaConnect#(
end
doAssert(False, "No TLB st");
endrule
return axi4_slave_xactor.axi_side;
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
@@ -269,6 +269,14 @@ typedef enum {
// sanctum user CSR
CSRtrng = 12'hcc0, // random number for secure boot
`endif
`ifdef INCLUDE_GDB_CONTROL
CSRdcsr = 12'h7B0, // Debug control and status
CSRdpc = 12'h7B1, // Debug PC
CSRdscratch0 = 12'h7B2, // Debug scratch0
CSRdscratch1 = 12'h7B3, // Debug scratch1
`endif
// CSR that catches all the unimplemented CSRs. To avoid exception on this,
// make it a user non-standard read/write CSR.
CSRnone = 12'h8ff
@@ -446,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 {