Merge branch 'master' into RVFI_DII, a complex merge for the fetch stage!
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
|
||||
// Copyright (c) 2017 Massachusetts Institute of Technology
|
||||
// Portions Copyright (c) 2019-2020 Bluespec, Inc.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person
|
||||
// obtaining a copy of this software and associated documentation
|
||||
@@ -21,8 +22,6 @@
|
||||
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
|
||||
// Portions Copyright (c) Bluespec, Inc.
|
||||
|
||||
`include "ProcConfig.bsv"
|
||||
|
||||
import Vector::*;
|
||||
@@ -88,6 +87,29 @@ import Toooba_RVFI_DII_Bridge::*;
|
||||
|
||||
import CsrFile :: *;
|
||||
|
||||
// ================================================================
|
||||
// Toooba
|
||||
|
||||
import Cur_Cycle :: *;
|
||||
import FIFOF :: *;
|
||||
import GetPut_Aux :: *;
|
||||
|
||||
`ifdef INCLUDE_GDB_CONTROL
|
||||
import DM_CPU_Req_Rsp :: *;
|
||||
`endif
|
||||
|
||||
`ifdef INCLUDE_TANDEM_VERIF
|
||||
import Trace_Data2 :: *;
|
||||
`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,
|
||||
@@ -139,13 +161,28 @@ interface Core;
|
||||
// Bluespec: external interrupt requests targeting Machine and Supervisor modes
|
||||
method Action setMEIP (Bit #(1) v);
|
||||
method Action setSEIP (Bit #(1) v);
|
||||
|
||||
// Bluespec: external interrupt to enter debug mode
|
||||
method Action setDEIP (Bit #(1) v);
|
||||
|
||||
`ifdef RVFI_DII
|
||||
interface Toooba_RVFI_DII_Server rvfi_dii_server;
|
||||
`endif
|
||||
`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
|
||||
|
||||
`ifdef INCLUDE_TANDEM_VERIF
|
||||
// Note: this is a SupSize vector of streams of Trace_Data2 structs,
|
||||
// each of which has a serialnum field. Each of the SupSize
|
||||
// streams has serialnums in increasing order. Each serialnum
|
||||
// appears exactly once in exactly one of the streams. Thus, the
|
||||
// channels can easily be merged into a single program-order stream.
|
||||
interface Vector #(SupSize, Get #(Trace_Data2)) v_to_TV;
|
||||
`endif
|
||||
|
||||
endinterface
|
||||
|
||||
// fixpoint to instantiate modules
|
||||
@@ -157,9 +194,22 @@ 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;
|
||||
|
||||
// ================================================================
|
||||
Integer verbosity = 0; // More levels of verbosity control than 'Bool verbose'
|
||||
|
||||
Reg#(Bool) outOfReset <- mkReg(False);
|
||||
rule rl_outOfReset if (!outOfReset);
|
||||
$fwrite(stderr, "mkProc came out of reset\n");
|
||||
@@ -168,6 +218,19 @@ 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
|
||||
|
||||
`ifdef INCLUDE_TANDEM_VERIF
|
||||
Vector #(SupSize, FIFOF #(Trace_Data2)) v_f_to_TV <- replicateM (mkFIFOF);
|
||||
`endif
|
||||
|
||||
// ================================================================
|
||||
|
||||
// front end
|
||||
FetchStage fetchStage <- mkFetchStage;
|
||||
ITlb iTlb = fetchStage.iTlbIfc;
|
||||
@@ -244,18 +307,6 @@ module mkCore#(CoreId coreId)(Core);
|
||||
// whether perf data is collected
|
||||
Reg#(Bool) doStatsReg <- mkConfigReg(False);
|
||||
|
||||
// redirect func
|
||||
//function Action redirectFunc(Addr trap_pc, Maybe#(SpecTag) spec_tag, InstTag inst_tag );
|
||||
//action
|
||||
// if (verbose) $fdisplay(stdout, "[redirect_action] new pc = 0x%8x, spec_tag = ", trap_pc, fshow(spec_tag));
|
||||
// epochManager.redirect;
|
||||
// fetchStage.redirect(trap_pc);
|
||||
// if (spec_tag matches tagged Valid .valid_spec_tag) begin
|
||||
// globalSpecUpdate.incorrectSpec(valid_spec_tag, inst_tag);
|
||||
// end
|
||||
//endaction
|
||||
//endfunction
|
||||
|
||||
// write aggressive elements + wakupe reservation stations
|
||||
function Action writeAggr(Integer wrAggrPort, PhyRIndx dst);
|
||||
action
|
||||
@@ -332,7 +383,7 @@ module mkCore#(CoreId coreId)(Core);
|
||||
let train <- toGet(trainBPQ[i]).get;
|
||||
fetchStage.train_predictors(
|
||||
train.pc, train.nextPc, train.iType, train.taken,
|
||||
train.dpTrain, train.mispred
|
||||
train.dpTrain, train.mispred, train.isCompressed
|
||||
);
|
||||
endrule
|
||||
end
|
||||
@@ -363,6 +414,9 @@ module mkCore#(CoreId coreId)(Core);
|
||||
method csrf_rd = csrf.rd;
|
||||
method rob_getPC = rob.getOrigPC[valueof(AluExeNum)].get; // last getPC port
|
||||
method rob_setExecuted_doFinishMem = rob.setExecuted_doFinishMem;
|
||||
`ifdef INCLUDE_TANDEM_VERIF
|
||||
method rob_setExecuted_doFinishMem_RegData = rob.setExecuted_doFinishMem_RegData;
|
||||
`endif
|
||||
method rob_setExecuted_deqLSQ = rob.setExecuted_deqLSQ;
|
||||
method isMMIOAddr = mmio.isMMIOAddr;
|
||||
method mmioReq = mmio.dataReq;
|
||||
@@ -407,13 +461,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
|
||||
@@ -500,6 +556,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);
|
||||
|
||||
@@ -512,16 +571,50 @@ 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;
|
||||
`ifdef INCLUDE_GDB_CONTROL
|
||||
method setFetchWaitFlush = fetchStage.setWaitFlush;
|
||||
`endif
|
||||
method incrementEpoch = epochManager.incrementEpoch;
|
||||
method commitCsrInstOrInterrupt = csrInstOrInterruptInflight_commit._write(False);
|
||||
method doStats = coreFix.doStatsIfc._read;
|
||||
@@ -532,6 +625,11 @@ module mkCore#(CoreId coreId)(Core);
|
||||
return False;
|
||||
`endif
|
||||
endmethod
|
||||
|
||||
`ifdef INCLUDE_TANDEM_VERIF
|
||||
interface v_to_TV = map (toPut, v_f_to_TV);
|
||||
`endif
|
||||
|
||||
endinterface);
|
||||
CommitStage commitStage <- mkCommitStage(commitInput);
|
||||
|
||||
@@ -568,11 +666,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;
|
||||
@@ -581,10 +681,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.
|
||||
@@ -593,6 +694,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);
|
||||
@@ -605,6 +707,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
|
||||
@@ -612,6 +715,7 @@ module mkCore#(CoreId coreId)(Core);
|
||||
rule flushBrPred(doFlushBrPred);
|
||||
flush_brpred <= False;
|
||||
fetchStage.flush_predictors;
|
||||
// $display ("%0d: %m.rule flushBrPred", cur_cycle);
|
||||
endrule
|
||||
`endif
|
||||
|
||||
@@ -656,9 +760,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
|
||||
@@ -671,6 +778,15 @@ 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;
|
||||
if (verbosity >= 1)
|
||||
$display ("%0d: %m.rule readyToFetch: halting for debug mode", cur_cycle);
|
||||
end
|
||||
`endif
|
||||
endrule
|
||||
|
||||
`ifdef PERF_COUNT
|
||||
@@ -930,6 +1046,280 @@ module mkCore#(CoreId coreId)(Core);
|
||||
endrule
|
||||
`endif
|
||||
|
||||
`ifdef INCLUDE_GDB_CONTROL
|
||||
// ================================================================
|
||||
// DEBUG MODULE INTERFACE
|
||||
|
||||
Bool show_DM_interactions = False; // 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 [%0h] => 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 [%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;
|
||||
|
||||
// ----------------
|
||||
// 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;
|
||||
|
||||
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're halted, but otherwise ignore the request
|
||||
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;
|
||||
|
||||
// In Debug Mode, debugger may have updated DCSR (hence privilege level, DCSR[1:0]),
|
||||
// and also other VM-related state.
|
||||
// The following TLB actions update to a consistent state.
|
||||
iTlb.flush;
|
||||
dTlb.flush;
|
||||
let vmI = csrf.vmI;
|
||||
let vmD = csrf.vmD;
|
||||
iTlb.updateVMInfo(vmI);
|
||||
dTlb.updateVMInfo(vmD);
|
||||
l2Tlb.updateVMInfo(vmI, vmD);
|
||||
|
||||
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.rl_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
|
||||
|
||||
interface CoreReq coreReq;
|
||||
method Action start(
|
||||
Bit#(64) startpc,
|
||||
@@ -941,8 +1331,11 @@ module mkCore#(CoreId coreId)(Core);
|
||||
`endif
|
||||
);
|
||||
started <= True;
|
||||
`ifdef INCLUDE_GDB_CONTROL
|
||||
rg_core_run_state <= CORE_RUNNING;
|
||||
`endif
|
||||
mmio.setHtifAddrs(toHostAddr, fromHostAddr);
|
||||
// start rename debug
|
||||
|
||||
commitStage.startRenameDebug;
|
||||
endmethod
|
||||
|
||||
@@ -1013,7 +1406,17 @@ module mkCore#(CoreId coreId)(Core);
|
||||
method Action setMEIP (v) = csrf.setMEIP (v);
|
||||
method Action setSEIP (v) = csrf.setSEIP (v);
|
||||
|
||||
// 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
|
||||
|
||||
`ifdef INCLUDE_TANDEM_VERIF
|
||||
interface v_to_TV = map (toGet, v_f_to_TV);
|
||||
`endif
|
||||
|
||||
endmodule
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
|
||||
// Copyright (c) 2017 Massachusetts Institute of Technology
|
||||
// Portions Copyright (c) 2019-2020 Bluespec, Inc.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person
|
||||
// obtaining a copy of this software and associated documentation
|
||||
@@ -21,8 +22,6 @@
|
||||
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
|
||||
// Portions Copyright (c) Bluespec, Inc.
|
||||
|
||||
`include "ProcConfig.bsv"
|
||||
import Types::*;
|
||||
import ProcTypes::*;
|
||||
@@ -37,6 +36,46 @@ import GetPut::*;
|
||||
import BuildVector::*;
|
||||
//import TRNG::*;
|
||||
|
||||
// ================================================================
|
||||
// BSV additional libs
|
||||
|
||||
import Cur_Cycle :: *;
|
||||
|
||||
// ================================================================
|
||||
// Project imports from Toooba
|
||||
|
||||
import SoC_Map :: *;
|
||||
|
||||
// ================================================================
|
||||
// Information returned on traps and mret/sret/uret
|
||||
|
||||
typedef struct {
|
||||
Addr new_pc;
|
||||
|
||||
`ifdef INCLUDE_TANDEM_VERIF
|
||||
// The fields below are for tandem verification only
|
||||
Bit #(2) prv;
|
||||
Data status;
|
||||
Data cause;
|
||||
Data epc;
|
||||
Data tval;
|
||||
`endif
|
||||
} Trap_Updates
|
||||
deriving (Bits, FShow);
|
||||
|
||||
typedef struct {
|
||||
Addr new_pc;
|
||||
|
||||
`ifdef INCLUDE_TANDEM_VERIF
|
||||
// The fields below are for tandem verification only
|
||||
Bit #(2) prv;
|
||||
Data status;
|
||||
`endif
|
||||
} RET_Updates
|
||||
deriving (Bits, FShow);
|
||||
|
||||
// ================================================================
|
||||
|
||||
interface CsrFile;
|
||||
// Read
|
||||
method Data rd(CSR csr);
|
||||
@@ -45,12 +84,23 @@ interface CsrFile;
|
||||
// normal write by FPU inst to FPU CSR
|
||||
method Bool fpuInstNeedWr(Bit#(5) fflags, Bool fpu_dirty);
|
||||
method Action fpuInstWr(Bit#(5) fflags); // FPU must become dirty
|
||||
`ifdef INCLUDE_TANDEM_VERIF
|
||||
// Returns new fcsr and mstatus (pure function)
|
||||
method Tuple2 #(Bit #(5), Data) fpuInst_csr_updates (Bit #(5) fflags,
|
||||
Bool init_for_way0,
|
||||
Bit #(5) old_fflags,
|
||||
Data old_mstatus);
|
||||
method Data getMIP;
|
||||
`endif
|
||||
|
||||
// The WARL transform performed during CSRRx writes to a CSR
|
||||
method Data warl_xform (CSR csr, Data x);
|
||||
|
||||
// Methods for handling traps
|
||||
method Maybe#(Interrupt) pending_interrupt;
|
||||
method ActionValue#(Addr) trap(Trap t, Addr pc, Addr faultAddr);
|
||||
method ActionValue#(Addr) sret;
|
||||
method ActionValue#(Addr) mret;
|
||||
method ActionValue#(Trap_Updates) trap(Trap t, Addr pc, Addr faultAddr, Bit #(32) orig_inst);
|
||||
method ActionValue#(RET_Updates) sret;
|
||||
method ActionValue#(RET_Updates) mret;
|
||||
|
||||
// Outputs for CSRs that the rest of the processor needs to know about
|
||||
method VMInfo vmI;
|
||||
@@ -79,9 +129,6 @@ interface CsrFile;
|
||||
method Action setMEIP (Bit #(1) v);
|
||||
method Action setSEIP (Bit #(1) v);
|
||||
|
||||
// Bluespec: external interrupt to enter debug mode
|
||||
method Action setDEIP (Bit #(1) v);
|
||||
|
||||
// performance stats is collected or not
|
||||
method Bool doPerfStats;
|
||||
// send/recv updates on stats CSR globally
|
||||
@@ -90,6 +137,26 @@ 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
|
||||
// Is invoked by logic that stops a hart, to enter Debug Mode
|
||||
(* always_ready *)
|
||||
method Action dcsr_cause_write (Bit #(3) dcsr_cause);
|
||||
|
||||
`endif
|
||||
endinterface
|
||||
|
||||
// Fancy Reg functions
|
||||
@@ -244,10 +311,13 @@ module mkCsrFile #(Data hartid)(CsrFile);
|
||||
// Machine level CSRs
|
||||
// mstatus
|
||||
Reg#(Bit#(2)) xs_reg <- mkReadOnlyReg(0); // XXX no extension
|
||||
Reg#(Bit#(2)) fs_reg <- (isa.f || isa.d) ? mkCsrReg(0) : mkReadOnlyReg(0);
|
||||
Reg#(Bit#(2)) fs_reg <- (isa.f || isa.d) ? mkCsrReg(2'b01) : mkReadOnlyReg(0);
|
||||
Reg#(Bit#(1)) sd_reg = readOnlyReg(
|
||||
((xs_reg == 2'b11) || (fs_reg == 2'b11)) ? 1 : 0
|
||||
);
|
||||
function Bit #(1) fn_sd_val (Bit #(2) xs_val, Bit #(2) fs_val);
|
||||
return (((xs_val == 2'b11) || (fs_val == 2'b11)) ? 1 : 0);
|
||||
endfunction
|
||||
Reg#(Bit#(2)) sxl_reg = readOnlyReg(getXLBits);
|
||||
Reg#(Bit#(2)) uxl_reg = readOnlyReg(getXLBits);
|
||||
Reg#(Bit#(1)) tsr_reg <- mkCsrReg(0);
|
||||
@@ -286,6 +356,25 @@ module mkCsrFile #(Data hartid)(CsrFile);
|
||||
ie_vec[prvM], readOnlyReg(1'b0),
|
||||
ie_vec[prvS], ie_vec[prvU]
|
||||
);
|
||||
function Data fn_mstatus_val (Bit #(2) sxl_val, Bit #(2) uxl_val,
|
||||
Bit #(1) tsr_val, Bit #(1) tw_val, Bit #(1) tvm_val,
|
||||
Bit #(1) mxr_val, Bit #(1) sum_val, Bit #(1) mprv_val,
|
||||
Bit #(2) xs_val, Bit #(2) fs_val,
|
||||
Bit #(2) mpp_val, Bit #(1) spp_val,
|
||||
Bit #(1) prev_ie_vec_prvM_val,
|
||||
Bit #(1) prev_ie_vec_prvS_val, Bit #(1) prev_ie_vec_prvU_val,
|
||||
Bit #(1) ie_vec_prvM_val,
|
||||
Bit #(1) ie_vec_prvS_val, Bit #(1) ie_vec_prvU_val);
|
||||
return {fn_sd_val (xs_val, fs_val),
|
||||
27'b0, sxl_val, uxl_val, 9'b0,
|
||||
tsr_val, tw_val, tvm_val, mxr_val, sum_val, mprv_val, xs_val, fs_val,
|
||||
mpp_val, 2'b0, spp_val,
|
||||
prev_ie_vec_prvM_val, 1'b0,
|
||||
prev_ie_vec_prvS_val, prev_ie_vec_prvU_val,
|
||||
ie_vec_prvM_val, 1'b0,
|
||||
ie_vec_prvS_val, ie_vec_prvU_val};
|
||||
endfunction
|
||||
|
||||
// misa
|
||||
Reg#(Data) misa_csr = readOnlyReg({getXLBits, 36'b0, getExtensionBits(isa)});
|
||||
// medeleg: some exceptions don't exist, fix corresponding bits to 0
|
||||
@@ -309,7 +398,6 @@ module mkCsrFile #(Data hartid)(CsrFile);
|
||||
readOnlyReg(1'b0), mideleg_1_0_reg
|
||||
);
|
||||
// mie
|
||||
Reg #(Bit #(1)) debug_int_en = readOnlyReg (1);
|
||||
Vector#(4, Reg#(Bit#(1))) external_int_en_vec = replicate(readOnlyReg(0));
|
||||
external_int_en_vec[prvU] <- mkCsrReg(0);
|
||||
external_int_en_vec[prvS] <- mkCsrReg(0);
|
||||
@@ -322,16 +410,14 @@ module mkCsrFile #(Data hartid)(CsrFile);
|
||||
software_int_en_vec[prvU] <- mkCsrReg(0);
|
||||
software_int_en_vec[prvS] <- mkCsrReg(0);
|
||||
software_int_en_vec[prvM] <- mkCsrReg(0);
|
||||
Reg#(Data) mie_csr = concatReg15(
|
||||
readOnlyReg(49'b0),
|
||||
debug_int_en, // mie [14]
|
||||
readOnlyReg(2'b0),
|
||||
Reg#(Data) mie_csr = concatReg13(
|
||||
readOnlyReg(52'b0),
|
||||
external_int_en_vec[prvM], readOnlyReg(1'b0),
|
||||
external_int_en_vec[prvS], external_int_en_vec[prvU],
|
||||
external_int_en_vec[prvS], readOnlyReg(1'b0), // only if misa.N: external_int_en_vec[prvU],
|
||||
timer_int_en_vec[prvM], readOnlyReg(1'b0),
|
||||
timer_int_en_vec[prvS], timer_int_en_vec[prvU],
|
||||
timer_int_en_vec[prvS], readOnlyReg(1'b0), // only if misa.N: timer_int_en_vec[prvU],
|
||||
software_int_en_vec[prvM], readOnlyReg(1'b0),
|
||||
software_int_en_vec[prvS], software_int_en_vec[prvU]
|
||||
software_int_en_vec[prvS], readOnlyReg(1'b0) // only if misa.N: software_int_en_vec[prvU]
|
||||
);
|
||||
// mtvec
|
||||
Reg#(Bit#(62)) mtvec_base_hi_reg <- mkCsrReg(0); // this is BASE[63:2]
|
||||
@@ -359,34 +445,48 @@ module mkCsrFile #(Data hartid)(CsrFile);
|
||||
Reg#(Data) mcause_csr = concatReg3(
|
||||
mcause_interrupt_reg, readOnlyReg(59'b0), mcause_code_reg
|
||||
);
|
||||
function Data fn_mcause_val (Bit #(1) mcause_interrupt_val, Bit #(4) mcause_code_val);
|
||||
return { mcause_interrupt_val, 59'b0, mcause_code_val };
|
||||
endfunction
|
||||
|
||||
// mtval (mbadaddr in spike)
|
||||
Reg#(Data) mtval_csr <- mkCsrReg(0);
|
||||
// mip
|
||||
Reg #(Bit #(1)) debug_int_pend <- mkCsrReg (0);
|
||||
Vector#(4, Reg#(Bit#(1))) external_int_pend_vec = replicate(readOnlyReg(0));
|
||||
external_int_pend_vec[prvU] <- mkCsrReg(0);
|
||||
external_int_pend_vec[prvS] <- mkCsrReg(0);
|
||||
external_int_pend_vec[prvM] <- mkCsrReg(0);
|
||||
external_int_pend_vec[prvM] <- mkCsrReg(0); // TODO: bug (writeable by CSRRx)?
|
||||
Vector#(4, Reg#(Bit#(1))) timer_int_pend_vec = replicate(readOnlyReg(0));
|
||||
timer_int_pend_vec[prvU] <- mkCsrReg(0);
|
||||
timer_int_pend_vec[prvS] <- mkCsrReg(0);
|
||||
timer_int_pend_vec[prvM] <- mkCsrReg(0);
|
||||
timer_int_pend_vec[prvM] <- mkCsrReg(0); // TODO: bug (writeable by CSRRx)?
|
||||
Vector#(4, Reg#(Bit#(1))) software_int_pend_vec = replicate(readOnlyReg(0));
|
||||
software_int_pend_vec[prvU] <- mkCsrReg(0);
|
||||
software_int_pend_vec[prvS] <- mkCsrReg(0);
|
||||
software_int_pend_vec[prvM] <- mkCsrReg(0);
|
||||
Reg#(Data) mip_csr = concatReg15(
|
||||
readOnlyReg(49'b0),
|
||||
debug_int_pend,
|
||||
readOnlyReg(2'b0),
|
||||
external_int_pend_vec[prvM], readOnlyReg(1'b0),
|
||||
external_int_pend_vec[prvS], external_int_pend_vec[prvU],
|
||||
readOnlyReg(timer_int_pend_vec[prvM]), // MTIP is read-only to software
|
||||
software_int_pend_vec[prvM] <- mkCsrReg(0); // TODO: bug (writeable by CSRRx)?
|
||||
Reg#(Data) mip_csr = concatReg13(
|
||||
readOnlyReg(52'b0),
|
||||
// External interrupts
|
||||
readOnlyReg(external_int_pend_vec[prvM]), // MEIP is read-only to software
|
||||
readOnlyReg(1'b0),
|
||||
timer_int_pend_vec[prvS], timer_int_pend_vec[prvU],
|
||||
software_int_pend_vec[prvM], readOnlyReg(1'b0),
|
||||
software_int_pend_vec[prvS], software_int_pend_vec[prvU]
|
||||
external_int_pend_vec[prvS],
|
||||
readOnlyReg(1'b0), // only if misa.N: external_int_pend_vec[prvU],
|
||||
// Timer interrupts
|
||||
readOnlyReg(timer_int_pend_vec[prvM]), // MTIP is read-only to software
|
||||
readOnlyReg(1'b0),
|
||||
timer_int_pend_vec[prvS],
|
||||
readOnlyReg(1'b0), // only if misa.N: timer_int_pend_vec[prvU],
|
||||
// Software interrupts
|
||||
readOnlyReg(software_int_pend_vec[prvM]), // MSIP is read-only to software
|
||||
readOnlyReg(1'b0),
|
||||
software_int_pend_vec[prvS],
|
||||
readOnlyReg(1'b0) // only if misa.N: software_int_pend_vec[prvU]
|
||||
);
|
||||
// MIP and MIE fields are WARL (Write Any Read Legal)
|
||||
// We support M-privilege and S-privilege bits only;
|
||||
// this mask allows only those bits through.
|
||||
Data mip_mie_warl_mask = zeroExtend (12'h_222);
|
||||
|
||||
// minstret
|
||||
Ehr#(2, Data) minstret_ehr <- mkCsrEhr(0);
|
||||
Reg#(Data) minstret_csr = minstret_ehr[0];
|
||||
@@ -411,14 +511,32 @@ module mkCsrFile #(Data hartid)(CsrFile);
|
||||
readOnlyReg(2'b0), prev_ie_vec[prvS], prev_ie_vec[prvU],
|
||||
readOnlyReg(2'b0), ie_vec[prvS], ie_vec[prvU]
|
||||
);
|
||||
function Data fn_sstatus_val (Bit #(2) uxl_val,
|
||||
Bit #(1) mxr_val, Bit #(1) sum_val,
|
||||
Bit #(2) xs_val, Bit #(2) fs_val,
|
||||
Bit #(1) spp_val,
|
||||
Bit #(1) prev_ie_vec_prvS_val,
|
||||
Bit #(1) prev_ie_vec_prvU_val,
|
||||
Bit #(1) ie_vec_prvS_val,
|
||||
Bit #(1) ie_vec_prvU_val);
|
||||
return {fn_sd_val (xs_val, fs_val),
|
||||
27'b0, 2'b0, uxl_val, 12'b0,
|
||||
mxr_val, sum_val, 1'b0, xs_val, fs_val,
|
||||
4'b0, spp_val,
|
||||
2'b0,
|
||||
prev_ie_vec_prvS_val, prev_ie_vec_prvU_val,
|
||||
2'b0,
|
||||
ie_vec_prvS_val, ie_vec_prvU_val};
|
||||
endfunction
|
||||
|
||||
// sie: restricted view of mie
|
||||
Reg#(Data) sie_csr = concatReg9(
|
||||
readOnlyReg(54'b0),
|
||||
external_int_en_vec[prvS], external_int_en_vec[prvU],
|
||||
external_int_en_vec[prvS], readOnlyReg(1'b0), // only if misa.N: external_int_en_vec[prvU],
|
||||
readOnlyReg(2'b0),
|
||||
timer_int_en_vec[prvS], timer_int_en_vec[prvU],
|
||||
timer_int_en_vec[prvS], readOnlyReg(1'b0), // only if misa.N: timer_int_en_vec[prvU],
|
||||
readOnlyReg(2'b0),
|
||||
software_int_en_vec[prvS], software_int_en_vec[prvU]
|
||||
software_int_en_vec[prvS], readOnlyReg(1'b0) // only if misa.N: software_int_en_vec[prvU]
|
||||
);
|
||||
// stvec
|
||||
Reg#(Bit#(62)) stvec_base_hi_reg <- mkCsrReg(0); // BASE[63:2]
|
||||
@@ -446,17 +564,27 @@ module mkCsrFile #(Data hartid)(CsrFile);
|
||||
Reg#(Data) scause_csr = concatReg3(
|
||||
scause_interrupt_reg, readOnlyReg(59'b0), scause_code_reg
|
||||
);
|
||||
function Data fn_scause_val (Bit #(1) scause_interrupt_val, Bit #(4) scause_code_val);
|
||||
return { scause_interrupt_val, 59'b0, scause_code_val };
|
||||
endfunction
|
||||
|
||||
// stval (sbadaddr in spike)
|
||||
Reg#(Data) stval_csr <- mkCsrReg(0);
|
||||
// sip: restricted view of mip
|
||||
Reg#(Data) sip_csr = concatReg9(
|
||||
readOnlyReg(54'b0),
|
||||
external_int_pend_vec[prvS], external_int_pend_vec[prvU],
|
||||
external_int_pend_vec[prvS], readOnlyReg(1'b0), // only if misa.N: external_int_pend_vec[prvU],
|
||||
readOnlyReg(2'b0),
|
||||
timer_int_pend_vec[prvS], timer_int_pend_vec[prvU],
|
||||
timer_int_pend_vec[prvS], readOnlyReg(1'b0), // only if misa.N: timer_int_pend_vec[prvU],
|
||||
readOnlyReg(2'b0),
|
||||
software_int_pend_vec[prvS], software_int_pend_vec[prvU]
|
||||
software_int_pend_vec[prvS], readOnlyReg(1'b0) // only if misa.N: software_int_pend_vec[prvU]
|
||||
);
|
||||
|
||||
// SIP and SIE fields are WARL (Write Any Read Legal)
|
||||
// We support S-privilege bits only;
|
||||
// this mask allows only those bits through.
|
||||
Data sip_sie_warl_mask = zeroExtend (12'h_222);
|
||||
|
||||
// satp (sptbr in spike): FIXME we only support Bare and Sv39, so we hack
|
||||
// the encoding of mode[3:0] field. Only mode[3] is relevant, other bits
|
||||
// are always 0
|
||||
@@ -501,6 +629,43 @@ module mkCsrFile #(Data hartid)(CsrFile);
|
||||
StatsCsr stats_module <- mkStatsCsr;
|
||||
Reg#(Data) stats_csr = stats_module.reg_ifc;
|
||||
|
||||
Reg #(Data) rg_tselect <- mkConfigReg (0);
|
||||
// Note: ISA test rv64mi-p-breakpoint assumes tdata1's reset value == 0
|
||||
// Until we implement trigger functionality,
|
||||
// force 'tdata1.type' field ([xlen-1:xlen-4]) to zero
|
||||
// meaning: 'There is no trigger at this tselect'
|
||||
Reg #(Bit #(4)) rg_tdata1_type <- mkReadOnlyReg (0);
|
||||
Reg #(Bit #(1)) rg_tdata1_dmode <- mkCsrReg (0);
|
||||
Reg #(Bit #(59)) rg_tdata1_data <- mkCsrReg (0);
|
||||
Reg #(Data) rg_tdata1 = concatReg3 (rg_tdata1_type, rg_tdata1_dmode, rg_tdata1_data);
|
||||
Reg #(Data) rg_tdata2 <- mkConfigRegU;
|
||||
Reg #(Data) rg_tdata3 <- mkConfigRegU;
|
||||
|
||||
`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:6] 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,16 +772,117 @@ module mkCsrFile #(Data hartid)(CsrFile);
|
||||
CSRmspec: mspec_csr;
|
||||
CSRtrng: trng_csr;
|
||||
`endif
|
||||
|
||||
CSRtselect: rg_tselect;
|
||||
CSRtdata1: rg_tdata1;
|
||||
CSRtdata2: rg_tdata2;
|
||||
CSRtdata3: rg_tdata3;
|
||||
|
||||
`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
|
||||
|
||||
// ================================================================
|
||||
// This function is the WARL (Write Any Read Legal) transform
|
||||
// performed during CSR writes. Currently it duplicates the logic
|
||||
// in the _write method of CSRs; ideally this function should be
|
||||
// separate from the _write method, which should remain as an
|
||||
// ordinary _write. The WARL'd value is needed for Tandem
|
||||
// Verification.
|
||||
|
||||
function Data fv_warl_xform (CSR csr, Data x);
|
||||
Asid x_asid = truncate (x [59:44]);
|
||||
Bit #(16) asid = zeroExtend (x_asid);
|
||||
return (
|
||||
case (csr)
|
||||
// Machine CSRs
|
||||
CSRmisa: {getXLBits, 36'b0, getExtensionBits(isa)};
|
||||
CSRmvendorid: 0;
|
||||
CSRmarchid: 0;
|
||||
CSRmimpid: 0;
|
||||
CSRmhartid: hartid;
|
||||
CSRmstatus: fn_mstatus_val (getXLBits, // sxl
|
||||
getXLBits, // uxl
|
||||
x [22], // tsr
|
||||
x [21], // tw
|
||||
x [20], // tvm
|
||||
x [19], // mxr
|
||||
x [18], // sum
|
||||
x [17], // mprv
|
||||
2'b0, // xs
|
||||
((isa.f || isa.d) ? x [14:13] : 2'b0), // fs
|
||||
x [12:11], // mpp
|
||||
x [8], // spp
|
||||
x [7], // prev_ie_vec[prvM]
|
||||
x [5], // prev_ie_vec[prvS]
|
||||
x [4], // prev_ie_vec[prvU]
|
||||
x [3], // ie_vec[prvM]
|
||||
x [1], // ie_vec[prvS]
|
||||
x [0]); // ie_vec[prvU]
|
||||
CSRmtvec: { x[63:2], 1'b0, x[0]};
|
||||
CSRmedeleg: { 48'b0, x[15], 1'b0, x[13:12], x[11], 1'b0, x[9:0]};
|
||||
CSRmideleg: { 52'b0, x[11], 1'b0, x[9:8], x[7], 1'b0, x[5:4], x[3], 1'b0, x[1:0]};
|
||||
CSRmip: ((mip_csr & (~ mip_mie_warl_mask)) | (x & mip_mie_warl_mask));
|
||||
CSRmie: (x & mip_mie_warl_mask);
|
||||
CSRmcounteren: { 61'b0, x[2:0]};
|
||||
CSRmcause: { x[63], 59'b0, x[3:0] };
|
||||
|
||||
CSRtdata1: { 4'b0, x [59:0] }; // Force tdata.type == 0 ("no trigger at this tselect")
|
||||
|
||||
// Supervisor level CSRs
|
||||
CSRsstatus: fn_sstatus_val (getXLBits, // uxl
|
||||
x [19], // mxr
|
||||
x [18], // sum
|
||||
2'b0, // xs
|
||||
((isa.f || isa.d) ? x [14:13] : 2'b0), // fs
|
||||
x [8], // spp
|
||||
x [5], // prev_ie_vec[prvS]
|
||||
x [4], // prev_ie_vec[prvU]
|
||||
x [1], // ie_vec[prvS]
|
||||
x [0]); // ie_vec[prvU]
|
||||
CSRstvec: { x[63:2], 1'b0, x[0]};
|
||||
CSRsip: ((sip_csr & (~ sip_sie_warl_mask)) | (x & sip_sie_warl_mask));
|
||||
CSRsie: (x & sip_sie_warl_mask);
|
||||
CSRscounteren: { 61'b0, x[2:0]};
|
||||
CSRscause: { x[63], 59'b0, x[3:0] };
|
||||
CSRsatp: { x[63], 3'b0, asid, x [43:0] };
|
||||
|
||||
// User level CSRs
|
||||
CSRfflags: { 59'b0, x [4:0] };
|
||||
CSRfrm: { 61'b0, x [2:0] };
|
||||
CSRfcsr: { 56'b0, x [7:0] };
|
||||
|
||||
`ifdef INCLUDE_GDB_CONTROL
|
||||
// Debug Mode CSRs
|
||||
CSRdcsr: { 32'b0, x[31:28], 12'b0, x[14], 1'b0, x[13:6], 1'b0, x[4:0] };
|
||||
`endif
|
||||
|
||||
default: x;
|
||||
endcase);
|
||||
endfunction
|
||||
|
||||
// ================================================================
|
||||
// INTERFACE
|
||||
|
||||
method Data rd(CSR csr);
|
||||
return get_csr(csr)._read;
|
||||
endmethod
|
||||
|
||||
method Action csrInstWr(CSR csr, Data x);
|
||||
get_csr(csr)._write(x);
|
||||
`ifdef INCLUDE_GDB_CONTROL
|
||||
if (csr == CSRdcsr) begin
|
||||
let prv = x [1:0];
|
||||
prv_reg <= prv;
|
||||
end
|
||||
`endif
|
||||
endmethod
|
||||
|
||||
method Bool fpuInstNeedWr(Bit#(5) fflags, Bool fpu_dirty);
|
||||
@@ -633,6 +899,35 @@ module mkCsrFile #(Data hartid)(CsrFile);
|
||||
fflags_reg <= fflags_reg | fflags;
|
||||
endmethod
|
||||
|
||||
`ifdef INCLUDE_TANDEM_VERIF
|
||||
method Tuple2 #(Bit #(5), Data) fpuInst_csr_updates (Bit #(5) fflags,
|
||||
Bool init_for_way0,
|
||||
Bit #(5) old_fflags,
|
||||
Data old_mstatus);
|
||||
|
||||
// Note: old_fflags and old_mstatus are accumulated in
|
||||
// sequential program order, and so may differ from fflags_reg
|
||||
// and mstatus_csr, which only change after superscalar-wide
|
||||
// retirement.
|
||||
|
||||
Bit #(5) old_fflags1 = (init_for_way0 ? fflags_reg : old_fflags);
|
||||
Data old_mstatus1 = (init_for_way0 ? mstatus_csr : old_mstatus);
|
||||
|
||||
Bit #(5) new_fflags = (old_fflags1 | fflags);
|
||||
Data new_mstatus = { 1'b1, old_mstatus1 [62:15], 2'b11, old_mstatus1 [12:0] };
|
||||
|
||||
return tuple2 (new_fflags, new_mstatus);
|
||||
endmethod
|
||||
|
||||
method Data getMIP;
|
||||
return mip_csr;
|
||||
endmethod
|
||||
`endif
|
||||
|
||||
method Data warl_xform (CSR csr, Data x);
|
||||
return fv_warl_xform (csr, x);
|
||||
endmethod
|
||||
|
||||
method Maybe#(Interrupt) pending_interrupt;
|
||||
// first get all the pending interrupts
|
||||
Bit#(InterruptNum) pend_ints = truncate(mie_csr & mip_csr);
|
||||
@@ -662,7 +957,7 @@ module mkCsrFile #(Data hartid)(CsrFile);
|
||||
end
|
||||
endmethod
|
||||
|
||||
method ActionValue#(Addr) trap(Trap t, Addr pc, Addr addr);
|
||||
method ActionValue#(Trap_Updates) trap(Trap t, Addr pc, Addr addr, Bit #(32) orig_inst);
|
||||
// figure out trap cause & trap val
|
||||
Bit#(1) cause_interrupt = 0;
|
||||
Bit#(4) cause_code = 0;
|
||||
@@ -671,6 +966,7 @@ module mkCsrFile #(Data hartid)(CsrFile);
|
||||
tagged Exception .e: begin
|
||||
cause_code = pack(e);
|
||||
trap_val = (case(e)
|
||||
IllegalInst: zeroExtend (orig_inst);
|
||||
InstAddrMisaligned, Breakpoint: return pc;
|
||||
|
||||
InstAccessFault, InstPageFault,
|
||||
@@ -716,7 +1012,25 @@ module mkCsrFile #(Data hartid)(CsrFile);
|
||||
scause_code_reg <= cause_code;
|
||||
stval_csr <= trap_val;
|
||||
// return next pc
|
||||
return getNextPc(stvec_mode_low_reg, stvec_base_hi_reg);
|
||||
// return getNextPc(stvec_mode_low_reg, stvec_base_hi_reg);
|
||||
Data sstatus_val = fn_sstatus_val (uxl_reg,
|
||||
mxr_reg, sum_reg,
|
||||
xs_reg, fs_reg,
|
||||
/* spp_reg */ prv_reg [0],
|
||||
/* prev_ie_vec_[prvS] */ ie_vec[prvS],
|
||||
prev_ie_vec [prvU],
|
||||
/* ie_vec [prvS] */ 0,
|
||||
ie_vec [prvU]);
|
||||
Data scause_val = fn_scause_val (cause_interrupt, cause_code);
|
||||
return Trap_Updates {new_pc: getNextPc(stvec_mode_low_reg, stvec_base_hi_reg)
|
||||
`ifdef INCLUDE_TANDEM_VERIF
|
||||
, prv: prvS,
|
||||
status: sstatus_val,
|
||||
cause: scause_val,
|
||||
epc: pc,
|
||||
tval: trap_val
|
||||
`endif
|
||||
};
|
||||
end
|
||||
else begin
|
||||
// ie/prv stack
|
||||
@@ -730,25 +1044,85 @@ module mkCsrFile #(Data hartid)(CsrFile);
|
||||
mcause_code_reg <= cause_code;
|
||||
mtval_csr <= trap_val;
|
||||
// return next pc
|
||||
return getNextPc(mtvec_mode_low_reg, mtvec_base_hi_reg);
|
||||
// return getNextPc(mtvec_mode_low_reg, mtvec_base_hi_reg);
|
||||
Data mstatus_val = fn_mstatus_val (sxl_reg, uxl_reg,
|
||||
tsr_reg, tw_reg, tvm_reg,
|
||||
mxr_reg, sum_reg, mprv_reg,
|
||||
xs_reg, fs_reg,
|
||||
/* mpp */ prv_reg, spp_reg,
|
||||
/* prev_ie_vec [prvM] */ ie_vec [prvM],
|
||||
prev_ie_vec [prvS],
|
||||
prev_ie_vec [prvU],
|
||||
/* ie_vec [prvM] */ 0,
|
||||
ie_vec [prvS],
|
||||
ie_vec [prvU]);
|
||||
Data mcause_val = fn_mcause_val (cause_interrupt, cause_code);
|
||||
return Trap_Updates {new_pc: getNextPc(mtvec_mode_low_reg, mtvec_base_hi_reg)
|
||||
`ifdef INCLUDE_TANDEM_VERIF
|
||||
, prv: prvM,
|
||||
status: mstatus_val,
|
||||
cause: mcause_val,
|
||||
epc: pc,
|
||||
tval: trap_val
|
||||
`endif
|
||||
};
|
||||
end
|
||||
// XXX yield load reservation should be done outside this method
|
||||
endmethod
|
||||
|
||||
method ActionValue#(Addr) mret;
|
||||
method ActionValue#(RET_Updates) mret;
|
||||
prv_reg <= prev_prv_vec[prvM];
|
||||
prev_prv_vec[prvM] <= prvU;
|
||||
ie_vec[prvM] <= prev_ie_vec[prvM];
|
||||
prev_ie_vec[prvM] <= 1;
|
||||
return mepc_csr;
|
||||
|
||||
Data mstatus_val = fn_mstatus_val(sxl_reg, uxl_reg,
|
||||
tsr_reg, tw_reg, tvm_reg,
|
||||
mxr_reg, sum_reg, mprv_reg,
|
||||
xs_reg, fs_reg,
|
||||
/* mpp */ prvU,
|
||||
spp_reg,
|
||||
/* prev_ie_vec [prvM] */ 1,
|
||||
prev_ie_vec [prvS],
|
||||
prev_ie_vec [prvU],
|
||||
/* ie_vec [prvM] */ prev_ie_vec[prvM],
|
||||
ie_vec [prvS],
|
||||
ie_vec [prvU]);
|
||||
return RET_Updates {new_pc: mepc_csr
|
||||
`ifdef INCLUDE_TANDEM_VERIF
|
||||
, prv: prev_prv_vec[prvM],
|
||||
status: mstatus_val
|
||||
`endif
|
||||
};
|
||||
endmethod
|
||||
|
||||
method ActionValue#(Addr) sret;
|
||||
method ActionValue#(RET_Updates) sret;
|
||||
prv_reg <= prev_prv_vec[prvS];
|
||||
prev_prv_vec[prvS] <= prvU;
|
||||
ie_vec[prvS] <= prev_ie_vec[prvS];
|
||||
prev_ie_vec[prvS] <= 1;
|
||||
return sepc_csr;
|
||||
|
||||
// For Tandem Verification, we return the full underlying MSTATUS register
|
||||
Data mstatus_val = fn_mstatus_val(sxl_reg, uxl_reg,
|
||||
tsr_reg, tw_reg, tvm_reg,
|
||||
mxr_reg, sum_reg, mprv_reg,
|
||||
xs_reg, fs_reg,
|
||||
mpp_reg,
|
||||
/* spp_reg */ prvU [0],
|
||||
|
||||
prev_ie_vec [prvM],
|
||||
/* prev_ie_vec_[prvS] */ 1,
|
||||
prev_ie_vec [prvU],
|
||||
|
||||
ie_vec [prvM],
|
||||
/* ie_vec [prvS] */ prev_ie_vec[prvS],
|
||||
ie_vec [prvU]);
|
||||
return RET_Updates {new_pc: sepc_csr
|
||||
`ifdef INCLUDE_TANDEM_VERIF
|
||||
, prv: prev_prv_vec[prvS],
|
||||
status: mstatus_val
|
||||
`endif
|
||||
};
|
||||
endmethod
|
||||
|
||||
method VMInfo vmI;
|
||||
@@ -845,15 +1219,53 @@ module mkCsrFile #(Data hartid)(CsrFile);
|
||||
external_int_pend_vec[prvS] <= v;
|
||||
endmethod
|
||||
|
||||
// Bluespec: external interrupt to enter debug mode
|
||||
method Action setDEIP (Bit #(1) v);
|
||||
debug_int_pend <= v;
|
||||
endmethod
|
||||
|
||||
method terminate = terminate_module.terminate;
|
||||
|
||||
// performance stats
|
||||
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
|
||||
// Is invoked by logic that stops a hart, to enter Debug Mode
|
||||
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 };
|
||||
|
||||
/*
|
||||
$display ("%0d: %m mkCsrFile.method-dcsr_cause_write: cause %0d, prv %0d",
|
||||
cur_cycle, dcsr_cause, prv_reg);
|
||||
*/
|
||||
endmethod
|
||||
|
||||
`endif
|
||||
|
||||
endmodule
|
||||
|
||||
@@ -107,8 +107,7 @@ module mkLLC_AXi4_Adapter #(MemFifoClient #(idT, childT) llc)
|
||||
awregion: fabric_default_region,
|
||||
awuser: fabric_default_user};
|
||||
|
||||
let mem_req_wr_data = AXI4_Wr_Data {wid: fabric_default_id,
|
||||
wdata: st_val,
|
||||
let mem_req_wr_data = AXI4_Wr_Data {wdata: st_val,
|
||||
wstrb: strb,
|
||||
wlast: True,
|
||||
wuser: fabric_default_user};
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
|
||||
// Copyright (c) 2018 Massachusetts Institute of Technology
|
||||
// Portions (c) 2019-2020 Bluespec, Inc.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person
|
||||
// obtaining a copy of this software and associated documentation
|
||||
@@ -21,8 +22,6 @@
|
||||
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
|
||||
// Portions (c) 2019 Bluespec, Inc.
|
||||
|
||||
// This file is adapted from: MIT-riscy/riscy-OOO/procs/lib/MMIOPlatform.bsv
|
||||
// Modifications to fit into Bluespec's RISC-V execution environments.
|
||||
|
||||
@@ -289,7 +288,8 @@ module mkMMIOPlatform #(Vector#(CoreNum, MMIOCoreToPlatform) cores,
|
||||
// To avoid posting timer interrupt repeatedly, we keep a copy of MTIP
|
||||
// here. Since each core cannot write MTIP by CSRXXX inst, the only way to
|
||||
// change MTIP is through here.
|
||||
Vector#(CoreNum, Reg#(Bool)) mtip <- replicateM(mkReg(False));
|
||||
// We initialize to True to avoid an timer interrupt at start of time.
|
||||
Vector#(CoreNum, Reg#(Bool)) mtip <- replicateM(mkReg(True));
|
||||
|
||||
// pass mtime to each core
|
||||
rule propagateTime(state != Init);
|
||||
|
||||
@@ -1,5 +1,14 @@
|
||||
// Copyright (c) 2019-2020 Bluespec, Inc.
|
||||
|
||||
package MMIO_AXI4_Adapter;
|
||||
|
||||
// ================================================================
|
||||
// This is an adapter to connect MIT's RISCY-OOO to an AXI4 fabric in
|
||||
// Bluespec's Toooba setup. All IO traffic to the fabric flows through
|
||||
// this. Note: a few IO addresses (e.g., MTIME, MTIMECMP, MSIP,
|
||||
// TOHOST, FROMHOST are intercepted and handled before they reach this
|
||||
// adapter).
|
||||
|
||||
// ================================================================
|
||||
// BSV lib imports
|
||||
|
||||
@@ -30,6 +39,7 @@ import ProcTypes :: *;
|
||||
|
||||
import AXI4_Types :: *;
|
||||
import Fabric_Defs :: *;
|
||||
import SoC_Map :: *;
|
||||
|
||||
// ================================================================
|
||||
|
||||
@@ -56,6 +66,8 @@ module mkMMIO_AXI4_Adapter (MMIO_AXI4_Adapter_IFC);
|
||||
FIFOF #(MMIOCRq) f_reqs_from_core <- mkFIFOF;
|
||||
FIFOF #(MMIODataPRs) f_rsps_to_core <- mkFIFOF;
|
||||
|
||||
SoC_Map_IFC soc_map <- mkSoC_Map; // for m_is_IO_addr
|
||||
|
||||
// ================================================================
|
||||
// Fabric request/response
|
||||
|
||||
@@ -108,12 +120,26 @@ module mkMMIO_AXI4_Adapter (MMIO_AXI4_Adapter_IFC);
|
||||
awregion: fabric_default_region,
|
||||
awuser: fabric_default_user};
|
||||
|
||||
let mem_req_wr_data = AXI4_Wr_Data {wid: fabric_default_id,
|
||||
wdata: st_val,
|
||||
let mem_req_wr_data = AXI4_Wr_Data {wdata: st_val,
|
||||
wstrb: strb,
|
||||
wlast: True,
|
||||
wuser: fabric_default_user};
|
||||
|
||||
`ifdef FABRIC64
|
||||
// Work-around for a misbehavior on Xilinx UART and its
|
||||
// Xilinx AXI4 adapter. On 64-bit fabrics, for a write where
|
||||
// axsize says '8 bytes' but wstrb is for <= 4 bytes, the
|
||||
// adapter converts it two 32-bit writes, one of which has
|
||||
// wstrb=4'b0000. The Xilinx UART, in turn ignores wstrb and
|
||||
// therefore performs a spurious write. This workaround
|
||||
// changes axsize for such writes to '4 bytes', avoiding this
|
||||
// problem.
|
||||
|
||||
if (strb [7:4] == 0 || strb [3:0] == 0) begin
|
||||
mem_req_wr_addr.awsize = axsize_4;
|
||||
end
|
||||
`endif
|
||||
|
||||
master_xactor.i_wr_addr.enq (mem_req_wr_addr);
|
||||
master_xactor.i_wr_data.enq (mem_req_wr_data);
|
||||
|
||||
@@ -122,8 +148,8 @@ module mkMMIO_AXI4_Adapter (MMIO_AXI4_Adapter_IFC);
|
||||
|
||||
// Debugging
|
||||
if (cfg_verbosity > 0) begin
|
||||
$display (" To fabric: ", fshow (mem_req_wr_addr));
|
||||
$display (" ", fshow (mem_req_wr_data));
|
||||
$display (" To fabric: ", fshow (mem_req_wr_addr));
|
||||
$display (" ", fshow (mem_req_wr_data));
|
||||
end
|
||||
endaction
|
||||
endfunction
|
||||
@@ -138,11 +164,25 @@ module mkMMIO_AXI4_Adapter (MMIO_AXI4_Adapter_IFC);
|
||||
let req <- pop (f_reqs_from_core);
|
||||
|
||||
if (cfg_verbosity > 0) begin
|
||||
$display ("%0d: MMIO_AXI4_Adapter.rl_handle_read_req: Ld request", cur_cycle);
|
||||
$display ("%0d: %m.rl_handle_read_req: Ld request", cur_cycle);
|
||||
$display (" ", fshow (req));
|
||||
end
|
||||
|
||||
fa_fabric_send_read_req (req.addr);
|
||||
// Technically the following check for legal IO addrs is not
|
||||
// necessary; the AXI4 fabric should return a DECERR for illegal
|
||||
// addrs; but not all AXI4 fabrics do the right thing.
|
||||
if (soc_map.m_is_IO_addr (req.addr))
|
||||
fa_fabric_send_read_req (req.addr);
|
||||
else begin
|
||||
let rsp = MMIODataPRs {valid: False,
|
||||
data: req.addr}; // For debugging convenience only
|
||||
f_rsps_to_core.enq (rsp);
|
||||
if (cfg_verbosity > 0) begin
|
||||
$display ("%0d: %m.rl_handle_read_req: unmapped IO address; returning error response",
|
||||
cur_cycle);
|
||||
$display (" ", fshow (req));
|
||||
end
|
||||
end
|
||||
endrule
|
||||
|
||||
// ----------------
|
||||
@@ -151,12 +191,12 @@ module mkMMIO_AXI4_Adapter (MMIO_AXI4_Adapter_IFC);
|
||||
let mem_rsp <- pop_o (master_xactor.o_rd_data);
|
||||
|
||||
if (cfg_verbosity > 0) begin
|
||||
$display ("%0d: MMIO_AXI4_Adapter.rl_handle_read_rsps ", cur_cycle);
|
||||
$display ("%0d: %m.rl_handle_read_rsps ", cur_cycle);
|
||||
$display (" ", fshow (mem_rsp));
|
||||
end
|
||||
|
||||
if ((cfg_verbosity > 0) && (mem_rsp.rresp != axi4_resp_okay)) begin
|
||||
$display ("%0d: MMIO_AXI4_Adapter.rl_handle_read_rsp: fabric response error", cur_cycle);
|
||||
$display ("%0d: %m.rl_handle_read_rsp: fabric response error", cur_cycle);
|
||||
$display (" ", fshow (mem_rsp));
|
||||
end
|
||||
|
||||
@@ -175,11 +215,25 @@ module mkMMIO_AXI4_Adapter (MMIO_AXI4_Adapter_IFC);
|
||||
let req <- pop (f_reqs_from_core);
|
||||
|
||||
if (cfg_verbosity > 0) begin
|
||||
$display ("%d: MMIO_AXI4_Adapter.rl_handle_write_req: St request:", cur_cycle);
|
||||
$display ("%d: %m.rl_handle_write_req: St request:", cur_cycle);
|
||||
$display (" ", fshow (req));
|
||||
end
|
||||
|
||||
fa_fabric_send_write_req (req.addr, pack (req.byteEn), req.data);
|
||||
// Technically the following check for legal IO addrs is not
|
||||
// necessary; the AXI4 fabric should return a DECERR for illegal
|
||||
// addrs; but not all AXI4 fabrics do the right thing.
|
||||
if (soc_map.m_is_IO_addr (req.addr))
|
||||
fa_fabric_send_write_req (req.addr, pack (req.byteEn), req.data);
|
||||
else begin
|
||||
let rsp = MMIODataPRs {valid: False,
|
||||
data: req.addr}; // For debugging convenience only
|
||||
f_rsps_to_core.enq (rsp);
|
||||
if (cfg_verbosity > 0) begin
|
||||
$display ("%0d: %m.rl_handle_write_req: unmapped IO address; returning error response",
|
||||
cur_cycle);
|
||||
$display (" ", fshow (req));
|
||||
end
|
||||
end
|
||||
endrule
|
||||
|
||||
// ----------------
|
||||
@@ -189,12 +243,12 @@ module mkMMIO_AXI4_Adapter (MMIO_AXI4_Adapter_IFC);
|
||||
let wr_resp <- pop_o (master_xactor.o_wr_resp);
|
||||
|
||||
if (cfg_verbosity > 0) begin
|
||||
$display ("%0d: MMIO_AXI4_Adapter.rl_discard_write_rsp", cur_cycle);
|
||||
$display ("%0d: %m.rl_discard_write_rsp", cur_cycle);
|
||||
$display (" ", fshow (wr_resp));
|
||||
end
|
||||
|
||||
if (ctr_wr_rsps_pending.value == 0) begin
|
||||
$display ("%0d: ERROR: MMIO_AXI4_Adapter.rl_discard_write_rsp: unexpected Wr response (ctr_wr_rsps_pending.value == 0)",
|
||||
$display ("%0d:%m.rl_discard_write_rsp: ERROR:unexpected Wr response (ctr_wr_rsps_pending.value == 0)",
|
||||
cur_cycle);
|
||||
$display (" ", fshow (wr_resp));
|
||||
$finish (1); // Assertion failure
|
||||
@@ -204,7 +258,7 @@ module mkMMIO_AXI4_Adapter (MMIO_AXI4_Adapter_IFC);
|
||||
|
||||
if (wr_resp.bresp != axi4_resp_okay) begin
|
||||
// TODO: need to raise a non-maskable interrupt (NMI) here
|
||||
$display ("%0d: MMIO_AXI4_Adapter.rl_discard_write_rsp: fabric response error: exit", cur_cycle);
|
||||
$display ("%0d:%m.rl_discard_write_rsp: ERROR: fabric response error: exit.", cur_cycle);
|
||||
$display (" ", fshow (wr_resp));
|
||||
$finish (1);
|
||||
end
|
||||
@@ -228,8 +282,7 @@ module mkMMIO_AXI4_Adapter (MMIO_AXI4_Adapter_IFC);
|
||||
rule rl_handle_non_Ld_St (! fn_is_Ld_or_St (f_reqs_from_core.first));
|
||||
let req <- pop (f_reqs_from_core);
|
||||
|
||||
$display ("%0d: ERROR: MMIO_AXI4_Adapter.rl_handle_non_Ld_St",
|
||||
cur_cycle);
|
||||
$display ("%0d:%m.rl_handle_non_Ld_St: ERROR: neither Ld nor St? exit.", cur_cycle);
|
||||
$display (" ", fshow (req));
|
||||
$finish (1); // Assertion failure
|
||||
endrule
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
package Proc;
|
||||
|
||||
// Note: this module corresponds to module 'mkCPU' in Piccolo/Flute.
|
||||
|
||||
// Copyright (c) 2018 Massachusetts Institute of Technology
|
||||
// Portions Copyright (c) 2019-2020 Bluespec, Inc.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person
|
||||
// obtaining a copy of this software and associated documentation
|
||||
@@ -22,8 +25,6 @@ package Proc;
|
||||
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
|
||||
// Portions Copyright (c) 2019 Bluespec, Inc.
|
||||
|
||||
// ================================================================
|
||||
// BSV lib imports
|
||||
|
||||
@@ -77,17 +78,13 @@ 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
|
||||
import ProcTypes :: *;
|
||||
import Trace_Data2 :: *;
|
||||
`endif
|
||||
|
||||
// ================================================================
|
||||
@@ -108,50 +105,6 @@ module mkProc (Proc_IFC);
|
||||
// Verbosity: 0=quiet; 1=instruction trace; 2=more detail
|
||||
Reg #(Bit #(4)) cfg_verbosity <- mkConfigReg (0);
|
||||
|
||||
// ----------------
|
||||
// Reset requests and responses (TODO: to be implemented)
|
||||
|
||||
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)
|
||||
|
||||
`ifdef INCLUDE_TANDEM_VERIF
|
||||
FIFOF #(Trace_Data) f_trace_data <- mkFIFOF;
|
||||
`endif
|
||||
|
||||
// ----------------
|
||||
// MMIO
|
||||
|
||||
@@ -185,16 +138,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);
|
||||
|
||||
@@ -249,18 +197,6 @@ module mkProc (Proc_IFC);
|
||||
end
|
||||
|
||||
// ================================================================
|
||||
// Reset
|
||||
|
||||
rule rl_reset;
|
||||
let x <- pop (f_reset_reqs);
|
||||
|
||||
llc_axi4_adapter.reset;
|
||||
mmio_axi4_adapter.reset;
|
||||
|
||||
f_reset_rsps.enq (?);
|
||||
endrule
|
||||
|
||||
// ----------------
|
||||
// Termination detection
|
||||
|
||||
for(Integer i = 0; i < valueof(CoreNum); i = i+1) begin
|
||||
@@ -270,7 +206,9 @@ module mkProc (Proc_IFC);
|
||||
endrule
|
||||
end
|
||||
|
||||
// ================================================================
|
||||
// Print out values written 'tohost'
|
||||
|
||||
rule rl_tohost;
|
||||
let x <- mmioPlatform.to_host;
|
||||
$display ("%0d: mmioPlatform.rl_tohost: 0x%0x (= %0d)", cur_cycle, x, x);
|
||||
@@ -292,11 +230,9 @@ module mkProc (Proc_IFC);
|
||||
// ================================================================
|
||||
// INTERFACE
|
||||
|
||||
// Reset
|
||||
interface Server hart0_server_reset = toGPServer (f_reset_reqs, f_reset_rsps);
|
||||
|
||||
// ----------------
|
||||
// Start the cores running
|
||||
// Use toHostAddr = 0 if not monitoring tohost
|
||||
method Action start (Addr startpc, Addr tohostAddr, Addr fromhostAddr);
|
||||
action
|
||||
for(Integer i = 0; i < valueof(CoreNum); i = i+1)
|
||||
@@ -305,8 +241,8 @@ module mkProc (Proc_IFC);
|
||||
|
||||
mmioPlatform.start (tohostAddr, fromhostAddr);
|
||||
|
||||
$display ("Proc.start: startpc = 0x%0h, tohostAddr = 0x%0h, fromhostAddr = %0h",
|
||||
startpc, tohostAddr, fromhostAddr);
|
||||
$display ("%0d: %m.method start: startpc %0h, tohostAddr %0h, fromhostAddr %0h",
|
||||
cur_cycle, startpc, tohostAddr, fromhostAddr);
|
||||
endmethod
|
||||
|
||||
// ----------------
|
||||
@@ -329,13 +265,6 @@ module mkProc (Proc_IFC);
|
||||
core[0].setSEIP (pack (x));
|
||||
endmethod
|
||||
|
||||
// ----------------
|
||||
// External interrupt [14] to go into Debug Mode
|
||||
|
||||
method Action debug_external_interrupt_req (Bool set_not_clear);
|
||||
core[0].setDEIP (pack (set_not_clear));
|
||||
endmethod
|
||||
|
||||
// ----------------
|
||||
// Non-maskable interrupt
|
||||
|
||||
@@ -350,11 +279,9 @@ module mkProc (Proc_IFC);
|
||||
endmethod
|
||||
|
||||
// ----------------
|
||||
// Optional interface to Tandem Verifier
|
||||
// Coherent port into LLC (used by Debug Module, DMA engines, ... to read/write memory)
|
||||
|
||||
`ifdef INCLUDE_TANDEM_VERIF
|
||||
interface Get trace_data_out = toGet (f_trace_data);
|
||||
`endif
|
||||
interface debug_module_mem_server = llc_mem_server;
|
||||
|
||||
`ifdef RVFI_DII
|
||||
interface Toooba_RVFI_DII_Server rvfi_dii_server = core[0].rvfi_dii_server;
|
||||
@@ -364,8 +291,8 @@ 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 Put hart0_put_other_req;
|
||||
method Action put (Bit #(4) req);
|
||||
@@ -373,16 +300,16 @@ module mkProc (Proc_IFC);
|
||||
endmethod
|
||||
endinterface
|
||||
|
||||
// GPR access
|
||||
interface Server hart0_gpr_mem_server = toGPServer (f_gpr_reqs, f_gpr_rsps);
|
||||
|
||||
interface Server hart0_gpr_mem_server = core[0].hart0_gpr_mem_server;
|
||||
`ifdef ISA_F
|
||||
// FPR access
|
||||
interface Server hart0_fpr_mem_server = toGPServer (f_fpr_reqs, f_fpr_rsps);
|
||||
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;
|
||||
|
||||
`endif
|
||||
|
||||
// CSR access
|
||||
interface Server hart0_csr_mem_server = toGPServer (f_csr_reqs, f_csr_rsps);
|
||||
`ifdef INCLUDE_TANDEM_VERIF
|
||||
interface v_to_TV = core [0].v_to_TV;
|
||||
`endif
|
||||
|
||||
endmodule: mkProc
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
// Copyright (c) 2016-2019 Bluespec, Inc. All Rights Reserved
|
||||
// Copyright (c) 2016-2020 Bluespec, Inc. All Rights Reserved
|
||||
|
||||
package Proc_IFC;
|
||||
|
||||
// ================================================================
|
||||
// BSV library imports
|
||||
|
||||
import Vector :: *;
|
||||
import GetPut :: *;
|
||||
import ClientServer :: *;
|
||||
|
||||
@@ -21,7 +22,8 @@ import DM_CPU_Req_Rsp :: *;
|
||||
`endif
|
||||
|
||||
`ifdef INCLUDE_TANDEM_VERIF
|
||||
import TV_Info :: *;
|
||||
import ProcTypes :: *;
|
||||
import Trace_Data2 :: *;
|
||||
`endif
|
||||
|
||||
`ifdef RVFI_DII
|
||||
@@ -36,11 +38,10 @@ import Types :: *;
|
||||
// because the RISCY-OOO mkProc contains those elements.
|
||||
|
||||
interface Proc_IFC;
|
||||
// Reset
|
||||
interface Server #(Token, Token) hart0_server_reset;
|
||||
|
||||
// ----------------
|
||||
// Start the cores running
|
||||
// Use toHostAddr = 0 if not monitoring tohost
|
||||
method Action start (Addr startpc, Addr tohostAddr, Addr fromhostAddr);
|
||||
|
||||
// ----------------
|
||||
@@ -61,12 +62,6 @@ interface Proc_IFC;
|
||||
(* always_ready, always_enabled *)
|
||||
method Action s_external_interrupt_req (Bool set_not_clear);
|
||||
|
||||
// ----------------
|
||||
// External interrupt [14] to go into Debug Mode
|
||||
|
||||
(* always_ready, always_enabled *)
|
||||
method Action debug_external_interrupt_req (Bool set_not_clear);
|
||||
|
||||
// ----------------
|
||||
// Non-maskable interrupt
|
||||
|
||||
@@ -79,11 +74,9 @@ interface Proc_IFC;
|
||||
method Action set_verbosity (Bit #(4) verbosity);
|
||||
|
||||
// ----------------
|
||||
// Optional interface to Tandem Verifier
|
||||
// Coherent port into LLC (used by Debug Module, DMA engines, ... to read/write memory)
|
||||
|
||||
`ifdef INCLUDE_TANDEM_VERIF
|
||||
interface Get #(Trace_Data) trace_data_out;
|
||||
`endif
|
||||
interface AXI4_Slave_IFC #(Wd_Id, Wd_Addr, Wd_Data, Wd_User) debug_module_mem_server;
|
||||
|
||||
`ifdef RVFI_DII
|
||||
interface Toooba_RVFI_DII_Server rvfi_dii_server;
|
||||
@@ -93,20 +86,24 @@ 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;
|
||||
|
||||
// Non-standard
|
||||
interface Put #(Bit #(4)) hart0_put_other_req;
|
||||
`endif
|
||||
|
||||
`ifdef INCLUDE_TANDEM_VERIF
|
||||
// Note: this is a SupSize vector of streams of Trace_Data2 structs,
|
||||
// each of which has a serialnum field. Each of the SupSize
|
||||
// streams has serialnums in increasing order. Each serialnum
|
||||
// appears exactly once in exactly one of the streams. Thus, the
|
||||
// channels can easily be merged into a single program-order stream.
|
||||
interface Vector #(SupSize, Get #(Trace_Data2)) v_to_TV;
|
||||
`endif
|
||||
|
||||
endinterface
|
||||
|
||||
Reference in New Issue
Block a user