Merge remote-tracking branch 'origin/Debug_Module'
Debug Module mostly working (except resume-after-breakpoint).
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -36,6 +36,7 @@
|
||||
`define a True
|
||||
`define f True
|
||||
`define d True
|
||||
`define c True
|
||||
|
||||
//`define NUM_CORES 1 // defined in make 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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 {
|
||||
|
||||
Reference in New Issue
Block a user