Prefetcher implementation in both L1 and LL and data logging

This commit is contained in:
Karlis Susters
2023-01-16 12:26:11 +02:00
parent 69b96cc68f
commit 347107b733
18 changed files with 1200 additions and 76 deletions

View File

@@ -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

View File

@@ -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'

View File

@@ -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)/

View File

@@ -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);

View File

@@ -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

View File

@@ -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,

View File

@@ -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

View File

@@ -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,

View File

@@ -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

View File

@@ -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;

View 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

View 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

View File

@@ -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

View File

@@ -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

View File

@@ -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;

View File

@@ -52,6 +52,8 @@ typedef enum {
LLCDmaMemLdLat,
LLCNormalMemLdCnt,
LLCNormalMemLdLat,
LLCInstructionLdCnt,
LLCInstructionLdLat,
LLCMshrBlockCycles, // full MSHR blocks new cRq
LLCDownRespCnt,
LLCDownRespDataCnt,

View File

@@ -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

View File

@@ -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);