Implemented multi line target prefetcher

This commit is contained in:
Karlis Susters
2023-01-17 21:10:19 +00:00
parent e602d4780e
commit 7c05ebbd90
2 changed files with 272 additions and 0 deletions

View File

@@ -350,6 +350,151 @@ module mkSingleWindowTargetPrefetcher(Prefetcher) provisos
endmethod
endmodule
module mkMultiWindowTargetPrefetcher(Prefetcher)
provisos(
Alias#(windowIdxT, Bit#(TLog#(NumWindows))),
NumAlias#(targetTableIdxBits, TLog#(TargetTableSize)),
NumAlias#(targetTableTagBits, TSub#(32, targetTableIdxBits)),
Alias#(targetEntryT, TargetEntry#(targetTableTagBits))
);
Integer cacheLinesInRange = 2;
Vector#(NumWindows, Reg#(StreamEntry)) streams
<- replicateM(mkReg(StreamEntry {rangeEnd: '0, nextToAsk: '0}));
Vector#(NumWindows, Reg#(windowIdxT)) shiftReg <- genWithM(compose(mkReg, fromInteger));
Reg#(LineAddr) lastChildRequest <- mkReg(0);
Vector#(TargetTableSize, Reg#(Maybe#(targetEntryT))) targetTable <- replicateM(mkReg(Invalid));
//rest is TODO
//function
function Action moveWindowToFront(windowIdxT window) =
action
if (shiftReg[0] == window) begin
end
else if (shiftReg[1] == window) begin
shiftReg[0] <= window;
shiftReg[1] <= shiftReg[0];
end
else if (shiftReg[2] == window) begin
shiftReg[0] <= window;
shiftReg[1] <= shiftReg[0];
shiftReg[2] <= shiftReg[1];
end
else if (shiftReg[3] == window) begin
shiftReg[0] <= window;
shiftReg[1] <= shiftReg[0];
shiftReg[2] <= shiftReg[1];
shiftReg[3] <= shiftReg[2];
end
endaction;
function ActionValue#(Maybe#(windowIdxT)) getMatchingWindow(LineAddr cl) =
actionvalue
//Finds the first window that contains cache line
function Bool pred(StreamEntry se);
//TODO < gives 100 cycles less??????
return (se.rangeEnd - fromInteger(cacheLinesInRange) - 1 <= cl
&& cl < se.rangeEnd);
endfunction
//Find first window that contains cache line cl
if (findIndex(pred, readVReg(streams)) matches tagged Valid .idx) begin
return Valid(pack(idx));
end
else begin
return Invalid;
end
endactionvalue;
method Action reportHit(Addr hitAddr);
//Check if any stream line matches request
//if so, advance that stream line
//also advance LRU shift reg
let cl = getLineAddr(hitAddr);
let idxMaybe <- getMatchingWindow(cl);
if (idxMaybe matches tagged Valid .idx) begin
moveWindowToFront(pack(idx)); //Update window as just used
let newRangeEnd = getLineAddr(hitAddr) + fromInteger(cacheLinesInRange) + 1;
streams[idx].rangeEnd <= newRangeEnd;
$display("%t Prefetcher reportHit %h, moving window end to %h for window idx %h",
$time, hitAddr, Addr'{newRangeEnd, '0}, idx);
end
else begin
$display("%t Prefetcher reportHit %h, no matching window found.",
$time, hitAddr);
end
if (cl != lastChildRequest + 1 && cl != lastChildRequest && cl != lastChildRequest - 1) begin
//Add entry to target table
targetEntryT entry;
entry.tag = lastChildRequest[31:valueOf(targetTableIdxBits)];
entry.target = cl;
Bit#(targetTableIdxBits) idx = truncate(lastChildRequest);
targetTable[idx] <= tagged Valid entry;
$display("%t Prefetcher reportHit %h, add target entry from %h", $time, hitAddr, Addr'{lastChildRequest, '0});
end
lastChildRequest <= cl;
endmethod
method Action reportMiss(Addr missAddr);
//Check if any stream line matches request
//If so, advance that stream line and advance LRU shift reg
//Otherwise, allocate new stream line, and shift LRU reg completely,
let cl = getLineAddr(missAddr);
let idxMaybe <- getMatchingWindow(cl);
if (idxMaybe matches tagged Valid .idx) begin
moveWindowToFront(pack(idx)); //Update window as just used
let newRangeEnd = getLineAddr(missAddr) + fromInteger(cacheLinesInRange) + 1;
//Also refresh nextToAsk on miss
streams[idx] <=
StreamEntry {nextToAsk: getLineAddr(missAddr) + 1,
rangeEnd: newRangeEnd};
$display("%t Prefetcher reportMiss %h, moving window end to %h for window idx %h",
$time, missAddr, Addr'{newRangeEnd, '0}, idx);
end
else begin
$display("%t Prefetcher reportMiss %h, allocating new stream, idx %h", $time, missAddr, shiftReg[3]);
streams[shiftReg[3]] <=
StreamEntry {nextToAsk: getLineAddr(missAddr) + 1,
rangeEnd: getLineAddr(missAddr) + fromInteger(cacheLinesInRange) + 1};
shiftReg[0] <= shiftReg[3];
shiftReg[1] <= shiftReg[0];
shiftReg[2] <= shiftReg[1];
shiftReg[3] <= shiftReg[2];
end
if (cl != lastChildRequest + 1 && cl != lastChildRequest && cl != lastChildRequest - 1) begin
//Add entry to target table
$display("%t Prefetcher reportMiss %h, add target entry from %h", $time, missAddr, Addr'{lastChildRequest, '0});
targetEntryT entry;
entry.tag = lastChildRequest[31:valueOf(targetTableIdxBits)];
entry.target = cl;
Bit#(targetTableIdxBits) idx = truncate(lastChildRequest);
targetTable[idx] <= tagged Valid entry;
end
lastChildRequest <= cl;
endmethod
method ActionValue#(Addr) getNextPrefetchAddr
if (streams[shiftReg[0]].nextToAsk != streams[shiftReg[0]].rangeEnd);
Addr retAddr;
let lastAsked = streams[shiftReg[0]].nextToAsk-1;
Bit#(targetTableIdxBits) idx = truncate(lastAsked);
if (targetTable[idx] matches tagged Valid .entry
&&& entry.tag == (lastAsked)[31:valueOf(targetTableIdxBits)]) begin
//If have valid entry for the last requested cline, prefetch the stored target first
//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
targetTable[idx] <= Invalid;
retAddr = {entry.target, '0};
$display("%t Prefetcher getNextPrefetchAddr requesting target entry %h", $time, retAddr);
end
else begin
streams[shiftReg[0]].nextToAsk <= streams[shiftReg[0]].nextToAsk + 1;
retAddr = Addr'{streams[shiftReg[0]].nextToAsk, '0}; //extend cache line address to regular address
$display("%t Prefetcher getNextPrefetchAddr requesting %h from window idx %h", $time, retAddr, shiftReg[0]);
end
return retAddr;
endmethod
endmodule
interface PCPrefetcher;
method Action reportAccess(Addr addr, Bit#(16) pcHash, HitOrMiss hitMiss);
method ActionValue#(Addr) getNextPrefetchAddr();

View File

@@ -104,6 +104,133 @@ module mkMultiWindowPrefetcherTest(Empty);
);
endmodule
module mkMultiWindowTargetPrefetcherTest(Empty);
//let p <- mkMultipleWindowPrefetcher;
//TODO pass in value of cachelinesinrange
let p <- mkMultiWindowTargetPrefetcher;
mkAutoFSM(
seq
// ----- Send misses and stuff to one window -----
action
p.reportMiss('h80000040);
endaction
action
let x <- p.getNextPrefetchAddr;
doAssert(x == 'h80000080, "test fail!");
endaction
action
let x <- p.getNextPrefetchAddr;
doAssert(x == 'h800000c0, "test fail!");
endaction
action
p.reportHit('h800000c0); //Report hit inside window
endaction
action
let x <- p.getNextPrefetchAddr;
doAssert(x == 'h80000100, "test fail!");
endaction
action
p.reportHit('h80004000); //Report hit outside window
endaction
action
let x <- p.getNextPrefetchAddr; //Previous window still recommended
doAssert(x == 'h80000140, "test fail!");
endaction
action
p.reportMiss('h80000140); //Report miss inside window
endaction
action
let x <- p.getNextPrefetchAddr; //Previous window still recommended
doAssert(x == 'h80000180, "test fail!");
endaction
// ----- Allocate other windows -----
action
p.reportMiss('h70000000); //Report miss outside window
endaction
action
let x <- p.getNextPrefetchAddr; //new window recommended
doAssert(x == 'h70000040, "test fail!");
endaction
action
p.reportMiss('h90000000); //Report miss outside window
endaction
action
let x <- p.getNextPrefetchAddr; //new window recommended
doAssert(x == 'h90000040, "test fail!");
endaction
action
p.reportMiss('h60000000); //Report miss outside window
endaction
action
let x <- p.getNextPrefetchAddr; //new window recommended
doAssert(x == 'h60000040, "test fail!");
endaction
action
p.reportHit('h80000180); //Report hit inside oldest window
endaction
action
let x <- p.getNextPrefetchAddr; //oldest window recommended
doAssert(x == 'h800001c0, "test fail!");
endaction
// ----- Trigger window deletion -----
action
p.reportMiss('h50000000); //Report miss outside window,
//discard window with 'h70..
endaction
action
let x <- p.getNextPrefetchAddr; //new window recommended
doAssert(x == 'h50000040, "test fail!");
endaction
action
p.reportHit('h70000040); //Report hit inside now deleted window
endaction
action
let x <- p.getNextPrefetchAddr; //most recent window still recommended
doAssert(x == 'h50000080, "test fail!");
endaction
// ----- Reorder some more windows around
action
p.reportMiss('h800001c0); //Report hit inside now deleted window
endaction
action
let x <- p.getNextPrefetchAddr;
doAssert(x == 'h80000200, "test fail!");
endaction
// ------ Test saving and prefetching target clines
action
p.reportMiss('h81000000); //Report miss somewhere far away
endaction
action
let x <- p.getNextPrefetchAddr; //New window allocated and recommended
doAssert(x == 'h81000040, "test fail!");
endaction
action
p.reportMiss('h80000180); //Report miss back home
endaction
action
let x <- p.getNextPrefetchAddr; //new window recommended
doAssert(x == 'h50000000, "test fail!");
endaction
action
let x <- p.getNextPrefetchAddr;
doAssert(x == 'h800001c0, "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
endaction
endseq
);
endmodule
module mkSingleWindowTargetPrefetcherTest(Empty);
//let p <- mkMultipleWindowPrefetcher;
//TODO pass in value of cachelinesinrange