Merge remote-tracking branch 'karlis/CHERI' into ks980-prefetch

This commit is contained in:
Jonathan Woodruff
2023-04-19 13:41:46 +00:00
7 changed files with 983 additions and 106 deletions

View File

@@ -45,10 +45,10 @@ SIM_LLC_ARBITER_LAT ?=
# default check cache deadlock and rename error
CHECK_DEADLOCK ?= true
RENAME_DEBUG ?= false
INSTR_PREFETCHER_LOCATION ?= NONE
INSTR_PREFETCHER_TYPE ?= MULTI_WINDOW
INSTR_PREFETCHER_LOCATION ?= L1
INSTR_PREFETCHER_TYPE ?= MULTI_WINDOW_TARGET
DATA_PREFETCHER_LOCATION ?= NONE
DATA_PREFETCHER_TYPE ?= STRIDE
DATA_PREFETCHER_TYPE ?= MARKOV_ON_HIT_2
# clk frequency depends on core size
ifneq (,$(filter $(CORE_SIZE),TINY SMALL BOOM MEDIUM))
@@ -77,7 +77,7 @@ endif
ifeq (,$(filter $(DATA_PREFETCHER_LOCATION),NONE L1 L1LL LL))
$(error unsupported DATA_PREFETCHER_LOCATION)
endif
ifeq (,$(filter $(DATA_PREFETCHER_TYPE),MARKOV MARKOV_ON_HIT BLOCK STRIDE STRIDE_ADAPTIVE))
ifeq (,$(filter $(DATA_PREFETCHER_TYPE),MARKOV MARKOV_ON_HIT MARKOV_ON_HIT_2 BLOCK STRIDE STRIDE_ADAPTIVE))
$(error unsupported DATA_PREFETCHER_TYPE)
endif

View File

@@ -168,7 +168,6 @@ module mkIBank#(
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;
let llcPrefetcher <- mkLLIPrefetcherInL1I;
@@ -323,7 +322,6 @@ module mkIBank#(
// 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
@@ -536,7 +534,6 @@ module mkIBank#(
prefetcher.reportAccess(req.addr, HIT);
llcPrefetcher.reportAccess(req.addr, HIT);
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);
@@ -773,11 +770,10 @@ module mkIBank#(
endrule
rule discardPrefetchRqResult(
//cRqMshr.sendRsToC.getResult(prefetchIndexQ.first) matches tagged Valid .inst);
prefetchRqDone[prefetchIndexQ.first]);
cRqMshr.prefetcher.getResult(prefetchIndexQ.first) matches tagged Valid .inst);
prefetchIndexQ.deq;
removedCRqs.incr(1);
cRqMshr.sendRsToC.releaseEntry(prefetchIndexQ.first); // release MSHR entry
cRqMshr.prefetcher.releaseEntry(prefetchIndexQ.first); // release MSHR entry
if (verbose)
$display("%t I %m discardPrefetchRqResult: ", $time,
fshow(prefetchIndexQ.first)

View File

@@ -143,6 +143,14 @@ interface ICRqMshr_sendRsToC#(
method Maybe#(resultT) getResult(Bit#(TLog#(cRqNum)) n);
endinterface
interface ICRqMshr_prefetcher#(
numeric type cRqNum,
type resultT
);
method Action releaseEntry(Bit#(TLog#(cRqNum)) n);
method Maybe#(resultT) getResult(Bit#(TLog#(cRqNum)) n);
endinterface
interface ICRqMshr#(
numeric type cRqNum,
type wayT,
@@ -156,6 +164,9 @@ interface ICRqMshr#(
// port for sendRsToC
interface ICRqMshr_sendRsToC#(cRqNum, resultT) sendRsToC;
// port for prefetcher
interface ICRqMshr_prefetcher#(cRqNum, resultT) prefetcher;
// port for sendRsToP_cRq
interface ICRqMshr_sendRsToP_cRq#(cRqNum, wayT, tagT, reqT) sendRsToP_cRq;
@@ -192,7 +203,8 @@ module mkICRqMshrSafe#(
// EHR ports
// We put pipelineResp < transfer to cater for deq < enq of cache pipeline
Integer cRqTransfer_port = 2;
Integer cRqTransfer_port = 3;
Integer prefetcher_port = 2;
Integer sendRsToC_port = 1; // create a bypass behavior from pipelineResp to sendRsToC (to save a cycle)
Integer pipelineResp_port = 0;
Integer sendRqToP_port = 0; // sendRqToP is read only
@@ -200,15 +212,15 @@ module mkICRqMshrSafe#(
Integer flush_port = 0; // flush port is read only
// MSHR entry state
Vector#(cRqNum, Ehr#(3, ICRqState)) stateVec <- replicateM(mkEhr(Empty));
Vector#(cRqNum, Ehr#(4, ICRqState)) stateVec <- replicateM(mkEhr(Empty));
// cRq req contents
Vector#(cRqNum, Ehr#(3, reqT)) reqVec <- replicateM(mkEhr(?));
Vector#(cRqNum, Ehr#(4, reqT)) reqVec <- replicateM(mkEhr(?));
// cRq mshr slots
Vector#(cRqNum, Ehr#(3, slotT)) slotVec <- replicateM(mkEhr(defaultValue));
Vector#(cRqNum, Ehr#(4, slotT)) slotVec <- replicateM(mkEhr(defaultValue));
// result
Vector#(cRqNum, Ehr#(3, Maybe#(resultT))) resultVec <- replicateM(mkEhr(Invalid));
Vector#(cRqNum, Ehr#(4, Maybe#(resultT))) resultVec <- replicateM(mkEhr(Invalid));
// successor valid bit
Vector#(cRqNum, Ehr#(3, Bool)) succValidVec <- replicateM(mkEhr(False));
Vector#(cRqNum, Ehr#(4, Bool)) succValidVec <- replicateM(mkEhr(False));
// successor MSHR index
RegFile#(cRqIndexT, cRqIndexT) succFile <- mkRegFile(0, fromInteger(valueOf(cRqNum) - 1));
// empty entry FIFO
@@ -273,6 +285,20 @@ module mkICRqMshrSafe#(
endmethod
endinterface
interface ICRqMshr_prefetcher prefetcher;
method Action releaseEntry(cRqIndexT n) if(inited);
emptyEntryQ.enq(n);
stateVec[n][prefetcher_port] <= Empty;
`ifdef CHECK_DEADLOCK
checker.releaseEntry(n);
`endif
endmethod
method Maybe#(resultT) getResult(Bit#(TLog#(cRqNum)) n);
return resultVec[n][prefetcher_port];
endmethod
endinterface
interface ICRqMshr_sendRsToP_cRq sendRsToP_cRq;
method reqT getRq(cRqIndexT n);
return reqVec[n][sendRsToP_cRq_port];

View File

@@ -52,6 +52,7 @@ import Cntrs::*;
import ConfigReg::*;
import RandomReplace::*;
import Prefetcher::*;
import ProcTypes::*;
`ifdef PERFORMANCE_MONITORING
import PerformanceMonitor::*;
import StatCounters::*;
@@ -184,7 +185,8 @@ module mkLLBank#(
FShow#(dmaRqIdT),
Add#(tagSz, a__, AddrSz),
// make sure: cRqNum <= wayNum
Add#(cRqNum, b__, wayNum)
Add#(cRqNum, b__, wayNum),
Add#(TLog#(TDiv#(childNum,2)), c__, TLog#(childNum))
);
Bool verbose = True;
@@ -234,8 +236,9 @@ module mkLLBank#(
Count#(Bit#(32)) removedCRqs <- mkCount(0);
Vector#(cRqNum, Reg#(Bool)) cRqIsPrefetch <- replicateM(mkReg(?));
Prefetcher dataPrefetcher <- mkLLDPrefetcher;
Prefetcher instrPrefetcher <- mkLLIPrefetcher;
PrefetcherVector#(TDiv#(childNum, 2)) dataPrefetchers <- mkPrefetcherVector(mkLLDPrefetcher);
PrefetcherVector#(TDiv#(childNum, 2)) instrPrefetchers <- mkPrefetcherVector(mkLLIPrefetcher);
`ifdef PERF_COUNT
Reg#(Bool) doStats <- mkConfigReg(True);
Count#(Data) dmaMemLdCnt <- mkCount(0);
@@ -417,13 +420,16 @@ endfunction
// create new request from data prefetcher and send to pipeline
// Rule only fires when no work from child and DMA
rule createDataPrefetchRq(newCRqSrc == Invalid);
Addr addr <- dataPrefetcher.getNextPrefetchAddr;
let x <- dataPrefetchers.getNextPrefetchAddr;
match {.addr, .cacheIdx} = x;
//Request from L1D of cacheIdx-th core
childT child = {cacheIdx, '0};
cRqT cRq = LLRq {
addr: addr,
fromState: I,
toState: E,
canUpToE: True,
child: 0,
child: child,
byteEn: ?,
id: Child (?)
};
@@ -447,13 +453,16 @@ endfunction
// create new request from instruction prefetcher and send to pipeline
// Rule only fires when no work from child and DMA
rule createInstrPrefetchRq(newCRqSrc == Invalid);
Addr addr <- instrPrefetcher.getNextPrefetchAddr;
let x <- instrPrefetchers.getNextPrefetchAddr;
match {.addr, .cacheIdx} = x;
//Request from L1D of cacheIdx-th core
childT child = {cacheIdx, '1};
cRqT cRq = LLRq {
addr: addr,
fromState: I,
toState: S,
canUpToE: True,
child: 1,
child: child,
byteEn: ?,
id: Child (?)
};
@@ -1002,10 +1011,12 @@ endfunction
}, True); // hit, so update rep info
if (!cRqIsPrefetch[n]) begin
if (cRq.child[0] == 1) begin
instrPrefetcher.reportAccess(cRq.addr, HIT);
instrPrefetchers.reportAccess(
truncateLSB(cRq.child), cRq.addr, HIT);
end
else begin
dataPrefetcher.reportAccess(cRq.addr, HIT);
dataPrefetchers.reportAccess(
truncateLSB(cRq.child), cRq.addr, HIT);
end
end
endaction
@@ -1205,10 +1216,12 @@ endfunction
}, False);
if (!cRqIsPrefetch[n]) begin
if (cRq.child[0] == 1) begin
instrPrefetcher.reportAccess(cRq.addr, MISS);
instrPrefetchers.reportAccess(
truncateLSB(cRq.child), cRq.addr, MISS);
end
else begin
dataPrefetcher.reportAccess(cRq.addr, MISS);
dataPrefetchers.reportAccess(
truncateLSB(cRq.child), cRq.addr, MISS);
end
end
endaction
@@ -1281,10 +1294,12 @@ endfunction
end
if (!cRqIsPrefetch[n]) begin
if (cRq.child[0] == 1) begin
instrPrefetcher.reportAccess(cRq.addr, MISS);
instrPrefetchers.reportAccess(
truncateLSB(cRq.child), cRq.addr, MISS);
end
else begin
dataPrefetcher.reportAccess(cRq.addr, MISS);
dataPrefetchers.reportAccess(
truncateLSB(cRq.child), cRq.addr, MISS);
end
end
endaction

