From 7c05ebbd908e1010672aaaca7ac371f175008d84 Mon Sep 17 00:00:00 2001 From: Karlis Susters Date: Tue, 17 Jan 2023 21:10:19 +0000 Subject: [PATCH] Implemented multi line target prefetcher --- .../RISCY_OOO/coherence/src/Prefetcher.bsv | 145 ++++++++++++++++++ .../coherence/src/test/Prefetcher_test.bsv | 127 +++++++++++++++ 2 files changed, 272 insertions(+) diff --git a/src_Core/RISCY_OOO/coherence/src/Prefetcher.bsv b/src_Core/RISCY_OOO/coherence/src/Prefetcher.bsv index e5cfdf7..93593ca 100644 --- a/src_Core/RISCY_OOO/coherence/src/Prefetcher.bsv +++ b/src_Core/RISCY_OOO/coherence/src/Prefetcher.bsv @@ -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(); diff --git a/src_Core/RISCY_OOO/coherence/src/test/Prefetcher_test.bsv b/src_Core/RISCY_OOO/coherence/src/test/Prefetcher_test.bsv index f3ebf86..f0e37cf 100644 --- a/src_Core/RISCY_OOO/coherence/src/test/Prefetcher_test.bsv +++ b/src_Core/RISCY_OOO/coherence/src/test/Prefetcher_test.bsv @@ -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