Prefetcher implementation in both L1 and LL and data logging
This commit is contained in:
@@ -131,7 +131,7 @@ import Trace_Data2 :: *;
|
||||
|
||||
// ================================================================
|
||||
|
||||
`ifdef SECURITY
|
||||
`ifdef SECURITY_BRPRED
|
||||
`define SECURITY_OR_INCLUDE_GDB_CONTROL
|
||||
`elsif INCLUDE_GDB_CONTROL
|
||||
`define SECURITY_OR_INCLUDE_GDB_CONTROL
|
||||
@@ -364,7 +364,7 @@ module mkCore#(CoreId coreId)(Core);
|
||||
);
|
||||
|
||||
// whether perf data is collected
|
||||
Reg#(Bool) doStatsReg <- mkConfigReg(False);
|
||||
Reg#(Bool) doStatsReg <- mkConfigReg(True);
|
||||
|
||||
// write aggressive elements + wakupe reservation stations
|
||||
function Action writeAggr(Integer wrAggrPort, PhyRIndx dst);
|
||||
@@ -830,8 +830,8 @@ module mkCore#(CoreId coreId)(Core);
|
||||
// to finish
|
||||
rule flushCaches(doFlushCaches);
|
||||
flush_caches <= False;
|
||||
iMem.flush;
|
||||
dMem.flush;
|
||||
//iMem.flush;
|
||||
//dMem.flush;
|
||||
// $display ("%0d: %m.rule flushCaches (imem and dmem)", cur_cycle);
|
||||
endrule
|
||||
|
||||
|
||||
@@ -237,6 +237,90 @@ module mkProc (Proc_IFC);
|
||||
endrule
|
||||
end
|
||||
|
||||
// ================================================================
|
||||
// Send and print perf requests
|
||||
|
||||
Reg#(Bit#(4)) perfCnt <- mkReg(0);
|
||||
Reg#(Bool) requestSent <- mkReg(False);
|
||||
rule rl_sendLLCPerfReq if (!requestSent);
|
||||
perfCnt <= (perfCnt == 12) ? 0 : perfCnt + 1;
|
||||
case (perfCnt)
|
||||
'b1001: llc.perf.req(LLCNormalMemLdCnt);
|
||||
'b1010: llc.perf.req(LLCNormalMemLdLat);
|
||||
'b1011: llc.perf.req(LLCInstructionLdCnt);
|
||||
'b1100: llc.perf.req(LLCInstructionLdLat);
|
||||
endcase
|
||||
requestSent <= True;
|
||||
endrule
|
||||
rule rl_printLLCPerfResp;
|
||||
let perfResp <- llc.perf.resp;
|
||||
requestSent <= False;
|
||||
if (perfResp.pType == LLCNormalMemLdCnt) begin
|
||||
$display("%0d: LLC data miss count: %d", cur_cycle, unpack(perfResp.data));
|
||||
end
|
||||
else if (perfResp.pType == LLCNormalMemLdLat) begin
|
||||
$display("%0d: LLC data miss latency: %d", cur_cycle, unpack(perfResp.data));
|
||||
end
|
||||
else if (perfResp.pType == LLCInstructionLdCnt) begin
|
||||
$display("%0d: LLC instruction miss count: %d", cur_cycle, unpack(perfResp.data));
|
||||
end
|
||||
else if (perfResp.pType == LLCInstructionLdLat) begin
|
||||
$display("%0d: LLC instruction miss latency: %d", cur_cycle, unpack(perfResp.data));
|
||||
end
|
||||
endrule
|
||||
|
||||
for(Integer i = 0; i < valueof(CoreNum); i = i+1) begin
|
||||
rule rl_sendPerfReq if (!requestSent);
|
||||
case (perfCnt)
|
||||
'b0000: core[i].coreReq.perfReq(ICache, zeroExtend(pack(L1ILdCnt)));
|
||||
'b0001: core[i].coreReq.perfReq(ICache, zeroExtend(pack(L1ILdMissCnt)));
|
||||
'b0010: core[i].coreReq.perfReq(ICache, zeroExtend(pack(L1ILdMissLat)));
|
||||
'b0011: core[i].coreReq.perfReq(DCache, zeroExtend(pack(L1DLdCnt)));
|
||||
'b0100: core[i].coreReq.perfReq(DCache, zeroExtend(pack(L1DLdMissCnt)));
|
||||
'b0101: core[i].coreReq.perfReq(DCache, zeroExtend(pack(L1DLdMissLat)));
|
||||
'b0110: core[i].coreReq.perfReq(DCache, zeroExtend(pack(L1DStCnt)));
|
||||
'b0111: core[i].coreReq.perfReq(DCache, zeroExtend(pack(L1DStMissCnt)));
|
||||
'b1000: core[i].coreReq.perfReq(DCache, zeroExtend(pack(L1DStMissLat)));
|
||||
endcase
|
||||
endrule
|
||||
|
||||
rule rl_printPerfResp;
|
||||
let perfResp <- core[i].coreIndInv.perfResp;
|
||||
requestSent <= False;
|
||||
if (perfResp.loc == ICache) begin
|
||||
if (perfResp.pType == zeroExtend(pack(L1ILdCnt))) begin
|
||||
$display("%0d: L1I load count: %d", cur_cycle, unpack(perfResp.data));
|
||||
end
|
||||
else if (perfResp.pType == zeroExtend(pack(L1ILdMissCnt))) begin
|
||||
$display("%0d: L1I load miss count: %d", cur_cycle, unpack(perfResp.data));
|
||||
end
|
||||
else if (perfResp.pType == zeroExtend(pack(L1ILdMissLat))) begin
|
||||
$display("%0d: L1I load miss latency: %d", cur_cycle, unpack(perfResp.data));
|
||||
end
|
||||
end
|
||||
else if (perfResp.loc == DCache) begin
|
||||
if (perfResp.pType == zeroExtend(pack(L1DLdCnt))) begin
|
||||
$display("%0d: L1D load count: %d", cur_cycle, unpack(perfResp.data));
|
||||
end
|
||||
else if (perfResp.pType == zeroExtend(pack(L1DLdMissCnt))) begin
|
||||
$display("%0d: L1D load miss count: %d", cur_cycle, unpack(perfResp.data));
|
||||
end
|
||||
else if (perfResp.pType == zeroExtend(pack(L1DLdMissLat))) begin
|
||||
$display("%0d: L1D load miss latency: %d", cur_cycle, unpack(perfResp.data));
|
||||
end
|
||||
if (perfResp.pType == zeroExtend(pack(L1DStCnt))) begin
|
||||
$display("%0d: L1D store count: %d", cur_cycle, unpack(perfResp.data));
|
||||
end
|
||||
else if (perfResp.pType == zeroExtend(pack(L1DStMissCnt))) begin
|
||||
$display("%0d: L1D store miss count: %d", cur_cycle, unpack(perfResp.data));
|
||||
end
|
||||
else if (perfResp.pType == zeroExtend(pack(L1DStMissLat))) begin
|
||||
$display("%0d: L1D store miss latency: %d", cur_cycle, unpack(perfResp.data));
|
||||
end
|
||||
end
|
||||
endrule
|
||||
end
|
||||
|
||||
// ================================================================
|
||||
// Print out values written 'tohost'
|
||||
|
||||
|
||||
@@ -108,6 +108,7 @@ copy_coherence_src_files:
|
||||
cp -p $(RISCY_HOME)/$(COHERENCE_SRC)/LLCRqMshr.bsv ./$(COHERENCE_SRC)/
|
||||
cp -p $(RISCY_HOME)/$(COHERENCE_SRC)/LLPipe.bsv ./$(COHERENCE_SRC)/
|
||||
cp -p $(RISCY_HOME)/$(COHERENCE_SRC)/MshrDeadlockChecker.bsv ./$(COHERENCE_SRC)/
|
||||
cp -p $(RISCY_HOME)/$(COHERENCE_SRC)/Prefetcher.bsv ./$(COHERENCE_SRC)/
|
||||
cp -p $(RISCY_HOME)/$(COHERENCE_SRC)/RandomReplace.bsv ./$(COHERENCE_SRC)/
|
||||
cp -p $(RISCY_HOME)/$(COHERENCE_SRC)/RWBramCore.bsv ./$(COHERENCE_SRC)/
|
||||
cp -p $(RISCY_HOME)/$(COHERENCE_SRC)/SelfInvIBank.bsv ./$(COHERENCE_SRC)/
|
||||
|
||||
@@ -205,6 +205,7 @@ typedef struct {
|
||||
MemTaggedData data; // valid when op == Sc/Amo
|
||||
AmoInst amoInst; // valid when op == Amo
|
||||
Bool loadTags; // valid when op == Ld
|
||||
Bit#(16) pcHash; // hash of instruction pc sending the request
|
||||
} ProcRq#(type idT) deriving(Bits, Eq, FShow);
|
||||
|
||||
interface L1ProcReq#(type idT);
|
||||
|
||||
@@ -57,6 +57,7 @@ import CacheUtils::*;
|
||||
import Performance::*;
|
||||
import LatencyTimer::*;
|
||||
import RandomReplace::*;
|
||||
import Prefetcher::*;
|
||||
`ifdef PERFORMANCE_MONITORING
|
||||
import PerformanceMonitor::*;
|
||||
import BlueUtils::*;
|
||||
@@ -142,7 +143,7 @@ module mkIBank#(
|
||||
Add#(TAdd#(tagSz, indexSz), TAdd#(lgBankNum, LgLineSzBytes), AddrSz)
|
||||
);
|
||||
|
||||
Bool verbose = False;
|
||||
Bool verbose = False;
|
||||
|
||||
ICRqMshr#(cRqNum, wayT, tagT, procRqT, resultT) cRqMshr <- mkICRqMshrLocal;
|
||||
|
||||
@@ -165,6 +166,11 @@ module mkIBank#(
|
||||
|
||||
// index Q to order all in flight cRq for in-order resp
|
||||
FIFO#(cRqIdxT) cRqIndexQ <- mkSizedFIFO(valueof(cRqNum));
|
||||
FIFO#(cRqIdxT) prefetchIndexQ <- mkSizedFIFO(valueof(cRqNum));
|
||||
Vector#(cRqNum, Reg#(Bool)) cRqIsPrefetch <- replicateM(mkReg(?));
|
||||
Vector#(cRqNum, Reg#(Bool)) prefetchRqDone <- replicateM(mkReg(?));
|
||||
|
||||
let prefetcher <- mkL1IPrefetcher;
|
||||
|
||||
`ifdef DEBUG_ICACHE
|
||||
// id for each cRq, incremented when each new req comes
|
||||
@@ -175,7 +181,7 @@ module mkIBank#(
|
||||
`endif
|
||||
|
||||
// security flush
|
||||
`ifdef SECURITY
|
||||
`ifdef SECURITY_CACHES
|
||||
Reg#(Bool) flushDone <- mkReg(True);
|
||||
Reg#(Bool) flushReqStart <- mkReg(False);
|
||||
Reg#(Bool) flushReqDone <- mkReg(False);
|
||||
@@ -187,8 +193,10 @@ module mkIBank#(
|
||||
`endif
|
||||
|
||||
LatencyTimer#(cRqNum, 10) latTimer <- mkLatencyTimer;
|
||||
Count#(Bit#(32)) addedCRqs <- mkCount(0);
|
||||
Count#(Bit#(32)) removedCRqs <- mkCount(0);
|
||||
`ifdef PERF_COUNT
|
||||
Reg#(Bool) doStats <- mkConfigReg(False);
|
||||
Reg#(Bool) doStats <- mkConfigReg(True);
|
||||
Count#(Data) ldCnt <- mkCount(0);
|
||||
Count#(Data) ldMissCnt <- mkCount(0);
|
||||
Count#(Data) ldMissLat <- mkCount(0);
|
||||
@@ -233,10 +241,15 @@ module mkIBank#(
|
||||
|
||||
function tagT getTag(Addr a) = truncateLSB(a);
|
||||
|
||||
rule print_cRqIndexQ_len;
|
||||
//$display("L1I cRqIndexQ length= %d", addedCRqs-removedCRqs);
|
||||
endrule
|
||||
|
||||
// XXX since I$ may be requested by processor constantly
|
||||
// cRq may come at every cycle, so we must make cRq has lower priority than pRq/pRs
|
||||
// otherwise the whole system may deadlock/livelock
|
||||
// we stop accepting cRq when we need to flush for security
|
||||
(* descending_urgency = "createPrefetchRq, cRqTransfer" *)
|
||||
rule cRqTransfer(flushDone);
|
||||
Addr addr <- toGet(rqFromCQ).get;
|
||||
`ifdef DEBUG_ICACHE
|
||||
@@ -253,6 +266,8 @@ module mkIBank#(
|
||||
}));
|
||||
// enq to indexQ for in order resp
|
||||
cRqIndexQ.enq(n);
|
||||
cRqIsPrefetch[n] <= False;
|
||||
addedCRqs.incr(1);
|
||||
// performance counter: cRq type
|
||||
incrReqCnt;
|
||||
if (verbose)
|
||||
@@ -294,7 +309,32 @@ module mkIBank#(
|
||||
doAssert(resp.toState == S && isValid(resp.data), "I$ must upgrade to S with data");
|
||||
endrule
|
||||
|
||||
`ifdef SECURITY
|
||||
//(* descending_urgency = "createPrefetchRq, pRsTransfer, cRqTransfer" *)
|
||||
//(* descending_urgency = "createPrefetchRq, pRqTransfer, cRqTransfer" *)
|
||||
rule createPrefetchRq(flushDone);
|
||||
Addr addr <- prefetcher.getNextPrefetchAddr;
|
||||
procRqT r = ProcRqToI {addr: addr};
|
||||
cRqIdxT n <- cRqMshr.getEmptyEntryInit(r);
|
||||
// send to pipeline
|
||||
pipeline.send(CRq (L1PipeRqIn {
|
||||
addr: r.addr,
|
||||
mshrIdx: n
|
||||
}));
|
||||
// enq to indexQ for in order resp
|
||||
prefetchIndexQ.enq(n);
|
||||
cRqIsPrefetch[n] <= True;
|
||||
prefetchRqDone[n] <= False;
|
||||
addedCRqs.incr(1);
|
||||
// performance counter: cRq type
|
||||
//incrReqCnt; TODO make separate counter for prefetch requests
|
||||
if (verbose)
|
||||
$display("%t I %m createPrefetchRq: ", $time,
|
||||
fshow(n), " ; ",
|
||||
fshow(r)
|
||||
);
|
||||
endrule
|
||||
|
||||
`ifdef SECURITY_CACHES
|
||||
// start flush when cRq MSHR is empty
|
||||
rule startFlushReq(!flushDone && !flushReqStart && cRqMshr.emptyForFlush);
|
||||
flushReqStart <= True;
|
||||
@@ -334,6 +374,7 @@ module mkIBank#(
|
||||
endrule
|
||||
`endif
|
||||
|
||||
// Used when replacing an evicted cache line
|
||||
rule sendRsToP_cRq(rsToPIndexQ.first matches tagged CRq .n);
|
||||
rsToPIndexQ.deq;
|
||||
// get cRq replacement info
|
||||
@@ -471,6 +512,10 @@ module mkIBank#(
|
||||
},
|
||||
line: ram.line
|
||||
}, True); // hit, so update rep info
|
||||
if (!cRqIsPrefetch[n]) begin
|
||||
prefetcher.reportHit(req.addr);
|
||||
end
|
||||
prefetchRqDone[n] <= True;
|
||||
// process req to get superscalar inst read results
|
||||
// set MSHR entry as Done & save inst results
|
||||
let instResult = readInst(ram.line, req.addr);
|
||||
@@ -530,10 +575,14 @@ module mkIBank#(
|
||||
},
|
||||
line: ram.line
|
||||
}, False);
|
||||
if (!cRqIsPrefetch[n]) begin
|
||||
prefetcher.reportMiss(procRq.addr);
|
||||
end
|
||||
endaction
|
||||
endfunction
|
||||
|
||||
// function to do replacement for cRq
|
||||
// When we evict an S cache line to make space
|
||||
function Action cRqReplacement;
|
||||
action
|
||||
// deq pipeline
|
||||
@@ -556,6 +605,9 @@ module mkIBank#(
|
||||
repTag: ram.info.tag, // tag being replaced for sending rs to parent
|
||||
waitP: True
|
||||
});
|
||||
if (!cRqIsPrefetch[n]) begin
|
||||
prefetcher.reportMiss(procRq.addr);
|
||||
end
|
||||
// send replacement resp to parent
|
||||
rsToPIndexQ.enq(CRq (n));
|
||||
endaction
|
||||
@@ -640,7 +692,9 @@ module mkIBank#(
|
||||
);
|
||||
cRqHit(cOwner, procRq);
|
||||
// performance counter: miss cRq
|
||||
incrMissCnt(cOwner);
|
||||
if (!cRqIsPrefetch[cOwner]) begin
|
||||
incrMissCnt(cOwner);
|
||||
end
|
||||
end
|
||||
else begin
|
||||
doAssert(False, ("pRs owner must match some cRq"));
|
||||
@@ -694,8 +748,20 @@ module mkIBank#(
|
||||
rsToPIndexQ.enq(PRq (n));
|
||||
end
|
||||
endrule
|
||||
|
||||
rule discardPrefetchRqResult(
|
||||
//cRqMshr.sendRsToC.getResult(prefetchIndexQ.first) matches tagged Valid .inst);
|
||||
prefetchRqDone[prefetchIndexQ.first]);
|
||||
prefetchIndexQ.deq;
|
||||
removedCRqs.incr(1);
|
||||
cRqMshr.sendRsToC.releaseEntry(prefetchIndexQ.first); // release MSHR entry
|
||||
if (verbose)
|
||||
$display("%t I %m discardPrefetchRqResult: ", $time,
|
||||
fshow(prefetchIndexQ.first)
|
||||
);
|
||||
endrule
|
||||
|
||||
`ifdef SECURITY
|
||||
`ifdef SECURITY_CACHES
|
||||
rule pipelineResp_flush(
|
||||
!flushDone &&& !flushRespDone &&&
|
||||
pipeOut.cmd matches tagged L1Flush .flush
|
||||
@@ -783,6 +849,7 @@ module mkIBank#(
|
||||
cRqMshr.sendRsToC.getResult(cRqIndexQ.first) matches tagged Valid .inst
|
||||
);
|
||||
cRqIndexQ.deq;
|
||||
removedCRqs.incr(1);
|
||||
cRqMshr.sendRsToC.releaseEntry(cRqIndexQ.first); // release MSHR entry
|
||||
if (verbose)
|
||||
$display("%t I %m sendRsToC: ", $time,
|
||||
@@ -810,7 +877,7 @@ module mkIBank#(
|
||||
|
||||
interface pRqStuck = pRqMshr.stuck;
|
||||
|
||||
`ifdef SECURITY
|
||||
`ifdef SECURITY_CACHES
|
||||
method Action flush if(flushDone);
|
||||
flushDone <= False;
|
||||
endmethod
|
||||
|
||||
@@ -74,7 +74,7 @@ interface IPRqMshr_pipelineResp#(numeric type pRqNum);
|
||||
method PRqMsg#(void) getRq(Bit#(TLog#(pRqNum)) n);
|
||||
method Action releaseEntry(Bit#(TLog#(pRqNum)) n);
|
||||
method Action setDone(Bit#(TLog#(pRqNum)) n);
|
||||
`ifdef SECURITY
|
||||
`ifdef SECURITY_CACHES
|
||||
method Action setFlushAddr(Bit#(TLog#(pRqNum)) n, Addr a);
|
||||
`endif
|
||||
endinterface
|
||||
@@ -204,7 +204,7 @@ module mkIPRqMshrSafe(
|
||||
stateVec[n][pipelineResp_port] <= Empty;
|
||||
endmethod
|
||||
|
||||
`ifdef SECURITY
|
||||
`ifdef SECURITY_CACHES
|
||||
method Action setFlushAddr(Bit#(TLog#(pRqNum)) n, Addr a);
|
||||
reqVec[n][pipelineResp_port] <= PRqMsg {
|
||||
addr: a,
|
||||
|
||||
@@ -60,6 +60,7 @@ import CrossBar::*;
|
||||
import Performance::*;
|
||||
import LatencyTimer::*;
|
||||
import RandomReplace::*;
|
||||
import Prefetcher::*;
|
||||
`ifdef PERFORMANCE_MONITORING
|
||||
import PerformanceMonitor::*;
|
||||
import StatCounters::*;
|
||||
@@ -155,7 +156,7 @@ module mkL1Bank#(
|
||||
Add#(TAdd#(tagSz, indexSz), TAdd#(lgBankNum, LgLineSzBytes), AddrSz)
|
||||
);
|
||||
|
||||
Bool verbose = False;
|
||||
Bool verbose = True;
|
||||
|
||||
L1CRqMshr#(cRqNum, wayT, tagT, procRqT) cRqMshr <- mkL1CRqMshrLocal;
|
||||
|
||||
@@ -186,8 +187,11 @@ module mkL1Bank#(
|
||||
// we process AMO resp in a new cycle to cut critical path
|
||||
Reg#(Maybe#(AmoHitInfo#(cRqIdxT, procRqT))) processAmo <- mkReg(Invalid);
|
||||
|
||||
Vector#(cRqNum, Reg#(Bool)) cRqIsPrefetch <- replicateM(mkReg(?));
|
||||
let prefetcher <- mkL1DPrefetcher;
|
||||
|
||||
// security flush
|
||||
`ifdef SECURITY
|
||||
`ifdef SECURITY_CACHES
|
||||
Reg#(Bool) flushDone <- mkReg(True);
|
||||
Reg#(Bool) flushReqStart <- mkReg(False);
|
||||
Reg#(Bool) flushReqDone <- mkReg(False);
|
||||
@@ -299,6 +303,7 @@ endfunction
|
||||
addr: req.addr,
|
||||
mshrIdx: n
|
||||
}));
|
||||
cRqIsPrefetch[n] <= False;
|
||||
if (verbose)
|
||||
$display("%t L1 %m cRqTransfer_retry: ", $time,
|
||||
fshow(n), " ; ",
|
||||
@@ -317,6 +322,7 @@ endfunction
|
||||
addr: r.addr,
|
||||
mshrIdx: n
|
||||
}));
|
||||
cRqIsPrefetch[n] <= False;
|
||||
// performance counter: cRq type
|
||||
incrReqCnt(r.op);
|
||||
if (verbose)
|
||||
@@ -355,7 +361,38 @@ endfunction
|
||||
$display("%t L1 %m pRsTransfer: ", $time, fshow(resp));
|
||||
endrule
|
||||
|
||||
`ifdef SECURITY
|
||||
|
||||
(* descending_urgency = "pRsTransfer, cRqTransfer_retry, cRqTransfer_new, createPrefetchRq" *)
|
||||
(* descending_urgency = "pRqTransfer, cRqTransfer_retry, cRqTransfer_new, createPrefetchRq" *)
|
||||
rule createPrefetchRq(flushDone);
|
||||
Addr addr <- prefetcher.getNextPrefetchAddr;
|
||||
procRqT r = ProcRq {
|
||||
id: ?, //Or maybe do 0 here
|
||||
addr: addr,
|
||||
toState: M,
|
||||
op: Ld,
|
||||
byteEn: ?,
|
||||
data: ?,
|
||||
amoInst: ?,
|
||||
loadTags: ?,
|
||||
pcHash: ?
|
||||
};
|
||||
cRqIdxT n <- cRqMshr.cRqTransfer.getEmptyEntryInit(r);
|
||||
// send to pipeline
|
||||
pipeline.send(CRq (L1PipeRqIn {
|
||||
addr: r.addr,
|
||||
mshrIdx: n
|
||||
}));
|
||||
cRqIsPrefetch[n] <= True;
|
||||
// performance counter: cRq type
|
||||
if (verbose)
|
||||
$display("%t L1 %m createPrefetchRq: ", $time,
|
||||
fshow(n), " ; ",
|
||||
fshow(r)
|
||||
);
|
||||
endrule
|
||||
|
||||
`ifdef SECURITY_CACHES
|
||||
// start flush when cRq MSHR is empty
|
||||
rule startFlushReq(!flushDone && !flushReqStart && cRqMshr.emptyForFlush);
|
||||
flushReqStart <= True;
|
||||
@@ -521,10 +558,12 @@ endfunction
|
||||
LineMemDataOffset dataSel = getLineMemDataOffset(req.addr);
|
||||
case(req.op) matches
|
||||
Ld: begin
|
||||
if (req.loadTags) begin
|
||||
procResp.respLd(req.id, getTagsAt(curLine));
|
||||
end else begin
|
||||
procResp.respLd(req.id, getTaggedDataAt(curLine, dataSel));
|
||||
if (!cRqIsPrefetch[n]) begin
|
||||
if (req.loadTags) begin
|
||||
procResp.respLd(req.id, getTagsAt(curLine));
|
||||
end else begin
|
||||
procResp.respLd(req.id, getTaggedDataAt(curLine, dataSel));
|
||||
end
|
||||
end
|
||||
end
|
||||
Lr: begin
|
||||
@@ -579,6 +618,9 @@ endfunction
|
||||
},
|
||||
line: newLine // write new data into cache
|
||||
}, True); // hit, so update rep info
|
||||
if (!cRqIsPrefetch[n]) begin
|
||||
prefetcher.reportAccess(req.addr, req.pcHash, HIT);
|
||||
end
|
||||
if (verbose)
|
||||
$display("%t L1 %m pipelineResp: Hit func: update ram: ", $time,
|
||||
fshow(newLine), " ; ",
|
||||
@@ -729,6 +771,9 @@ endfunction
|
||||
},
|
||||
line: ram.line
|
||||
}, False);
|
||||
if (!cRqIsPrefetch[n]) begin
|
||||
prefetcher.reportAccess(procRq.addr, procRq.pcHash, MISS);
|
||||
end
|
||||
endaction
|
||||
endfunction
|
||||
|
||||
@@ -754,6 +799,9 @@ endfunction
|
||||
waitP: False // we send req to parent later (when resp to parent is sent)
|
||||
});
|
||||
cRqMshr.pipelineResp.setData(n, ram.info.cs == M ? Valid (ram.line) : Invalid);
|
||||
if (!cRqIsPrefetch[n]) begin
|
||||
prefetcher.reportAccess(procRq.addr, procRq.pcHash, MISS);
|
||||
end
|
||||
// send replacement resp to parent
|
||||
rsToPIndexQ.enq(CRq (n));
|
||||
// reset link addr
|
||||
@@ -892,7 +940,9 @@ endfunction
|
||||
);
|
||||
cRqHit(cOwner, procRq);
|
||||
// performance counter: miss cRq
|
||||
incrMissCnt(procRq.op, cOwner);
|
||||
if (!cRqIsPrefetch[cOwner]) begin
|
||||
incrMissCnt(procRq.op, cOwner);
|
||||
end
|
||||
end
|
||||
else begin
|
||||
doAssert(False, ("pRs owner must match some cRq"));
|
||||
@@ -989,7 +1039,7 @@ endfunction
|
||||
end
|
||||
endrule
|
||||
|
||||
`ifdef SECURITY
|
||||
`ifdef SECURITY_CACHES
|
||||
rule pipelineResp_flush(
|
||||
!isValid(processAmo) &&&
|
||||
!flushDone &&& !flushRespDone &&&
|
||||
@@ -1095,7 +1145,7 @@ endfunction
|
||||
|
||||
interface pRqStuck = pRqMshr.stuck;
|
||||
|
||||
`ifdef SECURITY
|
||||
`ifdef SECURITY_CACHES
|
||||
method Action flush if(flushDone);
|
||||
flushDone <= False;
|
||||
endmethod
|
||||
|
||||
@@ -77,7 +77,7 @@ interface L1PRqMshr_pipelineResp#(numeric type pRqNum);
|
||||
|
||||
method Action releaseEntry(Bit#(TLog#(pRqNum)) n);
|
||||
method Action setDone_setData(Bit#(TLog#(pRqNum)) n, Maybe#(Line) d);
|
||||
`ifdef SECURITY
|
||||
`ifdef SECURITY_CACHES
|
||||
method Action setFlushAddr(Bit#(TLog#(pRqNum)) n, Addr a);
|
||||
`endif
|
||||
endinterface
|
||||
@@ -223,7 +223,7 @@ module mkL1PRqMshrSafe(
|
||||
stateVec[n][pipelineResp_port] <= Empty;
|
||||
endmethod
|
||||
|
||||
`ifdef SECURITY
|
||||
`ifdef SECURITY_CACHES
|
||||
method Action setFlushAddr(Bit#(TLog#(pRqNum)) n, Addr a);
|
||||
reqVec[n][pipelineResp_port] <= PRqMsg {
|
||||
addr: a,
|
||||
|
||||
@@ -84,7 +84,7 @@ typedef union tagged {
|
||||
L1PipeRqIn#(cRqIdxT) CRq;
|
||||
L1PipeRqIn#(pRqIdxT) PRq;
|
||||
L1PipePRsIn#(wayT) PRs;
|
||||
`ifdef SECURITY
|
||||
`ifdef SECURITY_CACHES
|
||||
L1PipeFlushIn#(wayT, indexT, pRqIdxT) Flush;
|
||||
`endif
|
||||
} L1PipeIn#(
|
||||
@@ -104,7 +104,7 @@ typedef union tagged {
|
||||
cRqIdxT L1CRq;
|
||||
pRqIdxT L1PRq;
|
||||
void L1PRs;
|
||||
`ifdef SECURITY
|
||||
`ifdef SECURITY_CACHES
|
||||
L1FlushCmd#(indexT, pRqIdxT) L1Flush;
|
||||
`endif
|
||||
} L1Cmd#(
|
||||
@@ -145,7 +145,7 @@ typedef union tagged {
|
||||
L1PipeRqIn#(cRqIdxT) CRq;
|
||||
L1PipeRqIn#(pRqIdxT) PRq;
|
||||
L1PipePRsCmd#(wayT) PRs;
|
||||
`ifdef SECURITY
|
||||
`ifdef SECURITY_CACHES
|
||||
L1PipeFlushIn#(wayT, indexT, pRqIdxT) Flush;
|
||||
`endif
|
||||
} L1PipeCmd#(
|
||||
@@ -220,7 +220,7 @@ module mkL1Pipe(
|
||||
tagged CRq .r: r.addr;
|
||||
tagged PRq .r: r.addr;
|
||||
tagged PRs .r: r.addr;
|
||||
`ifdef SECURITY
|
||||
`ifdef SECURITY_CACHES
|
||||
// fake an address for flush req that has the same index
|
||||
tagged Flush .r: (zeroExtend(r.index) << (valueOf(LgLineSzBytes) + valueOf(lgBankNum)));
|
||||
`endif
|
||||
@@ -258,7 +258,7 @@ module mkL1Pipe(
|
||||
pRqMiss: False
|
||||
};
|
||||
end
|
||||
`ifdef SECURITY
|
||||
`ifdef SECURITY_CACHES
|
||||
else if(cmd matches tagged Flush .flush) begin
|
||||
// flush directly read from cmd
|
||||
return TagMatchResult {
|
||||
@@ -360,7 +360,7 @@ module mkL1Pipe(
|
||||
way: rs.way
|
||||
}), rs.data, UpCs (rs.toState));
|
||||
end
|
||||
`ifdef SECURITY
|
||||
`ifdef SECURITY_CACHES
|
||||
tagged Flush .flush: begin
|
||||
pipe.enq(Flush (flush), Invalid, Invalid);
|
||||
end
|
||||
@@ -376,7 +376,7 @@ module mkL1Pipe(
|
||||
tagged CRq .rq: L1CRq (rq.mshrIdx);
|
||||
tagged PRq .rq: L1PRq (rq.mshrIdx);
|
||||
tagged PRs .rs: L1PRs;
|
||||
`ifdef SECURITY
|
||||
`ifdef SECURITY_CACHES
|
||||
tagged Flush .flush: L1Flush (L1FlushCmd {
|
||||
index: flush.index,
|
||||
mshrIdx: flush.mshrIdx
|
||||
@@ -397,7 +397,7 @@ module mkL1Pipe(
|
||||
if(swapRq matches tagged Valid .idx) begin // swap in cRq
|
||||
Addr addr = getAddrFromCmd(pipe.first.cmd); // inherit addr
|
||||
newCmd = Valid (CRq (L1PipeRqIn {addr: addr, mshrIdx: idx}));
|
||||
`ifdef SECURITY
|
||||
`ifdef SECURITY_CACHES
|
||||
doAssert(pipe.first.cmd matches tagged Flush .f ? False : True,
|
||||
"Cannot swap after a flush req");
|
||||
`endif
|
||||
|
||||
@@ -51,6 +51,7 @@ import LatencyTimer::*;
|
||||
import Cntrs::*;
|
||||
import ConfigReg::*;
|
||||
import RandomReplace::*;
|
||||
import Prefetcher::*;
|
||||
`ifdef PERFORMANCE_MONITORING
|
||||
import PerformanceMonitor::*;
|
||||
import StatCounters::*;
|
||||
@@ -186,7 +187,7 @@ module mkLLBank#(
|
||||
Add#(cRqNum, b__, wayNum)
|
||||
);
|
||||
|
||||
Bool verbose = False;
|
||||
Bool verbose = True;
|
||||
|
||||
LLCRqMshr#(cRqNum, wayT, tagT, Vector#(childNum, DirPend), cRqT) cRqMshr <- mkLLMshr;
|
||||
|
||||
@@ -228,12 +229,21 @@ module mkLLBank#(
|
||||
|
||||
// performance
|
||||
LatencyTimer#(cRqNum, 10) latTimer <- mkLatencyTimer; // max 1K cycle latency
|
||||
|
||||
Count#(Bit#(32)) addedCRqs <- mkCount(0);
|
||||
Count#(Bit#(32)) removedCRqs <- mkCount(0);
|
||||
|
||||
Vector#(cRqNum, Reg#(Bool)) cRqIsPrefetch <- replicateM(mkReg(?));
|
||||
Prefetcher dataPrefetcher <- mkLLDPrefetcher;
|
||||
Prefetcher instrPrefetcher <- mkLLIPrefetcher;
|
||||
`ifdef PERF_COUNT
|
||||
Reg#(Bool) doStats <- mkConfigReg(False);
|
||||
Reg#(Bool) doStats <- mkConfigReg(True);
|
||||
Count#(Data) dmaMemLdCnt <- mkCount(0);
|
||||
Count#(Data) dmaMemLdLat <- mkCount(0);
|
||||
Count#(Data) normalMemLdCnt <- mkCount(0);
|
||||
Count#(Data) normalMemLdLat <- mkCount(0);
|
||||
Count#(Data) instructionLdCnt <- mkCount(0);
|
||||
Count#(Data) instructionLdLat <- mkCount(0);
|
||||
Count#(Data) mshrBlocks <- mkCount(0);
|
||||
Count#(Data) downRespCnt <- mkCount(0);
|
||||
Count#(Data) downRespDataCnt <- mkCount(0);
|
||||
@@ -246,7 +256,7 @@ module mkLLBank#(
|
||||
`ifdef PERFORMANCE_MONITORING
|
||||
Array #(Reg #(EventsLL)) perf_events <- mkDRegOR (2, unpack (0));
|
||||
`endif
|
||||
function Action incrMissCnt(cRqIndexT idx, Bool isDma);
|
||||
function Action incrMissCnt(cRqIndexT idx, Bool isDma, Bool isInstructionAccess);
|
||||
action
|
||||
let lat <- latTimer.done(idx);
|
||||
`ifdef PERF_COUNT
|
||||
@@ -255,6 +265,10 @@ action
|
||||
dmaMemLdCnt.incr(1);
|
||||
dmaMemLdLat.incr(zeroExtend(lat));
|
||||
end
|
||||
else if (isInstructionAccess) begin
|
||||
instructionLdCnt.incr(1);
|
||||
instructionLdLat.incr(zeroExtend(lat));
|
||||
end
|
||||
else begin
|
||||
normalMemLdCnt.incr(1);
|
||||
normalMemLdLat.incr(zeroExtend(lat));
|
||||
@@ -329,6 +343,7 @@ endfunction
|
||||
// later cRq to same addr needs to be appended after this one
|
||||
// send to pipeline
|
||||
cRqT req = cRqMshr.transfer.getRq(n);
|
||||
cRqIsPrefetch[n] <= False;
|
||||
pipeline.send(CRq (LLPipeCRqIn {
|
||||
addr: req.addr,
|
||||
mshrIdx: n
|
||||
@@ -389,6 +404,7 @@ endfunction
|
||||
addr: cRq.addr,
|
||||
mshrIdx: n
|
||||
}));
|
||||
cRqIsPrefetch[n] <= False;
|
||||
// change round robin
|
||||
flipPriorNewCRqSrc;
|
||||
if (verbose)
|
||||
@@ -399,6 +415,64 @@ endfunction
|
||||
);
|
||||
endrule
|
||||
|
||||
// insert new cRq from child to MSHR and send to pipeline
|
||||
rule createDataPrefetchRq(newCRqSrc == Valid (Child));
|
||||
Addr addr <- dataPrefetcher.getNextPrefetchAddr;
|
||||
cRqT cRq = LLRq {
|
||||
addr: addr,
|
||||
fromState: I,
|
||||
toState: E,
|
||||
canUpToE: True,
|
||||
child: 0,
|
||||
byteEn: ?,
|
||||
id: Child (?)
|
||||
};
|
||||
// setup new MSHR entry
|
||||
cRqIndexT n <- cRqMshr.transfer.getEmptyEntryInit(cRq, Invalid);
|
||||
// send to pipeline
|
||||
pipeline.send(CRq (LLPipeCRqIn {
|
||||
addr: cRq.addr,
|
||||
mshrIdx: n
|
||||
}));
|
||||
cRqIsPrefetch[n] <= True;
|
||||
// change round robin
|
||||
flipPriorNewCRqSrc;
|
||||
if (verbose)
|
||||
$display("%t LL %m createDataPrefetchRq: ", $time,
|
||||
fshow(n), " ; ",
|
||||
fshow(cRq)
|
||||
);
|
||||
endrule
|
||||
|
||||
// insert new cRq from child to MSHR and send to pipeline
|
||||
rule createInstrPrefetchRq(newCRqSrc == Valid (Child));
|
||||
Addr addr <- instrPrefetcher.getNextPrefetchAddr;
|
||||
cRqT cRq = LLRq {
|
||||
addr: addr,
|
||||
fromState: I,
|
||||
toState: S,
|
||||
canUpToE: True,
|
||||
child: 1,
|
||||
byteEn: ?,
|
||||
id: Child (?)
|
||||
};
|
||||
// setup new MSHR entry
|
||||
cRqIndexT n <- cRqMshr.transfer.getEmptyEntryInit(cRq, Invalid);
|
||||
// send to pipeline
|
||||
pipeline.send(CRq (LLPipeCRqIn {
|
||||
addr: cRq.addr,
|
||||
mshrIdx: n
|
||||
}));
|
||||
cRqIsPrefetch[n] <= True;
|
||||
// change round robin
|
||||
flipPriorNewCRqSrc;
|
||||
if (verbose)
|
||||
$display("%t LL %m createInstrPrefetchRq: ", $time,
|
||||
fshow(n), " ; ",
|
||||
fshow(cRq)
|
||||
);
|
||||
endrule
|
||||
|
||||
`ifdef PERF_COUNT
|
||||
// perf stats: insert new cRq fails because of full MSHR
|
||||
rule cRqTransfer_new_child_block(
|
||||
@@ -467,7 +541,7 @@ endfunction
|
||||
!cRqRetryIndexQ.notEmpty && newCRqSrc == Valid (Dma) && doStats
|
||||
);
|
||||
dmaRqT r = rqFromDmaQ.first;
|
||||
Bool write = r.byteEn != replicate(False);
|
||||
Bool write = r.byteEn != replicate(replicate(False));
|
||||
cRqT cRq = LLRq {
|
||||
addr: r.addr,
|
||||
fromState: I,
|
||||
@@ -534,7 +608,8 @@ endfunction
|
||||
fshow(cSlot), " ; "
|
||||
);
|
||||
// performance counter: normal miss lat and cnt
|
||||
incrMissCnt(n, False);
|
||||
// Check lowest bit of child ID to determine if this was an ICache access
|
||||
incrMissCnt(n, False, cRq.child[0] == 1);
|
||||
endrule
|
||||
|
||||
// this mem resp is just for a DMA req, won't go into pipeline to refill cache
|
||||
@@ -547,7 +622,7 @@ endfunction
|
||||
cRqMshr.mRsDeq.setData(mRs.id.mshrIdx, Valid (mRs.data));
|
||||
rsLdToDmaIndexQ_mRsDeq.enq(mRs.id.mshrIdx);
|
||||
// performance counter: dma miss lat and cnt
|
||||
incrMissCnt(mRs.id.mshrIdx, True);
|
||||
incrMissCnt(mRs.id.mshrIdx, True, False);
|
||||
endrule
|
||||
|
||||
// send rd/wr to mem
|
||||
@@ -709,7 +784,7 @@ endfunction
|
||||
endrule
|
||||
|
||||
// send upgrade resp to child
|
||||
rule sendRsToC(rsToCIndexQ.notEmpty);
|
||||
rule sendRsToC(rsToCIndexQ.notEmpty && !cRqIsPrefetch[rsToCIndexQ.first.cRqId]);
|
||||
// send upgrade resp to child
|
||||
rsToCIndexQ.deq;
|
||||
cRqIndexT n = rsToCIndexQ.first.cRqId;
|
||||
@@ -745,6 +820,13 @@ endfunction
|
||||
`endif
|
||||
endrule
|
||||
|
||||
rule discardPrefetchRqResult(rsToCIndexQ.notEmpty && cRqIsPrefetch[rsToCIndexQ.first.cRqId]);
|
||||
let n = rsToCIndexQ.first.cRqId;
|
||||
$display("%t LL %m discardPrefetchRqResult: ", $time, fshow(n));
|
||||
rsToCIndexQ.deq;
|
||||
cRqMshr.sendRsToDmaC.releaseEntry(n);
|
||||
endrule
|
||||
|
||||
// send downgrade req to child
|
||||
// round robin select cRq to downgrade child
|
||||
// but downgrade must wait for all upgrade resp
|
||||
@@ -886,7 +968,11 @@ endfunction
|
||||
cRqMshr.pipelineResp.setData(n, ram.info.dir[cRq.child] <= T ? Valid (ram.line) : Invalid);
|
||||
// update child dir
|
||||
dirT newDir = ram.info.dir;
|
||||
newDir[cRq.child] = toState;
|
||||
if (!cRqIsPrefetch[n]) begin
|
||||
//Only update dir if not a prefetch request, since
|
||||
//Prerefetch request results don't get handed down to children,
|
||||
newDir[cRq.child] = toState;
|
||||
end
|
||||
// update cs (may have E -> M)
|
||||
Msi newCs = ram.info.cs;
|
||||
if(toState == M) begin
|
||||
@@ -910,6 +996,14 @@ endfunction
|
||||
},
|
||||
line: ram.line // use line in ram
|
||||
}, True); // hit, so update rep info
|
||||
if (!cRqIsPrefetch[n]) begin
|
||||
if (cRq.child[0] == 1) begin
|
||||
instrPrefetcher.reportHit(cRq.addr);
|
||||
end
|
||||
else begin
|
||||
dataPrefetcher.reportHit(cRq.addr);
|
||||
end
|
||||
end
|
||||
endaction
|
||||
endfunction
|
||||
|
||||
@@ -1103,6 +1197,14 @@ endfunction
|
||||
},
|
||||
line: ram.line
|
||||
}, False);
|
||||
if (!cRqIsPrefetch[n]) begin
|
||||
if (cRq.child[0] == 1) begin
|
||||
instrPrefetcher.reportMiss(cRq.addr);
|
||||
end
|
||||
else begin
|
||||
dataPrefetcher.reportMiss(cRq.addr);
|
||||
end
|
||||
end
|
||||
endaction
|
||||
endfunction
|
||||
|
||||
@@ -1171,6 +1273,14 @@ endfunction
|
||||
dirPend: dirPend
|
||||
});
|
||||
end
|
||||
if (!cRqIsPrefetch[n]) begin
|
||||
if (cRq.child[0] == 1) begin
|
||||
instrPrefetcher.reportMiss(cRq.addr);
|
||||
end
|
||||
else begin
|
||||
dataPrefetcher.reportMiss(cRq.addr);
|
||||
end
|
||||
end
|
||||
endaction
|
||||
endfunction
|
||||
|
||||
@@ -1538,6 +1648,8 @@ endfunction
|
||||
LLCDmaMemLdLat: dmaMemLdLat;
|
||||
LLCNormalMemLdCnt: normalMemLdCnt;
|
||||
LLCNormalMemLdLat: normalMemLdLat;
|
||||
LLCInstructionLdCnt: instructionLdCnt;
|
||||
LLCInstructionLdLat: instructionLdLat;
|
||||
LLCMshrBlockCycles: mshrBlocks;
|
||||
LLCDownRespCnt: downRespCnt;
|
||||
LLCDownRespDataCnt: downRespDataCnt;
|
||||
|
||||
542
src_Core/RISCY_OOO/coherence/src/Prefetcher.bsv
Normal file
542
src_Core/RISCY_OOO/coherence/src/Prefetcher.bsv
Normal file
@@ -0,0 +1,542 @@
|
||||
import ISA_Decls :: *;
|
||||
import CacheUtils::*;
|
||||
import CCTypes::*;
|
||||
import Types::*;
|
||||
import Vector::*;
|
||||
|
||||
interface Prefetcher;
|
||||
method Action reportHit(Addr hitAddr);
|
||||
method Action reportMiss(Addr missAddr);
|
||||
method ActionValue#(Addr) getNextPrefetchAddr();
|
||||
//method Action flush;
|
||||
//method Bool flush_done;
|
||||
endinterface
|
||||
|
||||
module mkTestPrefetcher(Prefetcher);
|
||||
Reg#(Addr) lastMissAddr <- mkReg(0);
|
||||
Reg#(Bit#(2)) reqSent <- mkReg(0);
|
||||
method Action reportHit(Addr hitAddr);
|
||||
$display("%t I Prefetcher reportHit %h", $time, hitAddr);
|
||||
endmethod
|
||||
method Action reportMiss(Addr missAddr);
|
||||
$display("%t I Prefetcher reportMiss %h", $time, missAddr);
|
||||
if (missAddr == 'h0000000080000040)
|
||||
lastMissAddr <= missAddr;
|
||||
endmethod
|
||||
method ActionValue#(Addr) getNextPrefetchAddr if (reqSent < 2 && lastMissAddr == 'h0000000080000040);
|
||||
$display("%t I Prefetcher getNextPrefetchAddr", $time);
|
||||
reqSent <= reqSent + 1;
|
||||
if (reqSent == 0) begin
|
||||
return 64'h0000000080000080;
|
||||
end
|
||||
else begin
|
||||
return 64'h00000000800000c0;
|
||||
end
|
||||
endmethod
|
||||
endmodule
|
||||
|
||||
module mkDoNothingPrefetcher(Prefetcher);
|
||||
method Action reportHit(Addr hitAddr);
|
||||
endmethod
|
||||
method Action reportMiss(Addr missAddr);
|
||||
endmethod
|
||||
method ActionValue#(Addr) getNextPrefetchAddr if (False);
|
||||
return 64'h0000000080000080;
|
||||
endmethod
|
||||
endmodule
|
||||
|
||||
module mkPrintPrefetcher(Prefetcher);
|
||||
method Action reportHit(Addr hitAddr);
|
||||
$display("%t PrintPrefetcher reportHit %h", $time, hitAddr);
|
||||
endmethod
|
||||
method Action reportMiss(Addr missAddr);
|
||||
$display("%t PrintPrefetcher reportMiss %h", $time, missAddr);
|
||||
endmethod
|
||||
method ActionValue#(Addr) getNextPrefetchAddr if (False);
|
||||
return 64'h0000000080000080;
|
||||
endmethod
|
||||
endmodule
|
||||
|
||||
typedef 3 INextLinesOnMiss;
|
||||
typedef 0 DNextLinesOnMiss;
|
||||
|
||||
module mkNextLineOnMissPrefetcher(Prefetcher)
|
||||
provisos (
|
||||
Alias#(rqCntT, Bit#(TLog#(TAdd#(INextLinesOnMiss, 1))))
|
||||
);
|
||||
Reg#(Addr) lastMissAddr <- mkReg(0);
|
||||
Reg#(rqCntT) sentRequestCounter <- mkReg(fromInteger(valueOf(INextLinesOnMiss)));
|
||||
method Action reportHit(Addr hitAddr);
|
||||
$display("%t Prefetcher reportHit %h", $time, hitAddr);
|
||||
endmethod
|
||||
method Action reportMiss(Addr missAddr);
|
||||
$display("%t Prefetcher reportMiss %h", $time, missAddr);
|
||||
lastMissAddr <= missAddr;
|
||||
sentRequestCounter <= 0;
|
||||
endmethod
|
||||
method ActionValue#(Addr) getNextPrefetchAddr if (sentRequestCounter < fromInteger(valueOf(INextLinesOnMiss)));
|
||||
sentRequestCounter <= sentRequestCounter + 1;
|
||||
let addrToRequest = lastMissAddr + (zeroExtend(sentRequestCounter) + 1)*fromInteger(valueOf(DataSz));
|
||||
$display("%t Prefetcher getNextPrefetchAddr requesting %h", $time, addrToRequest);
|
||||
return addrToRequest;
|
||||
endmethod
|
||||
endmodule
|
||||
|
||||
module mkNextLineOnAllPrefetcher(Prefetcher)
|
||||
provisos (
|
||||
Alias#(rqCntT, Bit#(TLog#(TAdd#(INextLinesOnMiss, 1))))
|
||||
);
|
||||
Reg#(Addr) lastMissAddr <- mkReg(0);
|
||||
Reg#(rqCntT) sentRequestCounter <- mkReg(fromInteger(valueOf(INextLinesOnMiss)));
|
||||
method Action reportHit(Addr hitAddr);
|
||||
$display("%t Prefetcher reportHit %h", $time, hitAddr);
|
||||
lastMissAddr <= hitAddr;
|
||||
sentRequestCounter <= 0;
|
||||
endmethod
|
||||
method Action reportMiss(Addr missAddr);
|
||||
$display("%t Prefetcher reportMiss %h", $time, missAddr);
|
||||
lastMissAddr <= missAddr;
|
||||
sentRequestCounter <= 0;
|
||||
endmethod
|
||||
method ActionValue#(Addr) getNextPrefetchAddr if (sentRequestCounter < fromInteger(valueOf(INextLinesOnMiss)));
|
||||
sentRequestCounter <= sentRequestCounter + 1;
|
||||
let addrToRequest = lastMissAddr + (zeroExtend(sentRequestCounter) + 1)*fromInteger(valueOf(DataSz));
|
||||
$display("%t Prefetcher getNextPrefetchAddr requesting %h", $time, addrToRequest);
|
||||
return addrToRequest;
|
||||
endmethod
|
||||
endmodule
|
||||
|
||||
module mkNextLinePrefetcherBackwards(Prefetcher)
|
||||
provisos (
|
||||
Alias#(rqCntT, Bit#(TLog#(TAdd#(DNextLinesOnMiss, 1))))
|
||||
);
|
||||
Reg#(Addr) lastMissAddr <- mkReg(0);
|
||||
Reg#(rqCntT) sentRequestCounter <- mkReg(fromInteger(valueOf(DNextLinesOnMiss)));
|
||||
method Action reportHit(Addr hitAddr);
|
||||
$display("%t Prefetcher reportHit %h", $time, hitAddr);
|
||||
endmethod
|
||||
method Action reportMiss(Addr missAddr);
|
||||
$display("%t Prefetcher reportMiss %h", $time, missAddr);
|
||||
lastMissAddr <= missAddr;
|
||||
sentRequestCounter <= 0;
|
||||
endmethod
|
||||
method ActionValue#(Addr) getNextPrefetchAddr if (sentRequestCounter < fromInteger(valueOf(DNextLinesOnMiss)));
|
||||
sentRequestCounter <= sentRequestCounter + 1;
|
||||
let addrToRequest = lastMissAddr - (zeroExtend(sentRequestCounter) + 1)*fromInteger(valueOf(DataSz));
|
||||
$display("%t Prefetcher getNextPrefetchAddr requesting %h", $time, addrToRequest);
|
||||
return addrToRequest;
|
||||
endmethod
|
||||
endmodule
|
||||
|
||||
module mkSingleWindowPrefetcher(Prefetcher);
|
||||
Integer cacheLinesInRange = 3;
|
||||
Reg#(LineAddr) rangeEnd <- mkReg(0); //Points to one CLine after end of range
|
||||
Reg#(LineAddr) nextToAsk <- mkReg(0);
|
||||
method Action reportHit(Addr hitAddr);
|
||||
let cl = getLineAddr(hitAddr);
|
||||
if (rangeEnd - fromInteger(cacheLinesInRange) - 1 < cl && cl < rangeEnd) begin
|
||||
let nextEnd = cl + fromInteger(cacheLinesInRange) + 1;
|
||||
$display("%t Prefetcher reportHit %h, moving window end to %h", $time, hitAddr, Addr'{nextEnd, '0});
|
||||
rangeEnd <= nextEnd;
|
||||
end
|
||||
endmethod
|
||||
method Action reportMiss(Addr missAddr);
|
||||
$display("%t Prefetcher reportMiss %h", $time, missAddr);
|
||||
nextToAsk <= getLineAddr(missAddr) + 1;
|
||||
rangeEnd <= getLineAddr(missAddr) + fromInteger(cacheLinesInRange) + 1;
|
||||
//LgLineSzBytes
|
||||
endmethod
|
||||
method ActionValue#(Addr) getNextPrefetchAddr if (nextToAsk != rangeEnd);
|
||||
nextToAsk <= nextToAsk + 1;
|
||||
let retAddr = Addr'{nextToAsk, '0}; //extend cache line address to regular address
|
||||
$display("%t Prefetcher getNextPrefetchAddr requesting %h", $time, retAddr);
|
||||
return retAddr;
|
||||
endmethod
|
||||
endmodule
|
||||
|
||||
|
||||
typedef struct {
|
||||
LineAddr rangeEnd;
|
||||
LineAddr nextToAsk;
|
||||
} StreamEntry deriving (Bits);
|
||||
|
||||
typedef 4 NumWindows;
|
||||
|
||||
module mkMultiWindowPrefetcher(Prefetcher)
|
||||
provisos(
|
||||
Alias#(windowIdxT, Bit#(TLog#(NumWindows)))
|
||||
);
|
||||
Integer cacheLinesInRange = 2;
|
||||
Vector#(NumWindows, Reg#(StreamEntry)) streams
|
||||
<- replicateM(mkReg(StreamEntry {rangeEnd: '0, nextToAsk: '0}));
|
||||
Vector#(NumWindows, Reg#(windowIdxT)) shiftReg <- genWithM(compose(mkReg, fromInteger));
|
||||
|
||||
//function
|
||||
function Action moveWindowToFront(windowIdxT window) =
|
||||
action
|
||||
if (shiftReg[0] == window) begin
|
||||
end
|
||||
else if (shiftReg[1] == window) begin
|
||||
shiftReg[0] <= window;
|
||||
shiftReg[1] <= shiftReg[0];
|
||||
end
|
||||
else if (shiftReg[2] == window) begin
|
||||
shiftReg[0] <= window;
|
||||
shiftReg[1] <= shiftReg[0];
|
||||
shiftReg[2] <= shiftReg[1];
|
||||
end
|
||||
else if (shiftReg[3] == window) begin
|
||||
shiftReg[0] <= window;
|
||||
shiftReg[1] <= shiftReg[0];
|
||||
shiftReg[2] <= shiftReg[1];
|
||||
shiftReg[3] <= shiftReg[2];
|
||||
end
|
||||
endaction;
|
||||
|
||||
function ActionValue#(Maybe#(windowIdxT)) getMatchingWindow(Addr addr) =
|
||||
actionvalue
|
||||
//Finds the first window that contains addr,
|
||||
//and moves it to the front of the LRU shift reg
|
||||
let cl = getLineAddr(addr);
|
||||
function Bool pred(StreamEntry se);
|
||||
//TODO < gives 100 cycles less??????
|
||||
return (se.rangeEnd - fromInteger(cacheLinesInRange) - 1 <= cl
|
||||
&& cl < se.rangeEnd);
|
||||
endfunction
|
||||
//Find first window that contains cache line cl
|
||||
if (findIndex(pred, readVReg(streams)) matches tagged Valid .idx) begin
|
||||
return Valid(pack(idx));
|
||||
end
|
||||
else begin
|
||||
return Invalid;
|
||||
end
|
||||
endactionvalue;
|
||||
|
||||
method Action reportHit(Addr hitAddr);
|
||||
//Check if any stream line matches request
|
||||
//if so, advance that stream line
|
||||
//also advance LRU shift reg
|
||||
let idxMaybe <- getMatchingWindow(hitAddr);
|
||||
if (idxMaybe matches tagged Valid .idx) begin
|
||||
moveWindowToFront(pack(idx)); //Update window as just used
|
||||
let newRangeEnd = getLineAddr(hitAddr) + fromInteger(cacheLinesInRange) + 1;
|
||||
streams[idx].rangeEnd <= newRangeEnd;
|
||||
$display("%t Prefetcher reportHit %h, moving window end to %h for window idx %h",
|
||||
$time, hitAddr, Addr'{newRangeEnd, '0}, idx);
|
||||
end
|
||||
else begin
|
||||
$display("%t Prefetcher reportHit %h, no matching window found.",
|
||||
$time, hitAddr);
|
||||
end
|
||||
endmethod
|
||||
|
||||
method Action reportMiss(Addr missAddr);
|
||||
//Check if any stream line matches request
|
||||
//If so, advance that stream line and advance LRU shift reg
|
||||
//Otherwise, allocate new stream line, and shift LRU reg completely,
|
||||
let idxMaybe <- getMatchingWindow(missAddr);
|
||||
if (idxMaybe matches tagged Valid .idx) begin
|
||||
moveWindowToFront(pack(idx)); //Update window as just used
|
||||
let newRangeEnd = getLineAddr(missAddr) + fromInteger(cacheLinesInRange) + 1;
|
||||
//Also refresh nextToAsk on miss
|
||||
streams[idx] <=
|
||||
StreamEntry {nextToAsk: getLineAddr(missAddr) + 1,
|
||||
rangeEnd: newRangeEnd};
|
||||
$display("%t Prefetcher reportMiss %h, moving window end to %h for window idx %h",
|
||||
$time, missAddr, Addr'{newRangeEnd, '0}, idx);
|
||||
end
|
||||
else begin
|
||||
$display("%t Prefetcher reportMiss %h, allocating new stream, idx %h", $time, missAddr, shiftReg[3]);
|
||||
streams[shiftReg[3]] <=
|
||||
StreamEntry {nextToAsk: getLineAddr(missAddr) + 1,
|
||||
rangeEnd: getLineAddr(missAddr) + fromInteger(cacheLinesInRange) + 1};
|
||||
shiftReg[0] <= shiftReg[3];
|
||||
shiftReg[1] <= shiftReg[0];
|
||||
shiftReg[2] <= shiftReg[1];
|
||||
shiftReg[3] <= shiftReg[2];
|
||||
end
|
||||
endmethod
|
||||
|
||||
method ActionValue#(Addr) getNextPrefetchAddr
|
||||
if (streams[shiftReg[0]].nextToAsk != streams[shiftReg[0]].rangeEnd);
|
||||
|
||||
streams[shiftReg[0]].nextToAsk <= streams[shiftReg[0]].nextToAsk + 1;
|
||||
let retAddr = Addr'{streams[shiftReg[0]].nextToAsk, '0}; //extend cache line address to regular address
|
||||
$display("%t Prefetcher getNextPrefetchAddr requesting %h from window idx %h", $time, retAddr, shiftReg[0]);
|
||||
return retAddr;
|
||||
endmethod
|
||||
|
||||
endmodule
|
||||
|
||||
interface PCPrefetcher;
|
||||
method Action reportAccess(Addr addr, Bit#(16) pcHash, HitOrMiss hitMiss);
|
||||
method ActionValue#(Addr) getNextPrefetchAddr();
|
||||
endinterface
|
||||
|
||||
module mkDoNothingPCPrefetcher(PCPrefetcher);
|
||||
method Action reportAccess(Addr addr, Bit#(16) pcHash, HitOrMiss hitMiss);
|
||||
endmethod
|
||||
method ActionValue#(Addr) getNextPrefetchAddr if (False);
|
||||
return 64'h0000000080000080;
|
||||
endmethod
|
||||
endmodule
|
||||
|
||||
module mkPrintPCPrefetcher(PCPrefetcher);
|
||||
method Action reportAccess(Addr addr, Bit#(16) pcHash, HitOrMiss hitMiss);
|
||||
if (hitMiss == HIT)
|
||||
$display("%t PCPrefetcher reportHit %h", $time, addr);
|
||||
else
|
||||
$display("%t PCPrefetcher reportMiss %h", $time, addr);
|
||||
endmethod
|
||||
method ActionValue#(Addr) getNextPrefetchAddr if (False);
|
||||
return 64'h0000000080000080;
|
||||
endmethod
|
||||
endmodule
|
||||
|
||||
typedef enum {
|
||||
EMPTY = 2'b00, INIT = 2'b01, TRANSIENT = 2'b10, STEADY = 2'b11
|
||||
} StrideState deriving (Bits, Eq, FShow);
|
||||
|
||||
typedef enum {
|
||||
HIT = 1'b0, MISS = 1'b1
|
||||
} HitOrMiss deriving (Bits, Eq, FShow);
|
||||
|
||||
typedef struct {
|
||||
Addr lastAddr; //TODO maybe store less bits here?
|
||||
Bit#(13) stride;
|
||||
StrideState state;
|
||||
Bit#(4) lastPrefetch; //Stores how many strides ahead of lastAddr was the last prefetch done
|
||||
} StrideEntry deriving (Bits, Eq, FShow);
|
||||
|
||||
typedef 8 HistoryLen;
|
||||
typedef 64 StrideTableSize;
|
||||
typedef 4 StridesAheadToPrefetch;
|
||||
module mkStridePCPrefetcher(PCPrefetcher)
|
||||
provisos(
|
||||
Alias#(strideTableIndexT, Bit#(TLog#(StrideTableSize)))
|
||||
);
|
||||
Reg#(Vector#(HistoryLen, strideTableIndexT)) historyVec <- mkReg(replicate(?));
|
||||
Vector#(StrideTableSize, Reg#(StrideEntry)) strideTable <- replicateM(mkReg(unpack(0)));
|
||||
|
||||
function Maybe#(strideTableIndexT) getNextPrefetchIndex;
|
||||
function Bool canPrefetch(strideTableIndexT idx);
|
||||
return (strideTable[idx].state == STEADY &&
|
||||
strideTable[idx].lastPrefetch != fromInteger(valueof(StridesAheadToPrefetch)));
|
||||
endfunction
|
||||
|
||||
//Find first entry that allows more prefetches
|
||||
case (find(canPrefetch, historyVec)) matches
|
||||
tagged Valid .idx: return Valid(pack(idx));
|
||||
Invalid: return Invalid;
|
||||
endcase
|
||||
endfunction
|
||||
|
||||
method ActionValue#(Addr) getNextPrefetchAddr if
|
||||
(getNextPrefetchIndex() matches tagged Valid .idx);
|
||||
//could store some most recent table entries,
|
||||
//then check if any of those entries can be prefetched more
|
||||
|
||||
//could just store the recent table entries in a circular buffer with duplication
|
||||
// since shouldn't have duplicates within one loop iteration
|
||||
// but we need to access all entries (or have rule that discards first entry, it we can't prefetch for it)
|
||||
Reg#(StrideEntry) se = strideTable[idx];
|
||||
se.lastPrefetch <= se.lastPrefetch + 1;
|
||||
return se.lastAddr + (signExtend(se.stride) * zeroExtend(se.lastPrefetch + 1));
|
||||
endmethod
|
||||
method Action reportAccess(Addr addr, Bit#(16) pcHash, HitOrMiss hitMiss);
|
||||
//Find slot in vector
|
||||
//if miss and slot empty
|
||||
//if slot init, put address, stride and move to transit
|
||||
//if slot transit or steady, verify stride, and move to steady
|
||||
// also put last_prefetched
|
||||
//if stride wrong, move to transit
|
||||
strideTableIndexT index = truncate(pcHash);
|
||||
Reg#(StrideEntry) se = strideTable[index];
|
||||
StrideEntry seNext = se;
|
||||
$writeh("Prefetcher: ",
|
||||
fshow(hitMiss), " ", addr,
|
||||
". Entry state is ", fshow(se.state));
|
||||
|
||||
if (hitMiss == MISS && se.state == EMPTY) begin
|
||||
seNext.lastAddr = addr;
|
||||
seNext.state = INIT;
|
||||
$display(", allocate entry");
|
||||
end
|
||||
else if (se.state == INIT) begin
|
||||
seNext.stride = truncate(addr - se.lastAddr);
|
||||
seNext.state = TRANSIENT;
|
||||
seNext.lastAddr = addr;
|
||||
$display(", set stride to %h", seNext.stride);
|
||||
end
|
||||
else if (se.state == TRANSIENT || se.state == STEADY) begin
|
||||
if (truncate(addr - se.lastAddr) == se.stride) begin
|
||||
case (se.state)
|
||||
TRANSIENT: seNext.lastPrefetch = 0;
|
||||
STEADY: seNext.lastPrefetch = (seNext.lastPrefetch == 0) ? 0 : se.lastPrefetch - 1;
|
||||
endcase
|
||||
seNext.state = STEADY;
|
||||
seNext.lastAddr = addr;
|
||||
historyVec <= shiftInAt0(historyVec, index);
|
||||
$display(", stride %h is confirmed!", seNext.stride);
|
||||
end
|
||||
else begin
|
||||
seNext.state = TRANSIENT;
|
||||
seNext.stride = truncate(addr - se.lastAddr);
|
||||
seNext.lastAddr = addr;
|
||||
$display(", old stride is broken! New stride: %h", seNext.stride);
|
||||
end
|
||||
end
|
||||
se <= seNext;
|
||||
endmethod
|
||||
endmodule
|
||||
|
||||
typedef struct {
|
||||
Bit#(12) lastAddr; //TODO maybe store less bits here?
|
||||
Bit#(13) stride;
|
||||
StrideState state;
|
||||
Bit#(4) cLinesPrefetched; //Stores how many cache lines have been prefetched for this instruction
|
||||
} StrideEntry2 deriving (Bits, Eq, FShow);
|
||||
|
||||
typedef 3 CLinesAheadToPrefetch;
|
||||
|
||||
module mkStridePCPrefetcher2(PCPrefetcher)
|
||||
provisos(
|
||||
Alias#(strideTableIndexT, Bit#(TLog#(StrideTableSize))),
|
||||
Alias#(historyVecIndexT, Bit#(TLog#(HistoryLen)))
|
||||
);
|
||||
Reg#(Vector#(HistoryLen, Tuple2#(strideTableIndexT, Addr))) historyVec <- mkReg(replicate(?));
|
||||
Vector#(StrideTableSize, Reg#(StrideEntry2)) strideTable <- replicateM(mkReg(unpack(0)));
|
||||
|
||||
function Maybe#(historyVecIndexT) getNextPrefetchHistoryIndex;
|
||||
function Bool canPrefetch(Tuple2#(strideTableIndexT, Addr) entry);
|
||||
strideTableIndexT idx = tpl_1(entry);
|
||||
return (strideTable[idx].state == STEADY &&
|
||||
strideTable[idx].cLinesPrefetched !=
|
||||
fromInteger(valueof(CLinesAheadToPrefetch)));
|
||||
endfunction
|
||||
|
||||
//Find first entry that allows more prefetches
|
||||
case (findIndex(canPrefetch, historyVec)) matches
|
||||
tagged Valid .historyIdx: return Valid(pack(historyIdx));
|
||||
Invalid: return Invalid;
|
||||
endcase
|
||||
endfunction
|
||||
|
||||
method ActionValue#(Addr) getNextPrefetchAddr if
|
||||
(getNextPrefetchHistoryIndex() matches tagged Valid .historyIdx);
|
||||
match {.strideIdx, .fullAddr} = historyVec[historyIdx];
|
||||
Reg#(StrideEntry2) se = strideTable[strideIdx];
|
||||
se.cLinesPrefetched <= se.cLinesPrefetched + 1;
|
||||
Bit#(13) strideToUse;
|
||||
Bit#(13) cLineSize = fromInteger(valueof(DataSz));
|
||||
if (se.stride[12] == 1 && se.stride > -cLineSize) begin
|
||||
//stride is negative and jumps less than one cline
|
||||
strideToUse = -cLineSize;
|
||||
end
|
||||
else if (se.stride[12] == 0 && se.stride < cLineSize) begin
|
||||
//stride is positive and jumps less than one cline
|
||||
strideToUse = cLineSize;
|
||||
end
|
||||
else
|
||||
strideToUse = se.stride;
|
||||
|
||||
let reqAddr = fullAddr +
|
||||
(signExtend(strideToUse) * zeroExtend(se.cLinesPrefetched + 1));
|
||||
$display("%t Stride Prefetcher getNextPrefetchAddr requesting %h for entry %h", $time, reqAddr, strideIdx);
|
||||
return reqAddr;
|
||||
endmethod
|
||||
method Action reportAccess(Addr addr, Bit#(16) pcHash, HitOrMiss hitMiss);
|
||||
//Find slot in vector
|
||||
//if miss and slot empty
|
||||
//if slot init, put address, stride and move to transit
|
||||
//if slot transit or steady, verify stride, and move to steady
|
||||
// also put last_prefetched
|
||||
//if stride wrong, move to transit
|
||||
strideTableIndexT index = truncate(pcHash);
|
||||
Reg#(StrideEntry2) se = strideTable[index];
|
||||
StrideEntry2 seNext = se;
|
||||
Bit#(13) observedStride = {1'b0, addr[11:0]} - {1'b0, se.lastAddr};
|
||||
$writeh("%t Stride Prefetcher reportAccess ", $time,
|
||||
fshow(hitMiss), " ", addr,
|
||||
". Entry ", index, " state is ", fshow(se.state));
|
||||
if (se.state == EMPTY) begin
|
||||
if (hitMiss == MISS) begin
|
||||
seNext.lastAddr = truncate(addr);
|
||||
seNext.state = INIT;
|
||||
$display(", allocate entry");
|
||||
end
|
||||
else begin
|
||||
$display(", ignore");
|
||||
end
|
||||
end
|
||||
else if (se.state == INIT && observedStride != 0) begin
|
||||
seNext.stride = observedStride;
|
||||
seNext.state = TRANSIENT;
|
||||
seNext.lastAddr = truncate(addr);
|
||||
$display(", set stride to %h", seNext.stride);
|
||||
end
|
||||
else if ((se.state == TRANSIENT || se.state == STEADY) && observedStride != 0) begin
|
||||
if (observedStride == se.stride) begin
|
||||
if (se.state == TRANSIENT) begin
|
||||
//Here we transition from TRANSIENT to STEADY, so init this field
|
||||
seNext.cLinesPrefetched = 0;
|
||||
end
|
||||
else begin
|
||||
//state == STEADY
|
||||
if (se.lastAddr[11:6] != addr[11:6]) begin
|
||||
//This means we have crossed a cache line since last access
|
||||
seNext.cLinesPrefetched =
|
||||
(se.cLinesPrefetched == 0) ? 0 : se.cLinesPrefetched - 1;
|
||||
end
|
||||
end
|
||||
seNext.state = STEADY;
|
||||
seNext.lastAddr = truncate(addr);
|
||||
historyVec <= shiftInAt0(historyVec, tuple2(index, addr));
|
||||
$display(", stride %h is confirmed!", seNext.stride);
|
||||
end
|
||||
else begin
|
||||
seNext.state = TRANSIENT;
|
||||
seNext.stride = observedStride;
|
||||
seNext.lastAddr = truncate(addr);
|
||||
$display(", old stride is broken! New stride: %h", seNext.stride);
|
||||
end
|
||||
end
|
||||
else
|
||||
$display("");
|
||||
se <= seNext;
|
||||
endmethod
|
||||
|
||||
|
||||
|
||||
endmodule
|
||||
|
||||
module mkL1IPrefetcher(Prefetcher);
|
||||
//let m <- mkNextLinePrefetcher;
|
||||
//let m <- mkMultiWindowPrefetcher;
|
||||
//let m <- mkNextLineOnAllPrefetcher;
|
||||
let m <- mkDoNothingPrefetcher;
|
||||
return m;
|
||||
endmodule
|
||||
|
||||
module mkL1DPrefetcher(PCPrefetcher);
|
||||
//let m <- mkNextLineOnAllPrefetcher;
|
||||
//let m <- mkStridePCPrefetcher2;
|
||||
let m <- mkDoNothingPCPrefetcher;
|
||||
return m;
|
||||
endmodule
|
||||
|
||||
module mkLLIPrefetcher(Prefetcher);
|
||||
//let m <- mkNextLineOnMissPrefetcher;
|
||||
let m <- mkMultiWindowPrefetcher;
|
||||
//let m <- mkStridePCPrefetcher2;
|
||||
//let m <- mkPrintPrefetcher;
|
||||
//let m <- mkDoNothingPrefetcher;
|
||||
return m;
|
||||
endmodule
|
||||
|
||||
module mkLLDPrefetcher(Prefetcher);
|
||||
//let m <- mkNextLineOnAllPrefetcher;
|
||||
let m <- mkPrintPrefetcher;
|
||||
//let m <- mkDoNothingPrefetcher;
|
||||
return m;
|
||||
endmodule
|
||||
249
src_Core/RISCY_OOO/coherence/src/test/Prefetcher_test.bsv
Normal file
249
src_Core/RISCY_OOO/coherence/src/test/Prefetcher_test.bsv
Normal file
@@ -0,0 +1,249 @@
|
||||
import Prefetcher::*;
|
||||
import StmtFSM::*;
|
||||
import Types::*;
|
||||
|
||||
|
||||
module mkMultiWindowPrefetcherTest(Empty);
|
||||
//let p <- mkMultipleWindowPrefetcher;
|
||||
//TODO pass in value of cachelinesinrange
|
||||
let p <- mkMultiWindowPrefetcher;
|
||||
mkAutoFSM(
|
||||
seq
|
||||
// ----- Send misses and stuff to one window -----
|
||||
action
|
||||
p.reportMiss('h80000040);
|
||||
endaction
|
||||
action
|
||||
let x <- p.getNextPrefetchAddr;
|
||||
doAssert(x == 'h80000080, "test fail!");
|
||||
endaction
|
||||
action
|
||||
let x <- p.getNextPrefetchAddr;
|
||||
doAssert(x == 'h800000c0, "test fail!");
|
||||
endaction
|
||||
action
|
||||
p.reportHit('h800000c0); //Report hit inside window
|
||||
endaction
|
||||
action
|
||||
let x <- p.getNextPrefetchAddr;
|
||||
doAssert(x == 'h80000100, "test fail!");
|
||||
endaction
|
||||
action
|
||||
p.reportHit('h80004000); //Report hit outside window
|
||||
endaction
|
||||
action
|
||||
let x <- p.getNextPrefetchAddr; //Previous window still recommended
|
||||
doAssert(x == 'h80000140, "test fail!");
|
||||
endaction
|
||||
action
|
||||
p.reportMiss('h80000140); //Report miss inside window
|
||||
endaction
|
||||
action
|
||||
let x <- p.getNextPrefetchAddr; //Previous window still recommended
|
||||
doAssert(x == 'h80000180, "test fail!");
|
||||
endaction
|
||||
|
||||
// ----- Allocate other windows -----
|
||||
action
|
||||
p.reportMiss('h70000000); //Report miss outside window
|
||||
endaction
|
||||
action
|
||||
let x <- p.getNextPrefetchAddr; //new window recommended
|
||||
doAssert(x == 'h70000040, "test fail!");
|
||||
endaction
|
||||
action
|
||||
p.reportMiss('h90000000); //Report miss outside window
|
||||
endaction
|
||||
action
|
||||
let x <- p.getNextPrefetchAddr; //new window recommended
|
||||
doAssert(x == 'h90000040, "test fail!");
|
||||
endaction
|
||||
action
|
||||
p.reportMiss('h60000000); //Report miss outside window
|
||||
endaction
|
||||
action
|
||||
let x <- p.getNextPrefetchAddr; //new window recommended
|
||||
doAssert(x == 'h60000040, "test fail!");
|
||||
endaction
|
||||
action
|
||||
p.reportHit('h80000180); //Report hit inside oldest window
|
||||
endaction
|
||||
action
|
||||
let x <- p.getNextPrefetchAddr; //oldest window recommended
|
||||
doAssert(x == 'h800001c0, "test fail!");
|
||||
endaction
|
||||
|
||||
// ----- Trigger window deletion -----
|
||||
action
|
||||
p.reportMiss('h50000000); //Report miss outside window,
|
||||
//discard window with 'h70..
|
||||
endaction
|
||||
action
|
||||
let x <- p.getNextPrefetchAddr; //new window recommended
|
||||
doAssert(x == 'h50000040, "test fail!");
|
||||
endaction
|
||||
action
|
||||
p.reportHit('h70000040); //Report hit inside now deleted window
|
||||
endaction
|
||||
action
|
||||
let x <- p.getNextPrefetchAddr; //most recent window still recommended
|
||||
doAssert(x == 'h50000080, "test fail!");
|
||||
endaction
|
||||
|
||||
// ----- Reorder some more windows around
|
||||
action
|
||||
p.reportMiss('h800001c0); //Report hit inside now deleted window
|
||||
endaction
|
||||
action
|
||||
let x <- p.getNextPrefetchAddr; //most recent window still recommended
|
||||
doAssert(x == 'h80000200, "test fail!");
|
||||
endaction
|
||||
|
||||
|
||||
endseq
|
||||
);
|
||||
endmodule
|
||||
|
||||
|
||||
module mkStridePCPrefetcher2Test(Empty);
|
||||
//let p <- mkMultipleWindowPrefetcher;
|
||||
//TODO pass in value of cachelinesinrange
|
||||
let p <- mkStridePCPrefetcher2;
|
||||
mkAutoFSM(
|
||||
seq
|
||||
// ----- Send misses and stuff to one window -----
|
||||
action p.reportAccess('h80000040, 'h0069, MISS); endaction
|
||||
action p.reportAccess('h80000080, 'h0069, HIT); endaction
|
||||
action p.reportAccess('h800000a0, 'h0069, HIT); endaction
|
||||
action p.reportAccess('h800000c0, 'h0069, MISS); endaction
|
||||
action p.reportAccess('h800000e0, 'h0069, MISS); endaction
|
||||
action
|
||||
let x <- p.getNextPrefetchAddr;
|
||||
doAssert(x == 'h80000120, "test fail!");
|
||||
endaction
|
||||
action p.reportAccess('h80000100, 'h0069, HIT); endaction
|
||||
action p.reportAccess('h80000120, 'h0069, HIT); endaction
|
||||
action p.reportAccess('h80000140, 'h0069, HIT); endaction
|
||||
action
|
||||
let x <- p.getNextPrefetchAddr;
|
||||
doAssert(x == 'h80000180, "test fail!");
|
||||
endaction
|
||||
action
|
||||
let x <- p.getNextPrefetchAddr;
|
||||
doAssert(x == 'h800001c0, "test fail!");
|
||||
endaction
|
||||
action
|
||||
let x <- p.getNextPrefetchAddr;
|
||||
doAssert(x == 'h80000200, "test fail!");
|
||||
endaction
|
||||
action p.reportAccess('h900001f0, 'h006a, MISS); endaction
|
||||
action p.reportAccess('h900001c0, 'h006a, HIT); endaction
|
||||
action p.reportAccess('h90000190, 'h006a, HIT); endaction
|
||||
action
|
||||
let x <- p.getNextPrefetchAddr;
|
||||
doAssert(x == 'h90000150, "test fail!");
|
||||
endaction
|
||||
action
|
||||
let x <- p.getNextPrefetchAddr;
|
||||
doAssert(x == 'h90000110, "test fail!");
|
||||
endaction
|
||||
action p.reportAccess('h90000100, 'h006b, MISS); endaction
|
||||
action p.reportAccess('h90000200, 'h006b, MISS); endaction
|
||||
action p.reportAccess('h90000300, 'h006b, MISS); endaction
|
||||
action
|
||||
let x <- p.getNextPrefetchAddr;
|
||||
doAssert(x == 'h90000400, "test fail!");
|
||||
endaction
|
||||
action
|
||||
let x <- p.getNextPrefetchAddr;
|
||||
doAssert(x == 'h90000500, "test fail!");
|
||||
endaction
|
||||
action p.reportAccess('h90000160, 'h006a, HIT); endaction
|
||||
// -- use older entry
|
||||
action
|
||||
let x <- p.getNextPrefetchAddr;
|
||||
doAssert(x == 'h900000e0, "test fail!");
|
||||
endaction
|
||||
action
|
||||
let x <- p.getNextPrefetchAddr;
|
||||
doAssert(x == 'h900000a0, "test fail!");
|
||||
endaction
|
||||
action
|
||||
let x <- p.getNextPrefetchAddr;
|
||||
doAssert(x == 'h90000600, "test fail!");
|
||||
endaction
|
||||
endseq
|
||||
);
|
||||
endmodule
|
||||
|
||||
|
||||
module mkStridePCPrefetcherTest(Empty);
|
||||
//let p <- mkMultipleWindowPrefetcher;
|
||||
//TODO pass in value of cachelinesinrange
|
||||
let p <- mkStridePCPrefetcher;
|
||||
mkAutoFSM(
|
||||
seq
|
||||
// ----- Send misses and stuff to one window -----
|
||||
action
|
||||
p.reportAccess('h80000040, 'h0069, MISS);
|
||||
endaction
|
||||
action
|
||||
p.reportAccess('h80000080, 'h0069, HIT);
|
||||
endaction
|
||||
action
|
||||
p.reportAccess('h800000a0, 'h0069, HIT);
|
||||
endaction
|
||||
action
|
||||
p.reportAccess('h800000c0, 'h0069, MISS);
|
||||
endaction
|
||||
action
|
||||
let x <- p.getNextPrefetchAddr;
|
||||
doAssert(x == 'h80000100, "test fail!");
|
||||
endaction
|
||||
action
|
||||
let x <- p.getNextPrefetchAddr;
|
||||
doAssert(x == 'h80000140, "test fail!");
|
||||
endaction
|
||||
action
|
||||
p.reportAccess('h800000e0, 'h0069, MISS);
|
||||
endaction
|
||||
action
|
||||
let x <- p.getNextPrefetchAddr;
|
||||
doAssert(x == 'h80000180, "test fail!");
|
||||
endaction
|
||||
action
|
||||
p.reportAccess('h80000100, 'h0069, MISS);
|
||||
endaction
|
||||
action
|
||||
p.reportAccess('h80000120, 'h0069, MISS);
|
||||
endaction
|
||||
action
|
||||
p.reportAccess('h80000140, 'h0069, MISS);
|
||||
endaction
|
||||
action
|
||||
let x <- p.getNextPrefetchAddr;
|
||||
doAssert(x == 'h80000160, "test fail!");
|
||||
endaction
|
||||
action
|
||||
p.reportAccess('h90000040, 'h0000, MISS);
|
||||
endaction
|
||||
action
|
||||
p.reportAccess('h90000140, 'h0000, MISS);
|
||||
endaction
|
||||
action
|
||||
p.reportAccess('h90000240, 'h0000, MISS);
|
||||
endaction
|
||||
action
|
||||
let x <- p.getNextPrefetchAddr;
|
||||
doAssert(x == 'h90000340, "test fail!");
|
||||
endaction
|
||||
action
|
||||
p.reportAccess('h80000160, 'h0069, MISS);
|
||||
endaction
|
||||
action
|
||||
let x <- p.getNextPrefetchAddr;
|
||||
doAssert(x == 'h80000180, "test fail!");
|
||||
endaction
|
||||
endseq
|
||||
);
|
||||
endmodule
|
||||
@@ -328,12 +328,12 @@ module mkMemExePipeline#(MemExeInput inIfc)(MemExePipeline);
|
||||
Fifo#(1, WaitStResp) waitStRespQ <- mkCFFifo;
|
||||
`endif
|
||||
// fifo for req mem
|
||||
Fifo#(1, Tuple3#(LdQTag, Addr, Bool)) reqLdQ <- mkBypassFifo;
|
||||
Fifo#(1, Tuple4#(LdQTag, Addr, Bool, Bit#(16))) reqLdQ <- mkBypassFifo;
|
||||
Fifo#(1, ProcRq#(DProcReqId)) reqLrScAmoQ <- mkBypassFifo;
|
||||
`ifdef TSO_MM
|
||||
Fifo#(1, Addr) reqStQ <- mkBypassFifo;
|
||||
Fifo#(1, Tuple2#(Addr, Bit#(16))) reqStQ <- mkBypassFifo;
|
||||
`else
|
||||
Fifo#(1, Tuple2#(SBIndex, Addr)) reqStQ <- mkBypassFifo;
|
||||
Fifo#(1, Tuple2#(SBIndex, Addr, Bit#(16))) reqStQ <- mkBypassFifo;
|
||||
`endif
|
||||
// fifo for load result
|
||||
Fifo#(2, Tuple2#(LdQTag, MemResp)) forwardQ <- mkCFFifo;
|
||||
@@ -691,7 +691,6 @@ module mkMemExePipeline#(MemExeInput inIfc)(MemExePipeline);
|
||||
function Bool is_16b_inst (Bit #(n) inst);
|
||||
return (inst [1:0] != 2'b11);
|
||||
endfunction
|
||||
let pc = inIfc.rob_getPC(x.tag);
|
||||
let ppc = inIfc.rob_getPredPC(x.tag);
|
||||
let inst = inIfc.rob_getOrig_Inst(x.tag);
|
||||
let validPc = is_16b_inst(inst) ? addPc(pc,2) : addPc(pc,4);
|
||||
@@ -702,6 +701,7 @@ module mkMemExePipeline#(MemExeInput inIfc)(MemExePipeline);
|
||||
end
|
||||
`endif
|
||||
`endif
|
||||
let pc = inIfc.rob_getPC(x.tag);
|
||||
|
||||
// update LSQ
|
||||
LSQUpdateAddrResult updRes <- lsq.updateAddr(
|
||||
@@ -723,7 +723,8 @@ module mkMemExePipeline#(MemExeInput inIfc)(MemExePipeline);
|
||||
issueLd.wset(LSQIssueLdInfo {
|
||||
tag: ldTag,
|
||||
paddr: paddr,
|
||||
shiftedBE: x.shiftedBE
|
||||
shiftedBE: x.shiftedBE,
|
||||
pcHash: hash(getAddr(pc))
|
||||
});
|
||||
end
|
||||
|
||||
@@ -779,7 +780,7 @@ module mkMemExePipeline#(MemExeInput inIfc)(MemExePipeline);
|
||||
`endif
|
||||
end
|
||||
else if(issRes == ToCache) begin
|
||||
reqLdQ.enq(tuple3(zeroExtend(info.tag), info.paddr, info.shiftedBE == TagMemAccess));
|
||||
reqLdQ.enq(tuple4(zeroExtend(info.tag), info.paddr, info.shiftedBE == TagMemAccess, info.pcHash));
|
||||
// perf: load mem latency
|
||||
ldMemLatTimer.start(info.tag);
|
||||
end
|
||||
@@ -955,7 +956,8 @@ module mkMemExePipeline#(MemExeInput inIfc)(MemExePipeline);
|
||||
byteEn: ?,
|
||||
data: ?,
|
||||
amoInst: ?,
|
||||
loadTags: False
|
||||
loadTags: False,
|
||||
pcHash: ?
|
||||
};
|
||||
reqLrScAmoQ.enq(req);
|
||||
if(verbose) $display("[doDeqLdQ_Lr_issue] ", fshow(lsqDeqLd), "; ", fshow(req));
|
||||
@@ -1172,7 +1174,7 @@ module mkMemExePipeline#(MemExeInput inIfc)(MemExePipeline);
|
||||
);
|
||||
// send to mem
|
||||
Addr addr = lsqDeqSt.paddr;
|
||||
reqStQ.enq(addr);
|
||||
reqStQ.enq(tuple2(addr, lsqDeqSt.pcHash));
|
||||
// record waiting for store resp
|
||||
waitStRespQ.enq(WaitStResp {
|
||||
offset: getLineMemDataOffset(addr),
|
||||
@@ -1196,7 +1198,7 @@ module mkMemExePipeline#(MemExeInput inIfc)(MemExePipeline);
|
||||
);
|
||||
lsq.deqSt;
|
||||
// send to SB
|
||||
stb.enq(sbIdx, lsqDeqSt.paddr, lsqDeqSt.shiftedBE, lsqDeqSt.stData);
|
||||
stb.enq(sbIdx, lsqDeqSt.paddr, lsqDeqSt.shiftedBE, lsqDeqSt.stData, lsqDeqSt.pcHash);
|
||||
// ROB should have already been set to executed
|
||||
if(verbose) $display("[doDeqStQ_St] ", fshow(lsqDeqSt));
|
||||
// normal store should not have .rl, so no need to check SB empty
|
||||
@@ -1206,7 +1208,7 @@ module mkMemExePipeline#(MemExeInput inIfc)(MemExePipeline);
|
||||
// send store to mem
|
||||
rule doIssueSB;
|
||||
let {sbIdx, en} <- stb.issue;
|
||||
reqStQ.enq(tuple2(sbIdx, {en.addr, 0}));
|
||||
reqStQ.enq(tuple3(sbIdx, {en.addr, 0}, en.pcHash));
|
||||
// perf: store mem latency
|
||||
stMemLatTimer.start(sbIdx);
|
||||
endrule
|
||||
@@ -1300,7 +1302,8 @@ module mkMemExePipeline#(MemExeInput inIfc)(MemExePipeline);
|
||||
aq: lsqDeqSt.acq,
|
||||
rl: lsqDeqSt.rel
|
||||
},
|
||||
loadTags: False
|
||||
loadTags: False,
|
||||
pcHash: ?
|
||||
};
|
||||
reqLrScAmoQ.enq(req);
|
||||
if(verbose) $display("[doDeqStQ_ScAmo_issue] ", fshow(lsqDeqSt), "; ", fshow(req));
|
||||
@@ -1514,7 +1517,7 @@ module mkMemExePipeline#(MemExeInput inIfc)(MemExePipeline);
|
||||
|
||||
// send req to D$
|
||||
rule sendLdToMem;
|
||||
let {lsqTag, addr, loadTags} <- toGet(reqLdQ).get;
|
||||
let {lsqTag, addr, loadTags, pcHash} <- toGet(reqLdQ).get;
|
||||
dMem.procReq.req(ProcRq {
|
||||
id: zeroExtend(lsqTag),
|
||||
addr: addr,
|
||||
@@ -1523,16 +1526,17 @@ module mkMemExePipeline#(MemExeInput inIfc)(MemExePipeline);
|
||||
byteEn: ?,
|
||||
data: ?,
|
||||
amoInst: ?,
|
||||
loadTags: loadTags
|
||||
loadTags: loadTags,
|
||||
pcHash: pcHash
|
||||
});
|
||||
endrule
|
||||
(* descending_urgency = "sendLdToMem, sendStToMem" *) // prioritize Ld over St
|
||||
rule sendStToMem;
|
||||
`ifdef TSO_MM
|
||||
let addr <- toGet(reqStQ).get;
|
||||
let {addr, pcHash} <- toGet(reqStQ).get;
|
||||
DProcReqId id = 0;
|
||||
`else
|
||||
let {sbIdx, addr} <- toGet(reqStQ).get;
|
||||
let {sbIdx, addr, pcHash} <- toGet(reqStQ).get;
|
||||
DProcReqId id = zeroExtend(sbIdx);
|
||||
`endif
|
||||
dMem.procReq.req(ProcRq {
|
||||
@@ -1543,7 +1547,8 @@ module mkMemExePipeline#(MemExeInput inIfc)(MemExePipeline);
|
||||
byteEn: ?,
|
||||
data: ?,
|
||||
amoInst: ?,
|
||||
loadTags: False
|
||||
loadTags: False,
|
||||
pcHash: pcHash
|
||||
});
|
||||
endrule
|
||||
(* descending_urgency = "sendLrScAmoToMem, sendStToMem" *) // prioritize Lr/Sc/Amo over St
|
||||
|
||||
@@ -741,7 +741,7 @@ module mkRenameStage#(RenameInput inIfc)(RenameStage);
|
||||
lsq.enqLd(inst_tag, mem_inst, allow_cap, phy_regs.dst, spec_bits, hash(getAddr(pc)));
|
||||
end
|
||||
else begin
|
||||
lsq.enqSt(inst_tag, mem_inst, phy_regs.dst, spec_bits);
|
||||
lsq.enqSt(inst_tag, mem_inst, phy_regs.dst, spec_bits, hash(getAddr(pc)));
|
||||
end
|
||||
end
|
||||
else begin
|
||||
@@ -1075,7 +1075,7 @@ module mkRenameStage#(RenameInput inIfc)(RenameStage);
|
||||
lsq.enqLd(inst_tag, mem_inst, phy_regs.dst, spec_bits, hash(getAddr(pc)));
|
||||
end
|
||||
else begin
|
||||
lsq.enqSt(inst_tag, mem_inst, phy_regs.dst, spec_bits);
|
||||
lsq.enqSt(inst_tag, mem_inst, phy_regs.dst, spec_bits, hash(getAddr(pc)));
|
||||
end
|
||||
end
|
||||
else begin
|
||||
|
||||
@@ -94,7 +94,7 @@ module mkDirPredictor(DirPredictor#(DirPredTrainInfo));
|
||||
`endif
|
||||
|
||||
`ifdef DIR_PRED_TOUR
|
||||
`ifdef SECURITY
|
||||
`ifdef SECURITY_BRPRED
|
||||
let m <- mkTourPredSecure;
|
||||
`else
|
||||
let m <- mkTourPred;
|
||||
|
||||
@@ -52,6 +52,8 @@ typedef enum {
|
||||
LLCDmaMemLdLat,
|
||||
LLCNormalMemLdCnt,
|
||||
LLCNormalMemLdLat,
|
||||
LLCInstructionLdCnt,
|
||||
LLCInstructionLdLat,
|
||||
LLCMshrBlockCycles, // full MSHR blocks new cRq
|
||||
LLCDownRespCnt,
|
||||
LLCDownRespDataCnt,
|
||||
|
||||
@@ -295,6 +295,7 @@ typedef struct {
|
||||
LdQTag tag;
|
||||
Addr paddr;
|
||||
ByteOrTagEn shiftedBE;
|
||||
Bit#(16) pcHash;
|
||||
} LSQIssueLdInfo deriving(Bits, Eq, FShow);
|
||||
|
||||
typedef struct {
|
||||
@@ -342,6 +343,7 @@ typedef struct {
|
||||
MemTaggedData stData;
|
||||
Bool allowCapAmoLd;
|
||||
Maybe#(Trap) fault;
|
||||
Bit#(16) pcHash;
|
||||
} StQDeqEntry deriving (Bits, Eq, FShow);
|
||||
|
||||
interface SplitLSQ;
|
||||
@@ -354,11 +356,12 @@ interface SplitLSQ;
|
||||
MemInst mem_inst,
|
||||
Maybe#(PhyDst) dst,
|
||||
SpecBits spec_bits,
|
||||
Bit#(16) pc_hash);
|
||||
Bit#(16) pcHash);
|
||||
method Action enqSt(InstTag inst_tag,
|
||||
MemInst mem_inst,
|
||||
Maybe#(PhyDst) dst,
|
||||
SpecBits spec_bits);
|
||||
SpecBits spec_bits,
|
||||
Bit#(16) pcHash);
|
||||
// A mem inst needs orignal BE (not shifted) at addr translation
|
||||
method ByteOrTagEn getOrigBE(LdStQTag t);
|
||||
// Retrieve information when we want to wakeup RS early in case
|
||||
@@ -663,7 +666,7 @@ module mkSplitLSQ(SplitLSQ);
|
||||
Vector#(LdQSize, Reg#(Bool)) ld_acq <- replicateM(mkConfigRegU);
|
||||
Vector#(LdQSize, Reg#(Bool)) ld_rel <- replicateM(mkConfigRegU);
|
||||
Vector#(LdQSize, Reg#(Maybe#(PhyDst))) ld_dst <- replicateM(mkConfigRegU);
|
||||
Vector#(LdQSize, Reg#(Bit#(16))) ld_pc_hash <- replicateM(mkConfigRegU);
|
||||
Vector#(LdQSize, Reg#(Bit#(16))) ld_pcHash <- replicateM(mkConfigRegU);
|
||||
Vector#(LdQSize, Reg#(Bool)) ld_waitForOlderSt <- replicateM(mkConfigRegU);
|
||||
Vector#(LdQSize, Ehr#(2, Addr)) ld_paddr <- replicateM(mkEhr(?));
|
||||
Vector#(LdQSize, Ehr#(2, Bool)) ld_isMMIO <- replicateM(mkEhr(?));
|
||||
@@ -856,6 +859,7 @@ module mkSplitLSQ(SplitLSQ);
|
||||
Vector#(StQSize, Reg#(Bool)) st_acq <- replicateM(mkRegU);
|
||||
Vector#(StQSize, Reg#(Bool)) st_rel <- replicateM(mkRegU);
|
||||
Vector#(StQSize, Reg#(Maybe#(PhyDst))) st_dst <- replicateM(mkRegU);
|
||||
Vector#(StQSize, Reg#(Bit#(16))) st_pcHash <- replicateM(mkRegU);
|
||||
Vector#(StQSize, Ehr#(2, Addr)) st_paddr <- replicateM(mkEhr(?));
|
||||
Vector#(StQSize, Ehr#(2, Bool)) st_isMMIO <- replicateM(mkEhr(?));
|
||||
Vector#(StQSize, Ehr#(2, MemDataByteEn)) st_shiftedBE <- replicateM(mkEhr(?));
|
||||
@@ -1126,7 +1130,8 @@ module mkSplitLSQ(SplitLSQ);
|
||||
let info = LSQIssueLdInfo {
|
||||
tag: tag,
|
||||
paddr: ld_paddr_findIss[tag],
|
||||
shiftedBE: ld_shiftedBE_findIss[tag]
|
||||
shiftedBE: ld_shiftedBE_findIss[tag],
|
||||
pcHash: ld_pcHash[tag]
|
||||
};
|
||||
issueLdInfo.wset(info);
|
||||
if(verbose) begin
|
||||
@@ -1458,7 +1463,7 @@ module mkSplitLSQ(SplitLSQ);
|
||||
MemInst mem_inst,
|
||||
Maybe#(PhyDst) dst,
|
||||
SpecBits spec_bits,
|
||||
Bit#(16) pc_hash) if(ld_can_enq_wire && !wrongSpec_conflict);
|
||||
Bit#(16) pcHash) if(ld_can_enq_wire && !wrongSpec_conflict);
|
||||
if(verbose) begin
|
||||
$display("[LSQ - enqLd] enqP %d; ", ld_enqP,
|
||||
"; ", fshow(inst_tag),
|
||||
@@ -1487,8 +1492,8 @@ module mkSplitLSQ(SplitLSQ);
|
||||
ld_executing_enq[ld_enqP] <= False;
|
||||
ld_done_enq[ld_enqP] <= False;
|
||||
ld_killed_enq[ld_enqP] <= Invalid;
|
||||
ld_pc_hash[ld_enqP] <= pc_hash;
|
||||
ld_waitForOlderSt[ld_enqP] <= stlPred.pred(pc_hash);
|
||||
ld_pcHash[ld_enqP] <= pcHash;
|
||||
ld_waitForOlderSt[ld_enqP] <= stlPred.pred(pcHash);
|
||||
ld_readFrom_enq[ld_enqP] <= Invalid;
|
||||
ld_depLdQDeq_enq[ld_enqP] <= Invalid;
|
||||
ld_depStQDeq_enq[ld_enqP] <= Invalid;
|
||||
@@ -1516,7 +1521,8 @@ module mkSplitLSQ(SplitLSQ);
|
||||
method Action enqSt(InstTag inst_tag,
|
||||
MemInst mem_inst,
|
||||
Maybe#(PhyDst) dst,
|
||||
SpecBits spec_bits) if(st_can_enq_wire && !wrongSpec_conflict);
|
||||
SpecBits spec_bits,
|
||||
Bit#(16) pcHash) if(st_can_enq_wire && !wrongSpec_conflict);
|
||||
if(verbose) begin
|
||||
$display("[LSQ - enqSt] enqP %d; ", st_enqP,
|
||||
"; ", fshow(inst_tag),
|
||||
@@ -1540,6 +1546,7 @@ module mkSplitLSQ(SplitLSQ);
|
||||
st_rel[st_enqP] <= mem_inst.rl;
|
||||
st_dst[st_enqP] <= dst;
|
||||
st_fault_enq[st_enqP] <= Invalid;
|
||||
st_pcHash[st_enqP] <= pcHash;
|
||||
st_allowCapAmoLd_enq[st_enqP] <= False;
|
||||
st_computed_enq[st_enqP] <= False;
|
||||
st_verified_enq[st_enqP] <= False;
|
||||
@@ -1716,7 +1723,7 @@ module mkSplitLSQ(SplitLSQ);
|
||||
LdKilledBy by = lsqTag matches tagged Ld .unuse ? Ld : St;
|
||||
ld_killed_updAddr[killTag] <= Valid (by);
|
||||
if(verbose) begin
|
||||
$display("[LSQ - updateAddr] kill tag %d", killTag, " ld_hash: %x", ld_pc_hash[killTag]);
|
||||
$display("[LSQ - updateAddr] kill tag %d", killTag, " ld_hash: %x", ld_pcHash[killTag]);
|
||||
end
|
||||
// checks
|
||||
doAssert(ld_computed_updAddr[killTag], "must be computed");
|
||||
@@ -2119,7 +2126,7 @@ module mkSplitLSQ(SplitLSQ);
|
||||
end
|
||||
Bool waited = ld_waitForOlderSt[deqP]; // Don't negative train if we waited for older stores.
|
||||
// Update predictor.
|
||||
stlPred.update(ld_pc_hash[deqP], waited, killedLd);
|
||||
stlPred.update(ld_pcHash[deqP], waited, killedLd);
|
||||
|
||||
// remove the entry
|
||||
ld_valid_deqLd[deqP] <= False;
|
||||
@@ -2152,7 +2159,8 @@ module mkSplitLSQ(SplitLSQ);
|
||||
shiftedBE: st_shiftedBE_deqSt[deqP],
|
||||
stData: st_stData_deqSt[deqP],
|
||||
allowCapAmoLd: st_allowCapAmoLd_deqSt[deqP],
|
||||
fault: st_fault_deqSt[deqP]
|
||||
fault: st_fault_deqSt[deqP],
|
||||
pcHash: st_pcHash[deqP]
|
||||
};
|
||||
endmethod
|
||||
|
||||
|
||||
@@ -68,6 +68,7 @@ typedef struct {
|
||||
SBBlockAddr addr;
|
||||
SBByteEn byteEn;
|
||||
CLine line;
|
||||
Bit#(16) pcHash;
|
||||
} SBEntry deriving(Bits, Eq, FShow);
|
||||
|
||||
// result of searching (e.g. load byass)
|
||||
@@ -79,7 +80,7 @@ typedef struct {
|
||||
interface StoreBuffer;
|
||||
method Bool isEmpty;
|
||||
method Maybe#(SBIndex) getEnqIndex(Addr paddr);
|
||||
method Action enq(SBIndex idx, Addr paddr, MemDataByteEn be, MemTaggedData data);
|
||||
method Action enq(SBIndex idx, Addr paddr, MemDataByteEn be, MemTaggedData data, Bit#(16) pcHash);
|
||||
method ActionValue#(SBEntry) deq(SBIndex idx);
|
||||
method ActionValue#(Tuple2#(SBIndex, SBEntry)) issue;
|
||||
method SBSearchRes search(Addr paddr, ByteOrTagEn be); // load bypass/stall or atomic inst stall
|
||||
@@ -191,7 +192,7 @@ module mkStoreBufferEhr(StoreBuffer);
|
||||
end
|
||||
endmethod
|
||||
|
||||
method Action enq(SBIndex idx, Addr paddr, MemDataByteEn be, MemTaggedData d) if(inited);
|
||||
method Action enq(SBIndex idx, Addr paddr, MemDataByteEn be, MemTaggedData d, Bit#(16) pcHash) if(inited);
|
||||
// get data offset
|
||||
SBBlockMemDataSel sel = getSBBlockMemDataSel(paddr);
|
||||
// check whether the entry already exists
|
||||
@@ -211,7 +212,8 @@ module mkStoreBufferEhr(StoreBuffer);
|
||||
entry[idx][enqPort] <= SBEntry {
|
||||
addr: getSBBlockAddr(paddr),
|
||||
byteEn: unpack(pack(byteEn)),
|
||||
line: block
|
||||
line: block,
|
||||
pcHash: pcHash
|
||||
};
|
||||
// this entry must have been sent to issueQ
|
||||
end
|
||||
@@ -228,7 +230,8 @@ module mkStoreBufferEhr(StoreBuffer);
|
||||
entry[idx][enqPort] <= SBEntry {
|
||||
addr: getSBBlockAddr(paddr),
|
||||
byteEn: unpack(pack(byteEn)),
|
||||
line: block
|
||||
line: block,
|
||||
pcHash: pcHash
|
||||
};
|
||||
// send this entry to issueQ
|
||||
doAssert(issueQ.notFull, "SB issueQ should not be full");
|
||||
@@ -311,7 +314,7 @@ endmodule
|
||||
module mkDummyStoreBuffer(StoreBuffer);
|
||||
method Bool isEmpty = True;
|
||||
method Maybe#(SBIndex) getEnqIndex(Addr paddr) = Invalid;
|
||||
method Action enq(SBIndex idx, Addr paddr, MemDataByteEn be, MemTaggedData data);
|
||||
method Action enq(SBIndex idx, Addr paddr, MemDataByteEn be, MemTaggedData data, Bit#(16) pcHash);
|
||||
doAssert(False, "enq should never be called)");
|
||||
endmethod
|
||||
method ActionValue#(SBEntry) deq(SBIndex idx);
|
||||
|
||||
Reference in New Issue
Block a user