Merge remote-tracking branch 'karlis/CHERI' into ks980-prefetch
This commit is contained in:
@@ -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
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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];
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user