View File

@@ -1,4 +1,6 @@
import ISA_Decls :: *;
import CrossBar::*;
import GetPut::*;
import RWBramCore::*;
import FIFO::*;
import Fifos::*;
@@ -9,6 +11,7 @@ import CacheUtils::*;
import CCTypes::*;
import Types::*;
import Vector::*;
import BuildVector::*;
import ProcTypes::*;
typedef enum {
@@ -446,8 +449,8 @@ module mkTargetTableBRAM(TargetTableBRAM#(narrowTableSize, wideTableSize)) provi
Add#(c__, TLog#(wideTableSize), 32),
Add#(d__, TLog#(wideTableSize), 58)
);
RWBramCore#(Bit#(narrowTableIdxBits), Maybe#(narrowTargetEntryT)) narrowTable <- mkRWBramCoreForwarded;
RWBramCore#(Bit#(wideTableIdxBits), Maybe#(wideTargetEntryT)) wideTable <- mkRWBramCoreForwarded;
RWBramCore#(Bit#(narrowTableIdxBits), Maybe#(narrowTargetEntryT)) narrowTable <- mkRWBramCore;
RWBramCore#(Bit#(wideTableIdxBits), Maybe#(wideTargetEntryT)) wideTable <- mkRWBramCore;
Reg#(LineAddr) readReqLineAddr <- mkReg(?);
method Action writeReq(LineAddr prevAddr, LineAddr currAddr);
@@ -472,9 +475,10 @@ module mkTargetTableBRAM(TargetTableBRAM#(narrowTableSize, wideTableSize)) provi
endmethod
method Action readReq(LineAddr addr);
Bit#(narrowTableIdxBits) narrowIdx = truncate(addr);
Bit#(32) addrHash = hash(addr);
Bit#(narrowTableIdxBits) narrowIdx = truncate(addrHash);
narrowTable.rdReq(narrowIdx);
Bit#(wideTableIdxBits) wideIdx = truncate(addr);
Bit#(wideTableIdxBits) wideIdx = truncate(addrHash);
wideTable.rdReq(wideIdx);
readReqLineAddr <= addr;
endmethod
@@ -485,20 +489,21 @@ module mkTargetTableBRAM(TargetTableBRAM#(narrowTableSize, wideTableSize)) provi
narrowTable.deqRdResp;
wideTable.deqRdResp;
let addr = readReqLineAddr;
Bit#(narrowTableIdxBits) narrowIdx = truncate(addr);
Bit#(wideTableIdxBits) wideIdx = truncate(addr);
Bit#(32) addrHash = hash(addr);
Bit#(narrowTableIdxBits) narrowIdx = truncate(addrHash);
Bit#(wideTableIdxBits) wideIdx = truncate(addrHash);
if (narrowTable.rdResp matches tagged Valid .entry
&&& entry.tag == addr[23:valueOf(narrowTableIdxBits)]) begin
&&& entry.tag == addrHash[23:valueOf(narrowTableIdxBits)]) begin
if (clearEntry) begin
narrowTable.wrReq(narrowIdx, Invalid);
//narrowTable.wrReq(narrowIdx, Invalid);
end
$display("%t found narrow table entry %h", $time, addr + signExtend(pack(entry.distance)));
return Valid(addr + signExtend(pack(entry.distance)));
end
else if (wideTable.rdResp matches tagged Valid .entry
&&& entry.tag == addr[23:valueOf(wideTableIdxBits)]) begin
&&& entry.tag == addrHash[23:valueOf(wideTableIdxBits)]) begin
if (clearEntry) begin
wideTable.wrReq(wideIdx, Invalid);
//wideTable.wrReq(wideIdx, Invalid);
end
$display("%t found wide table entry %h", $time, entry.target);
return Valid(entry.target);
@@ -510,31 +515,253 @@ module mkTargetTableBRAM(TargetTableBRAM#(narrowTableSize, wideTableSize)) provi
endmethod
endmodule
interface TargetTableDouble#(numeric type narrowTableSize, numeric type wideTableSize);
method Action sendReadWriteReq(LineAddr addr, HitOrMiss hitMiss);
method ActionValue#(Tuple2#(Maybe#(LineAddr), Maybe#(LineAddr))) readResp();
endinterface
module mkTargetTableDouble(TargetTableDouble#(narrowTableSize, wideTableSize)) provisos
(
NumAlias#(narrowTableIdxBits, TLog#(narrowTableSize)),
NumAlias#(wideTableIdxBits, TLog#(wideTableSize)),
NumAlias#(narrowTableTagBits, TSub#(24, narrowTableIdxBits)),
NumAlias#(wideTableTagBits, TSub#(24, wideTableIdxBits)),
NumAlias#(narrowDistanceBits, 10),
NumAlias#(narrowMaxDistanceAbs, TExp#(TSub#(narrowDistanceBits, 1))),
Alias#(narrowTargetEntryT, NarrowTargetEntry#(narrowTableTagBits, narrowDistanceBits)),
Alias#(wideTargetEntryT, WideTargetEntry#(wideTableTagBits)),
Add#(a__, TLog#(narrowTableSize), 32),
Add#(b__, TLog#(narrowTableSize), 58),
Add#(c__, TLog#(wideTableSize), 32),
Add#(d__, TLog#(wideTableSize), 58)
);
//on any request, read all 4 tables. get prefetches. if it's a miss save both MRU entries.
//on a miss, perform a regular table write to the MRU table. if it's a narrow write, write the old MRU narrow entry to the LRU narrow table.
//one method, readReq, with parameter isMiss. sends read requests to all 4 tables.
//also saves read address
//one method setMRU.
// sends a write request with the previous miss address to the current miss address.
// if narrow table write, then also write the old MRU narrow entry to the LRU narrow table.
//one method, getPrefetches, which also saves all results if isMiss true.
RWBramCore#(Bit#(narrowTableIdxBits), Maybe#(narrowTargetEntryT)) narrowTableMRU <- mkRWBramCoreForwarded;
RWBramCore#(Bit#(wideTableIdxBits), Maybe#(wideTargetEntryT)) wideTableMRU <- mkRWBramCoreForwarded;
RWBramCore#(Bit#(narrowTableIdxBits), Maybe#(narrowTargetEntryT)) narrowTableLRU <- mkRWBramCoreForwarded;
RWBramCore#(Bit#(wideTableIdxBits), Maybe#(wideTargetEntryT)) wideTableLRU <- mkRWBramCoreForwarded;
Reg#(LineAddr) readReqLineAddr <- mkReg(0);
Reg#(HitOrMiss) readReqHitMiss <- mkReg(HIT);
Reg#(LineAddr) lastMissAddr <- mkReg(0);
Reg#(Maybe#(wideTargetEntryT)) lastMissWideMRUEntry <- mkReg(unpack(0));
Reg#(Maybe#(narrowTargetEntryT)) lastMissNarrowMRUEntry <- mkReg(unpack(0));
Reg#(Maybe#(wideTargetEntryT)) lastMissWideLRUEntry <- mkReg(unpack(0));
Reg#(Maybe#(narrowTargetEntryT)) lastMissNarrowLRUEntry <- mkReg(unpack(0));
function Bool narrowTagMatch(Bit#(32) addrHash, narrowTargetEntryT narrow);
return narrow.tag == addrHash[23:valueOf(narrowTableIdxBits)];
endfunction
function Bool narrowTagMatchMaybe(Bit#(32) addrHash, Maybe#(narrowTargetEntryT) narrowMaybe);
if (narrowMaybe matches tagged Valid .narrow &&& narrowTagMatch(addrHash, narrow))
return True;
else
return False;
endfunction
function Bool wideTagMatch(Bit#(32) addrHash, wideTargetEntryT wide);
return wide.tag == addrHash[23:valueOf(wideTableIdxBits)];
endfunction
function Bool wideTagMatchMaybe(Bit#(32) addrHash, Maybe#(wideTargetEntryT) wideMaybe);
if (wideMaybe matches tagged Valid .wide &&& wideTagMatch(addrHash, wide))
return True;
else
return False;
endfunction
function ActionValue#(Maybe#(LineAddr))
checkReadResp(LineAddr addr, Bit#(32) addrHash, Maybe#(narrowTargetEntryT) narrowWrapped, Maybe#(wideTargetEntryT) wideWrapped);
actionvalue
if (narrowWrapped matches tagged Valid .narrow
&&& narrowTagMatch(addrHash, narrow)) begin
//$display("%t found narrow table entry %h", $time, addr + signExtend(pack(narrow.distance)));
return Valid(addr + signExtend(pack(narrow.distance)));
end
else if (wideWrapped matches tagged Valid .wide
&&& wideTagMatch(addrHash, wide)) begin
//$display("%t found wide table entry %h", $time, wide.target);
return Valid(wide.target);
end
else
return Invalid;
endactionvalue
endfunction
function Action updateTables(
Bit#(32) lastMissAddrHash,
Bit#(idxBits) idx,
RWBramCore#(Bit#(idxBits), Maybe#(otherEntryT)) otherMRU,
RWBramCore#(Bit#(idxBits), Maybe#(otherEntryT)) otherLRU,
function Bool otherTagMatch(Bit#(32) addrHash, Maybe#(otherEntryT) entry),
function Bool myTagMatch(Bit#(32) addrHash, Maybe#(myEntryT) entry),
Maybe#(otherEntryT) otherMRUEntry,
Maybe#(otherEntryT) otherLRUEntry,
Maybe#(myEntryT) myMRUEntry
);
action
//Am inserting a new table entry into "my" table.
//So need to re-order the entries in the "other" table.
//To maintain the property that can't have both a narrow and wide entry in the same recency table.
if (otherTagMatch(lastMissAddrHash, otherMRUEntry)) begin
//If MRU other entry matches
if (otherTagMatch(lastMissAddrHash, otherLRUEntry)) begin
//If LRU other entry matches
// Shift other down
otherMRU.wrReq(idx, Invalid);
otherLRU.wrReq(idx, otherMRUEntry);
end
else begin
//If LRU other entry doesnt match
// Switch other entries around
otherMRU.wrReq(idx, otherLRUEntry);
otherLRU.wrReq(idx, otherMRUEntry);
end
end
else begin
//If other MRU entry doesn't match
if (otherTagMatch(lastMissAddrHash, otherLRUEntry) &&
myTagMatch(lastMissAddrHash, myMRUEntry)) begin
//will shift my MRU entry down, so
// invalidate other LRU entry
otherLRU.wrReq(idx, Invalid);
end
end
endaction
endfunction
function Action writeMissEntry(LineAddr currAddr);
action
let distance = currAddr - lastMissAddr;
Bit#(32) lastMissAddrHash = hash(lastMissAddr);
$display("%t Recording miss from %x to %x", $time, lastMissAddr, currAddr);
if (abs(distance) < fromInteger(valueOf(narrowMaxDistanceAbs))) begin
//Store lastMissAddr -> currAddr in narrow MRU table
Bit#(narrowTableIdxBits) idx = truncate(lastMissAddrHash);
narrowTargetEntryT entry;
entry.tag = lastMissAddrHash[23:valueOf(narrowTableIdxBits)];
entry.distance = truncate(distance);
if (Valid(entry) != lastMissNarrowMRUEntry) begin
//$display("%t Recording miss -- modifying narrow table", $time);
//Maintain the property that one address can only have
// at most 2 of 4 table entries for it.
//Shift narrow table entries down, storing in MRU.
//But only if the entry was not already the MRU entry.
narrowTableMRU.wrReq(idx, Valid(entry));
narrowTableLRU.wrReq(idx, lastMissNarrowMRUEntry);
Bit#(wideTableIdxBits) wideIdx = truncate(lastMissAddrHash);
updateTables(lastMissAddrHash, wideIdx, wideTableMRU, wideTableLRU, wideTagMatchMaybe, narrowTagMatchMaybe,
lastMissWideMRUEntry, lastMissWideLRUEntry, lastMissNarrowMRUEntry);
end
end
else begin
//Store lastMissAddr -> currAddr in wide MRU table
wideTargetEntryT entry;
Bit#(wideTableIdxBits) idx = truncate(lastMissAddrHash);
entry.tag = lastMissAddrHash[23:valueOf(wideTableIdxBits)];
entry.target = currAddr;
if (Valid(entry) != lastMissWideMRUEntry) begin
//$display("%t Recording miss -- modifying wide table", $time);
wideTableMRU.wrReq(idx, Valid(entry));
wideTableLRU.wrReq(idx, lastMissWideMRUEntry);
Bit#(narrowTableIdxBits) narrowIdx = truncate(lastMissAddrHash);
updateTables(lastMissAddrHash, narrowIdx, narrowTableMRU, narrowTableLRU, narrowTagMatchMaybe, wideTagMatchMaybe,
lastMissNarrowMRUEntry, lastMissNarrowLRUEntry, lastMissWideMRUEntry);
end
end
endaction
endfunction
method Action sendReadWriteReq(LineAddr addr, HitOrMiss hitMiss);
$display("%t send read write req for %x", $time, addr);
Bit#(32) addrHash = hash(addr);
Bit#(narrowTableIdxBits) narrowIdx = truncate(addrHash);
narrowTableMRU.rdReq(narrowIdx);
narrowTableLRU.rdReq(narrowIdx);
Bit#(wideTableIdxBits) wideIdx = truncate(addrHash);
wideTableMRU.rdReq(wideIdx);
wideTableLRU.rdReq(wideIdx);
readReqLineAddr <= addr;
readReqHitMiss <= hitMiss;
endmethod
method ActionValue#(Tuple2#(Maybe#(LineAddr), Maybe#(LineAddr))) readResp();
// Returns the read response and if a table had a hit,
// sends a write request to clear the entry in that table
narrowTableMRU.deqRdResp;
narrowTableLRU.deqRdResp;
wideTableMRU.deqRdResp;
wideTableLRU.deqRdResp;
let addr = readReqLineAddr;
Bit#(32) addrHash = hash(addr);
if (readReqHitMiss == MISS) begin
//Update the entries for the last miss to point to this one
writeMissEntry(addr);
//Save the raw table entries
//$display("idx: %x", addrHash);
//$display("%t Read resp: nMRU: ", fshow(narrowTableMRU.rdResp), "wMRU: ", fshow(wideTableMRU.rdResp));
//$display("%t Read resp: nLRU: ", fshow(narrowTableLRU.rdResp), "wLRU: ", fshow(wideTableLRU.rdResp));
lastMissWideMRUEntry <= wideTableMRU.rdResp;
lastMissNarrowMRUEntry <= narrowTableMRU.rdResp;
lastMissWideLRUEntry <= wideTableLRU.rdResp;
lastMissNarrowLRUEntry <= narrowTableLRU.rdResp;
lastMissAddr <= addr; // save for future use
end
let entryMRU <- checkReadResp(addr, addrHash, narrowTableMRU.rdResp, wideTableMRU.rdResp);
let entryLRU <- checkReadResp(addr, addrHash, narrowTableLRU.rdResp, wideTableLRU.rdResp);
Tuple2#(Maybe#(LineAddr), Maybe#(LineAddr)) retval = tuple2(entryMRU, entryLRU);
$display("%t read resp for %x returning ", $time, addr, fshow(retval));
return retval;
endmethod
endmodule
module mkBRAMSingleWindowTargetPrefetcher(Prefetcher) provisos
();
Integer cacheLinesInRange = 2;
(
NumAlias#(numLastRequests, 16)
);
Integer cacheLinesInRange = 1;
Reg#(LineAddr) rangeEnd <- mkReg(0); //Points to one CLine after end of range
Reg#(LineAddr) nextToAsk <- mkReg(0);
Reg#(LineAddr) lastChildRequest <- mkReg(0);
TargetTableBRAM#(64, 8) targetTable <- mkTargetTableBRAM;
TargetTableBRAM#(1024, 128) targetTable <- mkTargetTableBRAM;
FIFOF#(LineAddr) targetTableReadResp <- mkBypassFIFOF;
Reg#(Vector#(numLastRequests, Bit#(32))) lastTargetRequests <- mkReg(replicate(0));
rule sendReadReq;
let lastAsked = nextToAsk-1;
targetTable.readReq(lastAsked);
if (!elem(hash(lastChildRequest), lastTargetRequests)) begin
targetTable.readReq(lastChildRequest);
$display("%t Prefetcher sending target read request for %h", $time, lastChildRequest);
lastTargetRequests <= shiftInAt0(lastTargetRequests, hash(lastChildRequest));
end
endrule
rule getReadResp;
let res <- targetTable.readResp(True);
let res <- targetTable.readResp(False);
if (res matches tagged Valid .cline) begin
//Reset table entry, so on further calls we prefetch the next successive clines
//If we actually take the jump, the table entry will be restored
targetTableReadResp.enq(cline);
end
endrule
method Action reportAccess(Addr addr, HitOrMiss hitMiss);
let cl = getLineAddr(addr);
$display("%t prefecher reportAccess", $time);
if (hitMiss == HIT &&
rangeEnd - fromInteger(cacheLinesInRange) - 1 < cl &&
cl < rangeEnd) begin
@@ -550,7 +777,8 @@ module mkBRAMSingleWindowTargetPrefetcher(Prefetcher) provisos
rangeEnd <= cl + fromInteger(cacheLinesInRange) + 1;
end
if (cl != lastChildRequest + 1 && cl != lastChildRequest && cl != lastChildRequest - 1) begin
if (hitMiss == MISS && cl != lastChildRequest + 1 && cl != lastChildRequest && cl != lastChildRequest - 1) begin
//Try only recording table entries on a miss!
$display("%t Prefetcher add target entry from addr %h to addr %h", $time, Addr'{lastChildRequest, '0}, addr);
targetTable.writeReq(lastChildRequest, cl);
end
@@ -579,6 +807,7 @@ endmodule
module mkBRAMMultiWindowTargetPrefetcher(Prefetcher)
provisos(
NumAlias#(numWindows, 4),
NumAlias#(numLastRequests, 16),
Alias#(windowIdxT, Bit#(TLog#(numWindows)))
);
Integer cacheLinesInRange = 2;
@@ -587,19 +816,21 @@ provisos(
Vector#(numWindows, Reg#(windowIdxT)) shiftReg <- genWithM(compose(mkReg, fromInteger));
Reg#(LineAddr) lastChildRequest <- mkReg(0);
TargetTableBRAM#(64, 8) targetTable <- mkTargetTableBRAM;
TargetTableBRAM#(8192, 2048) targetTable <- mkTargetTableBRAM;
FIFOF#(LineAddr) targetTableReadResp <- mkBypassFIFOF;
Reg#(Vector#(numLastRequests, Bit#(32))) lastTargetRequests <- mkReg(replicate(0));
rule sendReadReq;
let lastAsked = streams[shiftReg[0]].nextToAsk-1;
targetTable.readReq(lastAsked);
if (!elem(hash(lastChildRequest), lastTargetRequests)) begin
targetTable.readReq(lastChildRequest);
$display("%t Prefetcher sending target read request for %h", $time, Addr'{lastChildRequest, 'h0});
lastTargetRequests <= shiftInAt0(lastTargetRequests, hash(lastChildRequest));
end
endrule
rule getReadResp;
let res <- targetTable.readResp(True);
let res <- targetTable.readResp(False);
if (res matches tagged Valid .cline) begin
//Reset table entry, so on further calls we prefetch the next successive clines
//If we actually take the jump, the table entry will be restored
targetTableReadResp.enq(cline);
end
endrule
@@ -679,7 +910,7 @@ provisos(
end
// Update target prefetcher
if (cl != lastChildRequest + 1 && cl != lastChildRequest && cl != lastChildRequest - 1) begin
if (hitMiss == MISS && cl != lastChildRequest + 1 && cl != lastChildRequest && cl != lastChildRequest - 1) begin
$display("%t Prefetcher add target entry from addr %h to addr %h", $time, Addr'{lastChildRequest, '0}, addr);
targetTable.writeReq(lastChildRequest, cl);
end
@@ -839,6 +1070,62 @@ module mkBRAMMarkovOnHitPrefetcher(Prefetcher) provisos
endmodule
module mkMarkovOnHit2Prefetcher(Prefetcher) provisos
(
NumAlias#(maxChainLength, 1),
NumAlias#(numLastRequests, 32),
Alias#(chainLengthT, Bit#(TLog#(TAdd#(maxChainLength,1))))
);
Reg#(LineAddr) lastChildRequest <- mkReg(0);
Reg#(Vector#(numLastRequests, Bit#(32))) lastAddrRequests <- mkReg(replicate(0));
TargetTableDouble#(2048, 256) targetTable <- mkTargetTableDouble;
Fifo#(8, LineAddr) highPriorityPrefetches <- mkOverflowBypassFifo;
Fifo#(8, LineAddr) lowPriorityPrefetches <- mkOverflowBypassFifo;
//on reportAccess, read the current address in both tables, and save it
// Next cycle, add any found next lines to prefetch queues. Have 2 prefetch queues, High and low priority.
// If this was a miss, save as lastMissEntry
// And issue a write of table[lastMissEntry] = thisMiss.
// but checking for LRU and everything.
rule addPrefetchesToQueues;
match { .highPrio, .lowPrio } <- targetTable.readResp();
if (highPrio matches tagged Valid .cl)
highPriorityPrefetches.enq(cl);
if (lowPrio matches tagged Valid .cl)
lowPriorityPrefetches.enq(cl);
endrule
method ActionValue#(Addr) getNextPrefetchAddr
if (highPriorityPrefetches.notEmpty || lowPriorityPrefetches.notEmpty);
//if (false);
Addr retAddr = unpack(0);
if (highPriorityPrefetches.notEmpty) begin
retAddr = {highPriorityPrefetches.first, '0};
highPriorityPrefetches.deq;
end
else if (lowPriorityPrefetches.notEmpty) begin
retAddr = {lowPriorityPrefetches.first, '0};
lowPriorityPrefetches.deq;
end
$display("%t Prefetcher getNextPrefetchAddr requesting chain entry %h", $time, retAddr);
return retAddr;
endmethod
method Action reportAccess(Addr addr, HitOrMiss hitMiss);
let cl = getLineAddr(addr);
if (hitMiss == MISS)
$display("%t Prefetcher report MISS %h", $time, addr);
if (hitMiss == MISS || !elem(hash(cl), lastAddrRequests)) begin
//Don't start a markov chain if we started a markov chain with that address recently
$display("%t Prefetcher start new chain with %h", $time, addr);
targetTable.sendReadWriteReq(cl, hitMiss);
lastAddrRequests <= shiftInAt0(lastAddrRequests, hash(cl));
end
endmethod
endmodule
module mkBlockPrefetcher(Prefetcher) provisos (
NumAlias#(numLinesEachWay, 1),
Alias#(lineCountT, Bit#(TLog#(TAdd#(numLinesEachWay, 1))))
@@ -1065,13 +1352,13 @@ provisos(
endmodule
typedef enum {
EMPTY = 3'd0, INIT = 3'd1, TRANSIENT = 3'd2, STEADY = 3'd3, NO_PRED = 3'd4
INIT = 2'd0, TRANSIENT = 2'd1, STEADY = 2'd2, NO_PRED = 2'd3
} StrideState2 deriving (Bits, Eq, FShow);
typedef struct {
Bit#(12) lastAddr;
Bit#(13) stride;
Bit#(4) cLinesPrefetched; //Stores how many cache lines have been prefetched for this instruction
Int#(13) stride;
Bit#(2) cLinesPrefetched; //Stores how many cache lines have been prefetched for this instruction
StrideState2 state;
} StrideEntry2 deriving (Bits, Eq, FShow);
@@ -1087,7 +1374,7 @@ provisos(
Fifo#(8, Addr) addrToPrefetch <- mkOverflowPipelineFifo;
FIFO#(Tuple3#(StrideEntry2, Addr, Bit#(16))) strideEntryForPrefetch <- mkBypassFIFO();
Reg#(Maybe#(Bit#(4))) cLinesPrefetchedLatest <- mkReg(?);
Reg#(Maybe#(Bit#(2))) cLinesPrefetchedLatest <- mkReg(?);
PulseWire holdReadReq <- mkPulseWire;
rule sendReadReq if (!holdReadReq);
@@ -1111,21 +1398,11 @@ provisos(
StrideEntry2 se = strideTable.rdResp;
strideTable.deqRdResp;
StrideEntry2 seNext = se;
Bit#(13) observedStride = {1'b0, addr[11:0]} - {1'b0, se.lastAddr};
Int#(13) observedStride = unpack({1'b0, addr[11:0]} - {1'b0, se.lastAddr});
$writeh("%t Stride Prefetcher updateStrideEntry ", $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
if (se.state == INIT && observedStride != 0) begin
if (se.stride == observedStride) begin
//fast track to steady
seNext.state = STEADY;
@@ -1190,29 +1467,21 @@ provisos(
rule createPrefetchRequests;
match {.se, .addr, .pcHash} = strideEntryForPrefetch.first;
//If this rule is looping, then we'll have a valid cLinesPrefetchedLatest
Bit#(4) cLinesPrefetched = fromMaybe(se.cLinesPrefetched, cLinesPrefetchedLatest);
Bit#(2) cLinesPrefetched = fromMaybe(se.cLinesPrefetched, cLinesPrefetchedLatest);
if (se.state == STEADY &&
cLinesPrefetched !=
fromInteger(valueof(cLinesAheadToPrefetch))) begin
//can prefetch
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 begin
strideToUse = se.stride;
Int#(13) cLineSize = fromInteger(valueof(DataSz));
Int#(13) strideToUse = se.stride;
if (abs(strideToUse) < cLineSize) begin
strideToUse = (strideToUse < 0) ? -cLineSize : cLineSize;
end
let reqAddr = addr +
(signExtend(strideToUse) * zeroExtend(cLinesPrefetched + 1));
Bit#(13) jumpDist = pack(strideToUse) * zeroExtend(cLinesPrefetched+1);
let reqAddr = addr + signExtend(jumpDist);
addrToPrefetch.enq(reqAddr);
// We will still be processing this StrideEntry next cycle,
@@ -1242,6 +1511,78 @@ provisos(
endmodule
typedef struct {
Addr lastAddr;
Int#(13) stride;
Bit#(2) confidence;
} SimpleStrideEntry deriving (Bits, Eq, FShow);
//10 minutes of planning
//25 minutes of implementation
//30 minutes of writing tests and fixing bugs
module mkSimpleStridePCPrefetcher(PCPrefetcher)
provisos(
NumAlias#(strideTableSize, 512),
NumAlias#(cLinesAheadToPrefetch, 2),
NumAlias#(minConfidenceToPrefetch, 2),
Alias#(strideTableIndexT, Bit#(TLog#(strideTableSize)))
);
Vector#(strideTableSize, Reg#(SimpleStrideEntry)) strideTable <- replicateM(mkReg(unpack(0)));
Reg#(Addr) addrToPrefetch <- mkReg(0);
Reg#(Int#(13)) strideToPrefetch <- mkReg(0);
Ehr#(2, Bit#(3)) prefetchesIssued <- mkEhr(fromInteger(valueOf(cLinesAheadToPrefetch)));
method Action reportAccess(Addr addr, Bit#(16) pcHash, HitOrMiss hitMiss);
$display("%t report access %x %x", $time, addr, pcHash);
strideTableIndexT idx = truncate(pcHash);
SimpleStrideEntry entry = strideTable[idx];
Int#(13) calc_stride = unpack(truncate(addr - entry.lastAddr));
$display("found stride %x", entry.stride);
entry.lastAddr = addr;
if (calc_stride == entry.stride) begin
if (entry.confidence != 2'd3) begin
entry.confidence = entry.confidence + 1;
end
end
else begin
if (entry.confidence > 0) begin
entry.confidence = entry.confidence - 1;
end
if (entry.confidence < fromInteger(valueOf(minConfidenceToPrefetch))) begin
entry.stride = calc_stride;
entry.confidence = 0;
end
end
if (entry.confidence >= fromInteger(valueOf(minConfidenceToPrefetch))) begin
prefetchesIssued[1] <= 0;
addrToPrefetch <= addr;
strideToPrefetch <= entry.stride;
end
strideTable[idx] <= entry;
endmethod
method ActionValue#(Addr) getNextPrefetchAddr
if (prefetchesIssued[0] < fromInteger(valueOf(cLinesAheadToPrefetch)));
Int#(13) strideToUse = strideToPrefetch;
Int#(13) cLineSize = fromInteger(valueof(DataSz));
if (abs(strideToPrefetch) < cLineSize) begin
strideToUse = (strideToPrefetch < 0) ? -cLineSize : cLineSize;
end
prefetchesIssued[0] <= prefetchesIssued[0] + 1;
let reqAddr = addrToPrefetch +
(pack(signExtend(strideToUse)) * zeroExtend(prefetchesIssued[0] + 1));
check(reqAddr[63:12] == addrToPrefetch[63:12]);
$display("%t getprefetchaddr ret %x", $time, reqAddr);
return reqAddr;
endmethod
endmodule
typedef enum {
EMPTY = 3'd0, INIT = 3'd1, TRANSIENT = 3'd2, STEADY1 = 3'd3,
STEADY2 = 3'd4, STEADY3 = 3'd5, STEADY4 = 4'd6, STEADYLAST = 3'd7
@@ -1453,6 +1794,40 @@ provisos(
endmodule
interface PrefetcherVector#(numeric type size);
method ActionValue#(Tuple2#(Addr, Bit#(TLog#(size)))) getNextPrefetchAddr;
method Action reportAccess(Bit#(TLog#(size)) idx, Addr addr, HitOrMiss hitMiss);
endinterface
module mkPrefetcherVector#(module#(Prefetcher) mkPrefetcher)
(
PrefetcherVector#(size)
) provisos (
Alias#(idxT, Bit#(TLog#(size)))
);
Vector#(size, Prefetcher) prefetchers <- replicateM(mkPrefetcher);
Fifo#(1, Tuple2#(Addr, idxT)) prefetchRq <- mkBypassFifo;
function XBarDstInfo#(Bit#(0),Tuple2#(Addr, idxT)) convertPrefetchRq(idxT item, Addr a);
return XBarDstInfo {
idx: 0,
data: tuple2(a, item)
};
endfunction
function Get#(Addr) reqGet(Prefetcher p) = toGet(p.getNextPrefetchAddr);
mkXBar(convertPrefetchRq, map(reqGet, prefetchers), vec(toPut(prefetchRq)));
method ActionValue#(Tuple2#(Addr, idxT)) getNextPrefetchAddr;
prefetchRq.deq;
return prefetchRq.first;
endmethod
method Action reportAccess(idxT idx, Addr addr, HitOrMiss hitMiss);
prefetchers[idx].reportAccess(addr, hitMiss);
endmethod
endmodule
module mkL1IPrefetcher(Prefetcher);
`ifdef INSTR_PREFETCHER_IN_L1
`ifdef INSTR_PREFETCHER_NEXT_LINE_ON_ALL
@@ -1535,6 +1910,8 @@ module mkL1DPrefetcher(PCPrefetcher);
let m <- mkPCPrefetcherAdapter(mkBRAMMarkovPrefetcher);
`elsif DATA_PREFETCHER_MARKOV_ON_HIT
let m <- mkPCPrefetcherAdapter(mkBRAMMarkovOnHitPrefetcher);
`elsif DATA_PREFETCHER_MARKOV_ON_HIT_2
let m <- mkPCPrefetcherAdapter(mkMarkovOnHit2Prefetcher);
`endif
//let m <- mkPCPrefetcherAdapter(mkAlwaysRequestPrefetcher);
`else
@@ -1555,6 +1932,8 @@ module mkLLDPrefetcherInL1D(PCPrefetcher);
let m <- mkPCPrefetcherAdapter(mkBRAMMarkovPrefetcher);
`elsif DATA_PREFETCHER_MARKOV_ON_HIT
let m <- mkPCPrefetcherAdapter(mkBRAMMarkovOnHitPrefetcher);
`elsif DATA_PREFETCHER_MARKOV_ON_HIT_2
let m <- mkPCPrefetcherAdapter(mkMarkovOnHit2Prefetcher);
`endif
//let m <- mkPCPrefetcherAdapter(mkAlwaysRequestPrefetcher);
`else
@@ -1575,6 +1954,8 @@ module mkLLDPrefetcher(Prefetcher);
let m <- mkBRAMMarkovPrefetcher;
`elsif DATA_PREFETCHER_MARKOV_ON_HIT
let m <- mkBRAMMarkovOnHitPrefetcher;
`elsif DATA_PREFETCHER_MARKOV_ON_HIT_2
let m <- mkMarkovOnHit2Prefetcher;
`endif
//let m <- mkPCPrefetcherAdapter(mkAlwaysRequestPrefetcher);
`else

View File

@@ -1,4 +1,5 @@
import Prefetcher::*;
import RWBramCore::*;
import StmtFSM::*;
import Types::*;
import Fifos::*;
@@ -99,6 +100,182 @@ module mkTargetTableBRAMTest(Empty);
);
endmodule
module mkTargetTableDoubleTest(Empty);
TargetTableDouble#(2048, 128) t <- mkTargetTableDouble;
mkAutoFSM(
seq
// ----- Send misses and stuff to one window -----
action
t.sendReadWriteReq('h8000, MISS); // goes in short table
endaction
action let x <- t.readResp(); endaction
action
t.sendReadWriteReq('h800a, MISS); // goes in short table
endaction
action let x <- t.readResp(); endaction
action
t.sendReadWriteReq('h8080000b, MISS); // goes in long table
endaction
action let x <- t.readResp(); endaction
action
t.sendReadWriteReq('h8000, MISS); // comes from short table
endaction
action
let x <- t.readResp();
doAssert(x == tuple2(Valid('h800a), Invalid), "test fail!");
endaction
action
t.sendReadWriteReq('h800a, MISS); // comes from long table
endaction
action
let x <- t.readResp();
doAssert(x == tuple2(Valid('h8080000b), Invalid), "test fail!");
endaction
action
t.sendReadWriteReq('h8000, MISS);
endaction
action let x <- t.readResp(); endaction
action
t.sendReadWriteReq('h2123000c, MISS);
endaction
action let x <- t.readResp(); endaction
action
t.sendReadWriteReq('h8000, HIT);
endaction
action
let x <- t.readResp();
doAssert(x == tuple2(Valid('h2123000c), Valid('h800a)), "test fail!");
endaction
action
t.sendReadWriteReq('h8000, MISS);
endaction
action let x <- t.readResp(); endaction
action
t.sendReadWriteReq('h2123000c, MISS);
endaction
action let x <- t.readResp(); endaction
action
t.sendReadWriteReq('h8000, MISS);
endaction
action
let x <- t.readResp();
doAssert(x == tuple2(Valid('h2123000c), Valid('h800a)), "test fail!");
endaction
/// ---- Add third entry (narrow) 8003
action
t.sendReadWriteReq('h8003, MISS);
endaction
action let x <- t.readResp(); endaction
action
t.sendReadWriteReq('h8000, MISS);
endaction
action
//wide entry is moved to LRU
let x <- t.readResp();
doAssert(x == tuple2(Valid('h8003), Valid('h2123000c)), "test fail!");
endaction
action
t.sendReadWriteReq('h8003, MISS);
endaction
action let x <- t.readResp(); endaction
action
t.sendReadWriteReq('h8000, MISS);
endaction
action
let x <- t.readResp();
doAssert(x == tuple2(Valid('h8003), Valid('h2123000c)), "test fail!");
endaction
//refresh 21230000
action
t.sendReadWriteReq('h2123000c, MISS);
endaction
action let x <- t.readResp(); endaction
action
t.sendReadWriteReq('h8000, MISS);
endaction
action
let x <- t.readResp();
doAssert(x == tuple2(Valid('h2123000c), Valid('h8003)), "test fail!");
endaction
/// ---- Add another entry (wide) 2123000d
action
t.sendReadWriteReq('h2123000d, MISS);
endaction
action let x <- t.readResp(); endaction
action
t.sendReadWriteReq('h8000, MISS);
endaction
action
//wide entry is moved to LRU
let x <- t.readResp();
doAssert(x == tuple2(Valid('h2123000d), Valid('h2123000c)), "test fail!");
endaction
/// ---- Add fifth entry (narrow) 8004
action
t.sendReadWriteReq('h8004, MISS);
endaction
action let x <- t.readResp(); endaction
action
t.sendReadWriteReq('h8000, MISS);
endaction
action
//wide entry is moved to LRU
let x <- t.readResp();
doAssert(x == tuple2(Valid('h8004), Valid('h2123000d)), "test fail!");
endaction
// --- Add a sixth narrow entry 8005
action
t.sendReadWriteReq('h8005, MISS);
endaction
action let x <- t.readResp(); endaction
action
t.sendReadWriteReq('h8000, MISS);
endaction
action
//wide entry is moved to LRU
let x <- t.readResp();
doAssert(x == tuple2(Valid('h8005), Valid('h8004)), "test fail!");
endaction
action
t.sendReadWriteReq('h7004, MISS); // get from short table
endaction
action
let x <- t.readResp();
doAssert(x == tuple2(Invalid, Invalid), "test fail!");
endaction
action
t.sendReadWriteReq('h6fde, MISS); // get from short table
endaction
action let x <- t.readResp(); endaction
action
t.sendReadWriteReq('h7004, MISS); // get from short table
endaction
action
let x <- t.readResp();
doAssert(x == tuple2(Valid('h6fde), Invalid), "test fail!");
endaction
action
t.sendReadWriteReq('h200, HIT); // get from short table
endaction
action
let x <- t.readResp();
doAssert(x == tuple2(Invalid, Invalid), "test fail!"); //entry was removed!
endaction
endseq
);
endmodule
module mkBRAMMultiWindowTargetPrefetcherTest(Empty);
let p <- mkBRAMMultiWindowTargetPrefetcher;
mkAutoFSM(
@@ -212,10 +389,6 @@ module mkBRAMMultiWindowTargetPrefetcherTest(Empty);
let x <- p.getNextPrefetchAddr; //target address recommended
doAssert(x == 'h50000000, "test fail!");
endaction
action
let x <- p.getNextPrefetchAddr; //target address recommended
doAssert(x == 'h81000000, "test fail!");
endaction
action
let x <- p.getNextPrefetchAddr;
doAssert(x == 'h80000200, "test fail!"); // window addresss recommended
@@ -225,6 +398,8 @@ module mkBRAMMultiWindowTargetPrefetcherTest(Empty);
endmodule
module mkBRAMSingleWindowTargetPrefetcherTest(Empty);
//2 ahead
//remember last 2 target table requests.
let p <- mkBRAMSingleWindowTargetPrefetcher;
mkAutoFSM(
seq
@@ -262,24 +437,21 @@ module mkBRAMSingleWindowTargetPrefetcherTest(Empty);
doAssert(x == 'h80000180, "test fail!");
endaction
action
p.reportAccess('h81000000, MISS); //Report miss somewhere far away
p.reportAccess('h81000200, MISS); //Report miss somewhere far away
endaction
action
let x <- p.getNextPrefetchAddr; //New window allocated and recommended
doAssert(x == 'h81000040, "test fail!");
doAssert(x == 'h81000240, "test fail!");
endaction
action
p.reportAccess('h80000180, MISS); //Report miss back home
endaction
action endaction
action
p.reportAccess('h82000000, MISS); //Report miss far away 2
endaction
action
p.reportAccess('h80000100, MISS); //Report miss back home
endaction
action
let x <- p.getNextPrefetchAddr;
doAssert(x == 'h80000140, "test fail!");
p.reportAccess('h80000140, MISS); //Report miss back home
endaction
action
let x <- p.getNextPrefetchAddr;
@@ -287,11 +459,17 @@ module mkBRAMSingleWindowTargetPrefetcherTest(Empty);
endaction
action
let x <- p.getNextPrefetchAddr; //target address recommended
doAssert(x == 'h81000000, "test fail!");
doAssert(x == 'h81000200, "test fail!");
endaction
action
let x <- p.getNextPrefetchAddr; //target address recommended
doAssert(x == 'h82000000, "test fail!");
p.reportAccess('h80000140, HIT); //Report miss back home
endaction
action
p.reportAccess('h81000200, HIT);
endaction
action
let x <- p.getNextPrefetchAddr; //target addresss recommended
doAssert(x == 'h800001c0, "test fail!");
endaction
endseq
);
@@ -372,6 +550,7 @@ module mkBRAMStridePCPrefetcherTest(Empty);
endmodule
module mkBRAMStrideAdaptivePCPrefetcherTest(Empty);
// config is 2 - 3 - 5
let p <- mkBRAMStrideAdaptivePCPrefetcher;
mkAutoFSM(
seq
@@ -474,6 +653,74 @@ module mkBRAMStrideAdaptivePCPrefetcherTest(Empty);
);
endmodule
module mkMarkovOnHit2PrefetcherTest(Empty);
//let p <- mkMultipleWindowPrefetcher;
//TODO pass in value of cachelinesinrange
let p <- mkMarkovOnHit2Prefetcher;
mkAutoFSM(
seq
// ----- Send misses and stuff to one window -----
action
p.reportAccess('h80010000, MISS);
endaction
action
p.reportAccess('h80010700, MISS);
endaction
action
p.reportAccess('h90010000, MISS);
endaction
action
p.reportAccess('ha0010300, MISS);
endaction
action
p.reportAccess('h80010000, MISS); //back to start
endaction
action
let x <- p.getNextPrefetchAddr;
doAssert(x == 'h80010700, "test fail!");
endaction
//Add second target
action
p.reportAccess('h80010900, MISS);
endaction
action
p.reportAccess('h80010000, MISS); //back to start
endaction
action
let x <- p.getNextPrefetchAddr;
doAssert(x == 'h80010900, "test fail!");
endaction
action
let x <- p.getNextPrefetchAddr;
doAssert(x == 'h80010700, "test fail!");
endaction
action
p.reportAccess('ha0010300, MISS);
endaction
action
let x <- p.getNextPrefetchAddr;
doAssert(x == 'h80010000, "test fail!");
endaction
action
p.reportAccess('ha0010200, MISS);
endaction
action
p.reportAccess('ha0010300, MISS);
endaction
action
let x <- p.getNextPrefetchAddr;
doAssert(x == 'ha0010200, "test fail!");
endaction
action
let x <- p.getNextPrefetchAddr;
doAssert(x == 'h80010000, "test fail!");
endaction
endseq
);
endmodule
module mkBRAMMarkovPrefetcherTest(Empty);
//let p <- mkMultipleWindowPrefetcher;
//TODO pass in value of cachelinesinrange
@@ -598,6 +845,77 @@ module mkOverflowPipelineFifoTest(Empty);
);
endmodule
module mkOverflowBypassFifoTest(Empty);
Fifo#(4, Bit#(8)) p <- mkOverflowBypassFifo;
mkAutoFSM(
seq
action
p.enq('h01);
endaction
action
p.enq('h02);
endaction
action
p.enq('h03);
endaction
action
p.enq('h04);
endaction
action
let x = p.first;
p.deq;
doAssert(x == 'h01, "test fail!");
endaction
action
p.enq('h05);
let x = p.first;
p.deq;
doAssert(x == 'h02, "test fail!");
endaction
action
p.enq('h06);
endaction
action
p.enq('h07);
let x = p.first;
p.deq;
$display("found %x", x);
doAssert(x == 'h04, "test fail!");
endaction
action
p.enq('h08);
endaction
action
p.enq('h09);
let x = p.first;
p.deq;
doAssert(x == 'h06, "test fail!");
endaction
action
let x = p.first;
p.deq;
doAssert(x == 'h07, "test fail!");
endaction
action
let x = p.first;
p.deq;
doAssert(x == 'h08, "test fail!");
endaction
action
let x = p.first;
p.deq;
doAssert(x == 'h09, "test fail!");
endaction
action
doAssert(!p.notEmpty, "test fail!");
endaction
action
$display("test done!");
endaction
endseq
);
endmodule
module mkStride2PCPrefetcherTest(Empty);
//paremeter - 2 ahead
let p <- mkStride2PCPrefetcher;
@@ -634,7 +952,11 @@ module mkStride2PCPrefetcherTest(Empty);
action p.reportAccess('h90000160, 'h006a, HIT); endaction
action
let x <- p.getNextPrefetchAddr;
doAssert(x == 'h90000120, "test fail!");
doAssert(x == 'h90000150, "test fail!");
endaction
action
let x <- p.getNextPrefetchAddr;
doAssert(x == 'h90000110, "test fail!");
endaction
action
let x <- p.getNextPrefetchAddr;
@@ -643,14 +965,13 @@ module mkStride2PCPrefetcherTest(Empty);
action p.reportAccess('h90000100, 'h006b, MISS); endaction
action p.reportAccess('h90000200, 'h006b, MISS); endaction
action p.reportAccess('h90000300, 'h006b, MISS); endaction
action p.reportAccess('h90000400, 'h006b, MISS); endaction
action
let x <- p.getNextPrefetchAddr;
doAssert(x == 'h90000500, "test fail!");
doAssert(x == 'h90000400, "test fail!");
endaction
action
let x <- p.getNextPrefetchAddr;
doAssert(x == 'h90000600, "test fail!");
doAssert(x == 'h90000500, "test fail!");
endaction
action p.reportAccess('ha0000420, 'h006b, MISS); endaction
action p.reportAccess('ha0000520, 'h006b, MISS); endaction
@@ -671,4 +992,94 @@ module mkStride2PCPrefetcherTest(Empty);
endaction
endseq
);
endmodule
module mkPrefetcherVectorTest(Empty);
//config - 2 lines
PrefetcherVector#(3) p <- mkPrefetcherVector(mkNextLineOnMissPrefetcher);
mkAutoFSM(
seq
action p.reportAccess(1, 'h90000000, MISS); endaction
action p.reportAccess(0, 'h80000000, MISS); endaction
action
let x <- p.getNextPrefetchAddr;
$display("%t Got %x", $time, x);
doAssert(x == tuple2('h90000040, 1), "test fail!");
endaction
action
let x <- p.getNextPrefetchAddr;
$display("%t Got %x", $time, x);
doAssert(x == tuple2('h90000080, 1), "test fail!");
endaction
action p.reportAccess(0, 'h40000000, MISS); endaction
action p.reportAccess(1, 'h50000000, MISS); endaction
action
let x <- p.getNextPrefetchAddr;
$display("%t Got %x", $time, x);
doAssert(x == tuple2('h80000040, 0), "test fail!");
endaction
action
let x <- p.getNextPrefetchAddr;
$display("%t Got %x", $time, x);
doAssert(x == tuple2('h40000040, 0), "test fail!");
endaction
action
let x <- p.getNextPrefetchAddr;
$display("%t Got %x", $time, x);
doAssert(x == tuple2('h50000040, 1), "test fail!");
endaction
action
let x <- p.getNextPrefetchAddr;
$display("%t Got %x", $time, x);
doAssert(x == tuple2('h40000080, 0), "test fail!");
endaction
action
let x <- p.getNextPrefetchAddr;
$display("%t Got %x", $time, x);
doAssert(x == tuple2('h50000080, 1), "test fail!");
endaction
action p.reportAccess(2, 'ha0000000, MISS); endaction
action
let x <- p.getNextPrefetchAddr;
$display("%t Got %x", $time, x);
doAssert(x == tuple2('ha0000040, 2), "test fail!");
endaction
action
let x <- p.getNextPrefetchAddr;
$display("%t Got %x", $time, x);
doAssert(x == tuple2('ha0000080, 2), "test fail!");
endaction
endseq
);
endmodule
module mkSimpleStridePCPrefetcherTest(Empty);
//paremeter - 2 ahead
let p <- mkSimpleStridePCPrefetcher;
mkAutoFSM(
seq
// ----- Send misses and stuff to one window -----
action $display("%t", $time); 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
let x <- p.getNextPrefetchAddr;
doAssert(x == 'h80000160, "test fail!");
endaction
action p.reportAccess('h80000400, 'h0069, MISS); endaction
action p.reportAccess('h80000300, 'h0069, MISS); endaction
action p.reportAccess('h80000200, 'h0069, MISS); endaction
action p.reportAccess('h80000100, 'h0069, MISS); endaction
action
let x <- p.getNextPrefetchAddr;
doAssert(x == 'h80000000, "test fail!");
endaction
endseq
);
endmodule

View File

@@ -740,4 +740,52 @@ module mkOverflowPipelineFifo( Fifo#(n, t) ) provisos (Bits#(t,tSz));
empty[2] <= True;
full[2] <= False;
endmethod
endmodule
endmodule
module mkOverflowBypassFifo( Fifo#(n, t) ) provisos (Bits#(t,tSz));
// n is size of fifo
// t is data type of fifo
Vector#(n, Ehr#(2,t)) data <- replicateM(mkEhr(?));
Ehr#(2, Bit#(TLog#(n))) enqP <- mkEhr(0);
Ehr#(3, Bit#(TLog#(n))) deqP <- mkEhr(0);
Ehr#(3, Bool) empty <- mkEhr(True);
Ehr#(3, Bool) full <- mkEhr(False);
Bit#(TLog#(n)) max_index = fromInteger(valueOf(n)-1);
method Bool notFull = !full[0];
method Action enq(t x);
data[enqP[0]][0] <= x;
empty[0] <= False;
let next_enqP = (enqP[0] == max_index) ? 0 : enqP[0] + 1;
if (full[0]) begin
deqP[0] <= next_enqP;
end
enqP[0] <= next_enqP;
if( next_enqP == deqP[0] ) begin
full[0] <= True;
end
endmethod
method Bool notEmpty = !empty[1];
method Action deq if( !empty[1] );
full[1] <= False;
let next_deqP = (deqP[1] == max_index) ? 0 : deqP[1] + 1;
deqP[1] <= next_deqP;
if( next_deqP == enqP[1] ) begin
empty[1] <= True;
end
endmethod
method t first if( !empty[1] );
return data[deqP[1]][1];
endmethod
method Action clear;
enqP[1] <= 0;
deqP[2] <= 0;
empty[2] <= True;
full[2] <= False;
endmethod
endmodule