From 347107b7337dd9126d0a059a1f6f2994c3136e55 Mon Sep 17 00:00:00 2001 From: Karlis Susters Date: Mon, 16 Jan 2023 12:26:11 +0200 Subject: [PATCH] Prefetcher implementation in both L1 and LL and data logging --- src_Core/CPU/Core.bsv | 8 +- src_Core/CPU/Proc.bsv | 84 +++ src_Core/RISCY_OOO/Makefile | 1 + src_Core/RISCY_OOO/coherence/src/CCTypes.bsv | 1 + src_Core/RISCY_OOO/coherence/src/IBank.bsv | 81 ++- src_Core/RISCY_OOO/coherence/src/IPRqMshr.bsv | 4 +- src_Core/RISCY_OOO/coherence/src/L1Bank.bsv | 70 ++- .../RISCY_OOO/coherence/src/L1PRqMshr.bsv | 4 +- src_Core/RISCY_OOO/coherence/src/L1Pipe.bsv | 16 +- src_Core/RISCY_OOO/coherence/src/LLBank.bsv | 128 ++++- .../RISCY_OOO/coherence/src/Prefetcher.bsv | 542 ++++++++++++++++++ .../coherence/src/test/Prefetcher_test.bsv | 249 ++++++++ .../procs/RV64G_OOO/MemExePipeline.bsv | 37 +- .../RISCY_OOO/procs/RV64G_OOO/RenameStage.bsv | 4 +- src_Core/RISCY_OOO/procs/lib/DirPredictor.bsv | 2 +- src_Core/RISCY_OOO/procs/lib/Performance.bsv | 2 + src_Core/RISCY_OOO/procs/lib/SplitLSQ.bsv | 30 +- src_Core/RISCY_OOO/procs/lib/StoreBuffer.bsv | 13 +- 18 files changed, 1200 insertions(+), 76 deletions(-) create mode 100644 src_Core/RISCY_OOO/coherence/src/Prefetcher.bsv create mode 100644 src_Core/RISCY_OOO/coherence/src/test/Prefetcher_test.bsv diff --git a/src_Core/CPU/Core.bsv b/src_Core/CPU/Core.bsv index 1dcca4a..6c0ea47 100644 --- a/src_Core/CPU/Core.bsv +++ b/src_Core/CPU/Core.bsv @@ -131,7 +131,7 @@ import Trace_Data2 :: *; // ================================================================ -`ifdef SECURITY +`ifdef SECURITY_BRPRED `define SECURITY_OR_INCLUDE_GDB_CONTROL `elsif INCLUDE_GDB_CONTROL `define SECURITY_OR_INCLUDE_GDB_CONTROL @@ -364,7 +364,7 @@ module mkCore#(CoreId coreId)(Core); ); // whether perf data is collected - Reg#(Bool) doStatsReg <- mkConfigReg(False); + Reg#(Bool) doStatsReg <- mkConfigReg(True); // write aggressive elements + wakupe reservation stations function Action writeAggr(Integer wrAggrPort, PhyRIndx dst); @@ -830,8 +830,8 @@ module mkCore#(CoreId coreId)(Core); // to finish rule flushCaches(doFlushCaches); flush_caches <= False; - iMem.flush; - dMem.flush; + //iMem.flush; + //dMem.flush; // $display ("%0d: %m.rule flushCaches (imem and dmem)", cur_cycle); endrule diff --git a/src_Core/CPU/Proc.bsv b/src_Core/CPU/Proc.bsv index b8b00d7..9a95610 100644 --- a/src_Core/CPU/Proc.bsv +++ b/src_Core/CPU/Proc.bsv @@ -237,6 +237,90 @@ module mkProc (Proc_IFC); endrule end + // ================================================================ + // Send and print perf requests + + Reg#(Bit#(4)) perfCnt <- mkReg(0); + Reg#(Bool) requestSent <- mkReg(False); + rule rl_sendLLCPerfReq if (!requestSent); + perfCnt <= (perfCnt == 12) ? 0 : perfCnt + 1; + case (perfCnt) + 'b1001: llc.perf.req(LLCNormalMemLdCnt); + 'b1010: llc.perf.req(LLCNormalMemLdLat); + 'b1011: llc.perf.req(LLCInstructionLdCnt); + 'b1100: llc.perf.req(LLCInstructionLdLat); + endcase + requestSent <= True; + endrule + rule rl_printLLCPerfResp; + let perfResp <- llc.perf.resp; + requestSent <= False; + if (perfResp.pType == LLCNormalMemLdCnt) begin + $display("%0d: LLC data miss count: %d", cur_cycle, unpack(perfResp.data)); + end + else if (perfResp.pType == LLCNormalMemLdLat) begin + $display("%0d: LLC data miss latency: %d", cur_cycle, unpack(perfResp.data)); + end + else if (perfResp.pType == LLCInstructionLdCnt) begin + $display("%0d: LLC instruction miss count: %d", cur_cycle, unpack(perfResp.data)); + end + else if (perfResp.pType == LLCInstructionLdLat) begin + $display("%0d: LLC instruction miss latency: %d", cur_cycle, unpack(perfResp.data)); + end + endrule + + for(Integer i = 0; i < valueof(CoreNum); i = i+1) begin + rule rl_sendPerfReq if (!requestSent); + case (perfCnt) + 'b0000: core[i].coreReq.perfReq(ICache, zeroExtend(pack(L1ILdCnt))); + 'b0001: core[i].coreReq.perfReq(ICache, zeroExtend(pack(L1ILdMissCnt))); + 'b0010: core[i].coreReq.perfReq(ICache, zeroExtend(pack(L1ILdMissLat))); + 'b0011: core[i].coreReq.perfReq(DCache, zeroExtend(pack(L1DLdCnt))); + 'b0100: core[i].coreReq.perfReq(DCache, zeroExtend(pack(L1DLdMissCnt))); + 'b0101: core[i].coreReq.perfReq(DCache, zeroExtend(pack(L1DLdMissLat))); + 'b0110: core[i].coreReq.perfReq(DCache, zeroExtend(pack(L1DStCnt))); + 'b0111: core[i].coreReq.perfReq(DCache, zeroExtend(pack(L1DStMissCnt))); + 'b1000: core[i].coreReq.perfReq(DCache, zeroExtend(pack(L1DStMissLat))); + endcase + endrule + + rule rl_printPerfResp; + let perfResp <- core[i].coreIndInv.perfResp; + requestSent <= False; + if (perfResp.loc == ICache) begin + if (perfResp.pType == zeroExtend(pack(L1ILdCnt))) begin + $display("%0d: L1I load count: %d", cur_cycle, unpack(perfResp.data)); + end + else if (perfResp.pType == zeroExtend(pack(L1ILdMissCnt))) begin + $display("%0d: L1I load miss count: %d", cur_cycle, unpack(perfResp.data)); + end + else if (perfResp.pType == zeroExtend(pack(L1ILdMissLat))) begin + $display("%0d: L1I load miss latency: %d", cur_cycle, unpack(perfResp.data)); + end + end + else if (perfResp.loc == DCache) begin + if (perfResp.pType == zeroExtend(pack(L1DLdCnt))) begin + $display("%0d: L1D load count: %d", cur_cycle, unpack(perfResp.data)); + end + else if (perfResp.pType == zeroExtend(pack(L1DLdMissCnt))) begin + $display("%0d: L1D load miss count: %d", cur_cycle, unpack(perfResp.data)); + end + else if (perfResp.pType == zeroExtend(pack(L1DLdMissLat))) begin + $display("%0d: L1D load miss latency: %d", cur_cycle, unpack(perfResp.data)); + end + if (perfResp.pType == zeroExtend(pack(L1DStCnt))) begin + $display("%0d: L1D store count: %d", cur_cycle, unpack(perfResp.data)); + end + else if (perfResp.pType == zeroExtend(pack(L1DStMissCnt))) begin + $display("%0d: L1D store miss count: %d", cur_cycle, unpack(perfResp.data)); + end + else if (perfResp.pType == zeroExtend(pack(L1DStMissLat))) begin + $display("%0d: L1D store miss latency: %d", cur_cycle, unpack(perfResp.data)); + end + end + endrule + end + // ================================================================ // Print out values written 'tohost' diff --git a/src_Core/RISCY_OOO/Makefile b/src_Core/RISCY_OOO/Makefile index 54ac990..cfbdaa2 100644 --- a/src_Core/RISCY_OOO/Makefile +++ b/src_Core/RISCY_OOO/Makefile @@ -108,6 +108,7 @@ copy_coherence_src_files: cp -p $(RISCY_HOME)/$(COHERENCE_SRC)/LLCRqMshr.bsv ./$(COHERENCE_SRC)/ cp -p $(RISCY_HOME)/$(COHERENCE_SRC)/LLPipe.bsv ./$(COHERENCE_SRC)/ cp -p $(RISCY_HOME)/$(COHERENCE_SRC)/MshrDeadlockChecker.bsv ./$(COHERENCE_SRC)/ + cp -p $(RISCY_HOME)/$(COHERENCE_SRC)/Prefetcher.bsv ./$(COHERENCE_SRC)/ cp -p $(RISCY_HOME)/$(COHERENCE_SRC)/RandomReplace.bsv ./$(COHERENCE_SRC)/ cp -p $(RISCY_HOME)/$(COHERENCE_SRC)/RWBramCore.bsv ./$(COHERENCE_SRC)/ cp -p $(RISCY_HOME)/$(COHERENCE_SRC)/SelfInvIBank.bsv ./$(COHERENCE_SRC)/ diff --git a/src_Core/RISCY_OOO/coherence/src/CCTypes.bsv b/src_Core/RISCY_OOO/coherence/src/CCTypes.bsv index 90a3038..7869903 100644 --- a/src_Core/RISCY_OOO/coherence/src/CCTypes.bsv +++ b/src_Core/RISCY_OOO/coherence/src/CCTypes.bsv @@ -205,6 +205,7 @@ typedef struct { MemTaggedData data; // valid when op == Sc/Amo AmoInst amoInst; // valid when op == Amo Bool loadTags; // valid when op == Ld + Bit#(16) pcHash; // hash of instruction pc sending the request } ProcRq#(type idT) deriving(Bits, Eq, FShow); interface L1ProcReq#(type idT); diff --git a/src_Core/RISCY_OOO/coherence/src/IBank.bsv b/src_Core/RISCY_OOO/coherence/src/IBank.bsv index 557c730..2e8d836 100644 --- a/src_Core/RISCY_OOO/coherence/src/IBank.bsv +++ b/src_Core/RISCY_OOO/coherence/src/IBank.bsv @@ -57,6 +57,7 @@ import CacheUtils::*; import Performance::*; import LatencyTimer::*; import RandomReplace::*; +import Prefetcher::*; `ifdef PERFORMANCE_MONITORING import PerformanceMonitor::*; import BlueUtils::*; @@ -142,7 +143,7 @@ module mkIBank#( Add#(TAdd#(tagSz, indexSz), TAdd#(lgBankNum, LgLineSzBytes), AddrSz) ); - Bool verbose = False; + Bool verbose = False; ICRqMshr#(cRqNum, wayT, tagT, procRqT, resultT) cRqMshr <- mkICRqMshrLocal; @@ -165,6 +166,11 @@ module mkIBank#( // index Q to order all in flight cRq for in-order resp FIFO#(cRqIdxT) cRqIndexQ <- mkSizedFIFO(valueof(cRqNum)); + FIFO#(cRqIdxT) prefetchIndexQ <- mkSizedFIFO(valueof(cRqNum)); + Vector#(cRqNum, Reg#(Bool)) cRqIsPrefetch <- replicateM(mkReg(?)); + Vector#(cRqNum, Reg#(Bool)) prefetchRqDone <- replicateM(mkReg(?)); + + let prefetcher <- mkL1IPrefetcher; `ifdef DEBUG_ICACHE // id for each cRq, incremented when each new req comes @@ -175,7 +181,7 @@ module mkIBank#( `endif // security flush -`ifdef SECURITY +`ifdef SECURITY_CACHES Reg#(Bool) flushDone <- mkReg(True); Reg#(Bool) flushReqStart <- mkReg(False); Reg#(Bool) flushReqDone <- mkReg(False); @@ -187,8 +193,10 @@ module mkIBank#( `endif LatencyTimer#(cRqNum, 10) latTimer <- mkLatencyTimer; + Count#(Bit#(32)) addedCRqs <- mkCount(0); + Count#(Bit#(32)) removedCRqs <- mkCount(0); `ifdef PERF_COUNT - Reg#(Bool) doStats <- mkConfigReg(False); + Reg#(Bool) doStats <- mkConfigReg(True); Count#(Data) ldCnt <- mkCount(0); Count#(Data) ldMissCnt <- mkCount(0); Count#(Data) ldMissLat <- mkCount(0); @@ -233,10 +241,15 @@ module mkIBank#( function tagT getTag(Addr a) = truncateLSB(a); + rule print_cRqIndexQ_len; + //$display("L1I cRqIndexQ length= %d", addedCRqs-removedCRqs); + endrule + // XXX since I$ may be requested by processor constantly // cRq may come at every cycle, so we must make cRq has lower priority than pRq/pRs // otherwise the whole system may deadlock/livelock // we stop accepting cRq when we need to flush for security + (* descending_urgency = "createPrefetchRq, cRqTransfer" *) rule cRqTransfer(flushDone); Addr addr <- toGet(rqFromCQ).get; `ifdef DEBUG_ICACHE @@ -253,6 +266,8 @@ module mkIBank#( })); // enq to indexQ for in order resp cRqIndexQ.enq(n); + cRqIsPrefetch[n] <= False; + addedCRqs.incr(1); // performance counter: cRq type incrReqCnt; if (verbose) @@ -294,7 +309,32 @@ module mkIBank#( doAssert(resp.toState == S && isValid(resp.data), "I$ must upgrade to S with data"); endrule -`ifdef SECURITY + //(* descending_urgency = "createPrefetchRq, pRsTransfer, cRqTransfer" *) + //(* descending_urgency = "createPrefetchRq, pRqTransfer, cRqTransfer" *) + rule createPrefetchRq(flushDone); + Addr addr <- prefetcher.getNextPrefetchAddr; + procRqT r = ProcRqToI {addr: addr}; + cRqIdxT n <- cRqMshr.getEmptyEntryInit(r); + // send to pipeline + pipeline.send(CRq (L1PipeRqIn { + addr: r.addr, + mshrIdx: n + })); + // enq to indexQ for in order resp + prefetchIndexQ.enq(n); + cRqIsPrefetch[n] <= True; + prefetchRqDone[n] <= False; + addedCRqs.incr(1); + // performance counter: cRq type + //incrReqCnt; TODO make separate counter for prefetch requests + if (verbose) + $display("%t I %m createPrefetchRq: ", $time, + fshow(n), " ; ", + fshow(r) + ); + endrule + +`ifdef SECURITY_CACHES // start flush when cRq MSHR is empty rule startFlushReq(!flushDone && !flushReqStart && cRqMshr.emptyForFlush); flushReqStart <= True; @@ -334,6 +374,7 @@ module mkIBank#( endrule `endif + // Used when replacing an evicted cache line rule sendRsToP_cRq(rsToPIndexQ.first matches tagged CRq .n); rsToPIndexQ.deq; // get cRq replacement info @@ -471,6 +512,10 @@ module mkIBank#( }, line: ram.line }, True); // hit, so update rep info + if (!cRqIsPrefetch[n]) begin + prefetcher.reportHit(req.addr); + end + prefetchRqDone[n] <= True; // process req to get superscalar inst read results // set MSHR entry as Done & save inst results let instResult = readInst(ram.line, req.addr); @@ -530,10 +575,14 @@ module mkIBank#( }, line: ram.line }, False); + if (!cRqIsPrefetch[n]) begin + prefetcher.reportMiss(procRq.addr); + end endaction endfunction // function to do replacement for cRq + // When we evict an S cache line to make space function Action cRqReplacement; action // deq pipeline @@ -556,6 +605,9 @@ module mkIBank#( repTag: ram.info.tag, // tag being replaced for sending rs to parent waitP: True }); + if (!cRqIsPrefetch[n]) begin + prefetcher.reportMiss(procRq.addr); + end // send replacement resp to parent rsToPIndexQ.enq(CRq (n)); endaction @@ -640,7 +692,9 @@ module mkIBank#( ); cRqHit(cOwner, procRq); // performance counter: miss cRq - incrMissCnt(cOwner); + if (!cRqIsPrefetch[cOwner]) begin + incrMissCnt(cOwner); + end end else begin doAssert(False, ("pRs owner must match some cRq")); @@ -694,8 +748,20 @@ module mkIBank#( rsToPIndexQ.enq(PRq (n)); end endrule + + rule discardPrefetchRqResult( + //cRqMshr.sendRsToC.getResult(prefetchIndexQ.first) matches tagged Valid .inst); + prefetchRqDone[prefetchIndexQ.first]); + prefetchIndexQ.deq; + removedCRqs.incr(1); + cRqMshr.sendRsToC.releaseEntry(prefetchIndexQ.first); // release MSHR entry + if (verbose) + $display("%t I %m discardPrefetchRqResult: ", $time, + fshow(prefetchIndexQ.first) + ); + endrule -`ifdef SECURITY +`ifdef SECURITY_CACHES rule pipelineResp_flush( !flushDone &&& !flushRespDone &&& pipeOut.cmd matches tagged L1Flush .flush @@ -783,6 +849,7 @@ module mkIBank#( cRqMshr.sendRsToC.getResult(cRqIndexQ.first) matches tagged Valid .inst ); cRqIndexQ.deq; + removedCRqs.incr(1); cRqMshr.sendRsToC.releaseEntry(cRqIndexQ.first); // release MSHR entry if (verbose) $display("%t I %m sendRsToC: ", $time, @@ -810,7 +877,7 @@ module mkIBank#( interface pRqStuck = pRqMshr.stuck; -`ifdef SECURITY +`ifdef SECURITY_CACHES method Action flush if(flushDone); flushDone <= False; endmethod diff --git a/src_Core/RISCY_OOO/coherence/src/IPRqMshr.bsv b/src_Core/RISCY_OOO/coherence/src/IPRqMshr.bsv index 2ef1be9..17d741c 100644 --- a/src_Core/RISCY_OOO/coherence/src/IPRqMshr.bsv +++ b/src_Core/RISCY_OOO/coherence/src/IPRqMshr.bsv @@ -74,7 +74,7 @@ interface IPRqMshr_pipelineResp#(numeric type pRqNum); method PRqMsg#(void) getRq(Bit#(TLog#(pRqNum)) n); method Action releaseEntry(Bit#(TLog#(pRqNum)) n); method Action setDone(Bit#(TLog#(pRqNum)) n); -`ifdef SECURITY +`ifdef SECURITY_CACHES method Action setFlushAddr(Bit#(TLog#(pRqNum)) n, Addr a); `endif endinterface @@ -204,7 +204,7 @@ module mkIPRqMshrSafe( stateVec[n][pipelineResp_port] <= Empty; endmethod -`ifdef SECURITY +`ifdef SECURITY_CACHES method Action setFlushAddr(Bit#(TLog#(pRqNum)) n, Addr a); reqVec[n][pipelineResp_port] <= PRqMsg { addr: a, diff --git a/src_Core/RISCY_OOO/coherence/src/L1Bank.bsv b/src_Core/RISCY_OOO/coherence/src/L1Bank.bsv index 8462fd2..937d735 100644 --- a/src_Core/RISCY_OOO/coherence/src/L1Bank.bsv +++ b/src_Core/RISCY_OOO/coherence/src/L1Bank.bsv @@ -60,6 +60,7 @@ import CrossBar::*; import Performance::*; import LatencyTimer::*; import RandomReplace::*; +import Prefetcher::*; `ifdef PERFORMANCE_MONITORING import PerformanceMonitor::*; import StatCounters::*; @@ -155,7 +156,7 @@ module mkL1Bank#( Add#(TAdd#(tagSz, indexSz), TAdd#(lgBankNum, LgLineSzBytes), AddrSz) ); - Bool verbose = False; + Bool verbose = True; L1CRqMshr#(cRqNum, wayT, tagT, procRqT) cRqMshr <- mkL1CRqMshrLocal; @@ -186,8 +187,11 @@ module mkL1Bank#( // we process AMO resp in a new cycle to cut critical path Reg#(Maybe#(AmoHitInfo#(cRqIdxT, procRqT))) processAmo <- mkReg(Invalid); + Vector#(cRqNum, Reg#(Bool)) cRqIsPrefetch <- replicateM(mkReg(?)); + let prefetcher <- mkL1DPrefetcher; + // security flush -`ifdef SECURITY +`ifdef SECURITY_CACHES Reg#(Bool) flushDone <- mkReg(True); Reg#(Bool) flushReqStart <- mkReg(False); Reg#(Bool) flushReqDone <- mkReg(False); @@ -299,6 +303,7 @@ endfunction addr: req.addr, mshrIdx: n })); + cRqIsPrefetch[n] <= False; if (verbose) $display("%t L1 %m cRqTransfer_retry: ", $time, fshow(n), " ; ", @@ -317,6 +322,7 @@ endfunction addr: r.addr, mshrIdx: n })); + cRqIsPrefetch[n] <= False; // performance counter: cRq type incrReqCnt(r.op); if (verbose) @@ -355,7 +361,38 @@ endfunction $display("%t L1 %m pRsTransfer: ", $time, fshow(resp)); endrule -`ifdef SECURITY + + (* descending_urgency = "pRsTransfer, cRqTransfer_retry, cRqTransfer_new, createPrefetchRq" *) + (* descending_urgency = "pRqTransfer, cRqTransfer_retry, cRqTransfer_new, createPrefetchRq" *) + rule createPrefetchRq(flushDone); + Addr addr <- prefetcher.getNextPrefetchAddr; + procRqT r = ProcRq { + id: ?, //Or maybe do 0 here + addr: addr, + toState: M, + op: Ld, + byteEn: ?, + data: ?, + amoInst: ?, + loadTags: ?, + pcHash: ? + }; + cRqIdxT n <- cRqMshr.cRqTransfer.getEmptyEntryInit(r); + // send to pipeline + pipeline.send(CRq (L1PipeRqIn { + addr: r.addr, + mshrIdx: n + })); + cRqIsPrefetch[n] <= True; + // performance counter: cRq type + if (verbose) + $display("%t L1 %m createPrefetchRq: ", $time, + fshow(n), " ; ", + fshow(r) + ); + endrule + +`ifdef SECURITY_CACHES // start flush when cRq MSHR is empty rule startFlushReq(!flushDone && !flushReqStart && cRqMshr.emptyForFlush); flushReqStart <= True; @@ -521,10 +558,12 @@ endfunction LineMemDataOffset dataSel = getLineMemDataOffset(req.addr); case(req.op) matches Ld: begin - if (req.loadTags) begin - procResp.respLd(req.id, getTagsAt(curLine)); - end else begin - procResp.respLd(req.id, getTaggedDataAt(curLine, dataSel)); + if (!cRqIsPrefetch[n]) begin + if (req.loadTags) begin + procResp.respLd(req.id, getTagsAt(curLine)); + end else begin + procResp.respLd(req.id, getTaggedDataAt(curLine, dataSel)); + end end end Lr: begin @@ -579,6 +618,9 @@ endfunction }, line: newLine // write new data into cache }, True); // hit, so update rep info + if (!cRqIsPrefetch[n]) begin + prefetcher.reportAccess(req.addr, req.pcHash, HIT); + end if (verbose) $display("%t L1 %m pipelineResp: Hit func: update ram: ", $time, fshow(newLine), " ; ", @@ -729,6 +771,9 @@ endfunction }, line: ram.line }, False); + if (!cRqIsPrefetch[n]) begin + prefetcher.reportAccess(procRq.addr, procRq.pcHash, MISS); + end endaction endfunction @@ -754,6 +799,9 @@ endfunction waitP: False // we send req to parent later (when resp to parent is sent) }); cRqMshr.pipelineResp.setData(n, ram.info.cs == M ? Valid (ram.line) : Invalid); + if (!cRqIsPrefetch[n]) begin + prefetcher.reportAccess(procRq.addr, procRq.pcHash, MISS); + end // send replacement resp to parent rsToPIndexQ.enq(CRq (n)); // reset link addr @@ -892,7 +940,9 @@ endfunction ); cRqHit(cOwner, procRq); // performance counter: miss cRq - incrMissCnt(procRq.op, cOwner); + if (!cRqIsPrefetch[cOwner]) begin + incrMissCnt(procRq.op, cOwner); + end end else begin doAssert(False, ("pRs owner must match some cRq")); @@ -989,7 +1039,7 @@ endfunction end endrule -`ifdef SECURITY +`ifdef SECURITY_CACHES rule pipelineResp_flush( !isValid(processAmo) &&& !flushDone &&& !flushRespDone &&& @@ -1095,7 +1145,7 @@ endfunction interface pRqStuck = pRqMshr.stuck; -`ifdef SECURITY +`ifdef SECURITY_CACHES method Action flush if(flushDone); flushDone <= False; endmethod diff --git a/src_Core/RISCY_OOO/coherence/src/L1PRqMshr.bsv b/src_Core/RISCY_OOO/coherence/src/L1PRqMshr.bsv index 732586e..b59c004 100644 --- a/src_Core/RISCY_OOO/coherence/src/L1PRqMshr.bsv +++ b/src_Core/RISCY_OOO/coherence/src/L1PRqMshr.bsv @@ -77,7 +77,7 @@ interface L1PRqMshr_pipelineResp#(numeric type pRqNum); method Action releaseEntry(Bit#(TLog#(pRqNum)) n); method Action setDone_setData(Bit#(TLog#(pRqNum)) n, Maybe#(Line) d); -`ifdef SECURITY +`ifdef SECURITY_CACHES method Action setFlushAddr(Bit#(TLog#(pRqNum)) n, Addr a); `endif endinterface @@ -223,7 +223,7 @@ module mkL1PRqMshrSafe( stateVec[n][pipelineResp_port] <= Empty; endmethod -`ifdef SECURITY +`ifdef SECURITY_CACHES method Action setFlushAddr(Bit#(TLog#(pRqNum)) n, Addr a); reqVec[n][pipelineResp_port] <= PRqMsg { addr: a, diff --git a/src_Core/RISCY_OOO/coherence/src/L1Pipe.bsv b/src_Core/RISCY_OOO/coherence/src/L1Pipe.bsv index c1d17fa..5c10df3 100644 --- a/src_Core/RISCY_OOO/coherence/src/L1Pipe.bsv +++ b/src_Core/RISCY_OOO/coherence/src/L1Pipe.bsv @@ -84,7 +84,7 @@ typedef union tagged { L1PipeRqIn#(cRqIdxT) CRq; L1PipeRqIn#(pRqIdxT) PRq; L1PipePRsIn#(wayT) PRs; -`ifdef SECURITY +`ifdef SECURITY_CACHES L1PipeFlushIn#(wayT, indexT, pRqIdxT) Flush; `endif } L1PipeIn#( @@ -104,7 +104,7 @@ typedef union tagged { cRqIdxT L1CRq; pRqIdxT L1PRq; void L1PRs; -`ifdef SECURITY +`ifdef SECURITY_CACHES L1FlushCmd#(indexT, pRqIdxT) L1Flush; `endif } L1Cmd#( @@ -145,7 +145,7 @@ typedef union tagged { L1PipeRqIn#(cRqIdxT) CRq; L1PipeRqIn#(pRqIdxT) PRq; L1PipePRsCmd#(wayT) PRs; -`ifdef SECURITY +`ifdef SECURITY_CACHES L1PipeFlushIn#(wayT, indexT, pRqIdxT) Flush; `endif } L1PipeCmd#( @@ -220,7 +220,7 @@ module mkL1Pipe( tagged CRq .r: r.addr; tagged PRq .r: r.addr; tagged PRs .r: r.addr; -`ifdef SECURITY +`ifdef SECURITY_CACHES // fake an address for flush req that has the same index tagged Flush .r: (zeroExtend(r.index) << (valueOf(LgLineSzBytes) + valueOf(lgBankNum))); `endif @@ -258,7 +258,7 @@ module mkL1Pipe( pRqMiss: False }; end -`ifdef SECURITY +`ifdef SECURITY_CACHES else if(cmd matches tagged Flush .flush) begin // flush directly read from cmd return TagMatchResult { @@ -360,7 +360,7 @@ module mkL1Pipe( way: rs.way }), rs.data, UpCs (rs.toState)); end -`ifdef SECURITY +`ifdef SECURITY_CACHES tagged Flush .flush: begin pipe.enq(Flush (flush), Invalid, Invalid); end @@ -376,7 +376,7 @@ module mkL1Pipe( tagged CRq .rq: L1CRq (rq.mshrIdx); tagged PRq .rq: L1PRq (rq.mshrIdx); tagged PRs .rs: L1PRs; -`ifdef SECURITY +`ifdef SECURITY_CACHES tagged Flush .flush: L1Flush (L1FlushCmd { index: flush.index, mshrIdx: flush.mshrIdx @@ -397,7 +397,7 @@ module mkL1Pipe( if(swapRq matches tagged Valid .idx) begin // swap in cRq Addr addr = getAddrFromCmd(pipe.first.cmd); // inherit addr newCmd = Valid (CRq (L1PipeRqIn {addr: addr, mshrIdx: idx})); -`ifdef SECURITY +`ifdef SECURITY_CACHES doAssert(pipe.first.cmd matches tagged Flush .f ? False : True, "Cannot swap after a flush req"); `endif diff --git a/src_Core/RISCY_OOO/coherence/src/LLBank.bsv b/src_Core/RISCY_OOO/coherence/src/LLBank.bsv index 0fbe4ba..b1db9ff 100644 --- a/src_Core/RISCY_OOO/coherence/src/LLBank.bsv +++ b/src_Core/RISCY_OOO/coherence/src/LLBank.bsv @@ -51,6 +51,7 @@ import LatencyTimer::*; import Cntrs::*; import ConfigReg::*; import RandomReplace::*; +import Prefetcher::*; `ifdef PERFORMANCE_MONITORING import PerformanceMonitor::*; import StatCounters::*; @@ -186,7 +187,7 @@ module mkLLBank#( Add#(cRqNum, b__, wayNum) ); - Bool verbose = False; + Bool verbose = True; LLCRqMshr#(cRqNum, wayT, tagT, Vector#(childNum, DirPend), cRqT) cRqMshr <- mkLLMshr; @@ -228,12 +229,21 @@ module mkLLBank#( // performance LatencyTimer#(cRqNum, 10) latTimer <- mkLatencyTimer; // max 1K cycle latency + + Count#(Bit#(32)) addedCRqs <- mkCount(0); + Count#(Bit#(32)) removedCRqs <- mkCount(0); + + Vector#(cRqNum, Reg#(Bool)) cRqIsPrefetch <- replicateM(mkReg(?)); + Prefetcher dataPrefetcher <- mkLLDPrefetcher; + Prefetcher instrPrefetcher <- mkLLIPrefetcher; `ifdef PERF_COUNT - Reg#(Bool) doStats <- mkConfigReg(False); + Reg#(Bool) doStats <- mkConfigReg(True); Count#(Data) dmaMemLdCnt <- mkCount(0); Count#(Data) dmaMemLdLat <- mkCount(0); Count#(Data) normalMemLdCnt <- mkCount(0); Count#(Data) normalMemLdLat <- mkCount(0); + Count#(Data) instructionLdCnt <- mkCount(0); + Count#(Data) instructionLdLat <- mkCount(0); Count#(Data) mshrBlocks <- mkCount(0); Count#(Data) downRespCnt <- mkCount(0); Count#(Data) downRespDataCnt <- mkCount(0); @@ -246,7 +256,7 @@ module mkLLBank#( `ifdef PERFORMANCE_MONITORING Array #(Reg #(EventsLL)) perf_events <- mkDRegOR (2, unpack (0)); `endif -function Action incrMissCnt(cRqIndexT idx, Bool isDma); +function Action incrMissCnt(cRqIndexT idx, Bool isDma, Bool isInstructionAccess); action let lat <- latTimer.done(idx); `ifdef PERF_COUNT @@ -255,6 +265,10 @@ action dmaMemLdCnt.incr(1); dmaMemLdLat.incr(zeroExtend(lat)); end + else if (isInstructionAccess) begin + instructionLdCnt.incr(1); + instructionLdLat.incr(zeroExtend(lat)); + end else begin normalMemLdCnt.incr(1); normalMemLdLat.incr(zeroExtend(lat)); @@ -329,6 +343,7 @@ endfunction // later cRq to same addr needs to be appended after this one // send to pipeline cRqT req = cRqMshr.transfer.getRq(n); + cRqIsPrefetch[n] <= False; pipeline.send(CRq (LLPipeCRqIn { addr: req.addr, mshrIdx: n @@ -389,6 +404,7 @@ endfunction addr: cRq.addr, mshrIdx: n })); + cRqIsPrefetch[n] <= False; // change round robin flipPriorNewCRqSrc; if (verbose) @@ -399,6 +415,64 @@ endfunction ); endrule + // insert new cRq from child to MSHR and send to pipeline + rule createDataPrefetchRq(newCRqSrc == Valid (Child)); + Addr addr <- dataPrefetcher.getNextPrefetchAddr; + cRqT cRq = LLRq { + addr: addr, + fromState: I, + toState: E, + canUpToE: True, + child: 0, + byteEn: ?, + id: Child (?) + }; + // setup new MSHR entry + cRqIndexT n <- cRqMshr.transfer.getEmptyEntryInit(cRq, Invalid); + // send to pipeline + pipeline.send(CRq (LLPipeCRqIn { + addr: cRq.addr, + mshrIdx: n + })); + cRqIsPrefetch[n] <= True; + // change round robin + flipPriorNewCRqSrc; + if (verbose) + $display("%t LL %m createDataPrefetchRq: ", $time, + fshow(n), " ; ", + fshow(cRq) + ); + endrule + + // insert new cRq from child to MSHR and send to pipeline + rule createInstrPrefetchRq(newCRqSrc == Valid (Child)); + Addr addr <- instrPrefetcher.getNextPrefetchAddr; + cRqT cRq = LLRq { + addr: addr, + fromState: I, + toState: S, + canUpToE: True, + child: 1, + byteEn: ?, + id: Child (?) + }; + // setup new MSHR entry + cRqIndexT n <- cRqMshr.transfer.getEmptyEntryInit(cRq, Invalid); + // send to pipeline + pipeline.send(CRq (LLPipeCRqIn { + addr: cRq.addr, + mshrIdx: n + })); + cRqIsPrefetch[n] <= True; + // change round robin + flipPriorNewCRqSrc; + if (verbose) + $display("%t LL %m createInstrPrefetchRq: ", $time, + fshow(n), " ; ", + fshow(cRq) + ); + endrule + `ifdef PERF_COUNT // perf stats: insert new cRq fails because of full MSHR rule cRqTransfer_new_child_block( @@ -467,7 +541,7 @@ endfunction !cRqRetryIndexQ.notEmpty && newCRqSrc == Valid (Dma) && doStats ); dmaRqT r = rqFromDmaQ.first; - Bool write = r.byteEn != replicate(False); + Bool write = r.byteEn != replicate(replicate(False)); cRqT cRq = LLRq { addr: r.addr, fromState: I, @@ -534,7 +608,8 @@ endfunction fshow(cSlot), " ; " ); // performance counter: normal miss lat and cnt - incrMissCnt(n, False); + // Check lowest bit of child ID to determine if this was an ICache access + incrMissCnt(n, False, cRq.child[0] == 1); endrule // this mem resp is just for a DMA req, won't go into pipeline to refill cache @@ -547,7 +622,7 @@ endfunction cRqMshr.mRsDeq.setData(mRs.id.mshrIdx, Valid (mRs.data)); rsLdToDmaIndexQ_mRsDeq.enq(mRs.id.mshrIdx); // performance counter: dma miss lat and cnt - incrMissCnt(mRs.id.mshrIdx, True); + incrMissCnt(mRs.id.mshrIdx, True, False); endrule // send rd/wr to mem @@ -709,7 +784,7 @@ endfunction endrule // send upgrade resp to child - rule sendRsToC(rsToCIndexQ.notEmpty); + rule sendRsToC(rsToCIndexQ.notEmpty && !cRqIsPrefetch[rsToCIndexQ.first.cRqId]); // send upgrade resp to child rsToCIndexQ.deq; cRqIndexT n = rsToCIndexQ.first.cRqId; @@ -745,6 +820,13 @@ endfunction `endif endrule + rule discardPrefetchRqResult(rsToCIndexQ.notEmpty && cRqIsPrefetch[rsToCIndexQ.first.cRqId]); + let n = rsToCIndexQ.first.cRqId; + $display("%t LL %m discardPrefetchRqResult: ", $time, fshow(n)); + rsToCIndexQ.deq; + cRqMshr.sendRsToDmaC.releaseEntry(n); + endrule + // send downgrade req to child // round robin select cRq to downgrade child // but downgrade must wait for all upgrade resp @@ -886,7 +968,11 @@ endfunction cRqMshr.pipelineResp.setData(n, ram.info.dir[cRq.child] <= T ? Valid (ram.line) : Invalid); // update child dir dirT newDir = ram.info.dir; - newDir[cRq.child] = toState; + if (!cRqIsPrefetch[n]) begin + //Only update dir if not a prefetch request, since + //Prerefetch request results don't get handed down to children, + newDir[cRq.child] = toState; + end // update cs (may have E -> M) Msi newCs = ram.info.cs; if(toState == M) begin @@ -910,6 +996,14 @@ endfunction }, line: ram.line // use line in ram }, True); // hit, so update rep info + if (!cRqIsPrefetch[n]) begin + if (cRq.child[0] == 1) begin + instrPrefetcher.reportHit(cRq.addr); + end + else begin + dataPrefetcher.reportHit(cRq.addr); + end + end endaction endfunction @@ -1103,6 +1197,14 @@ endfunction }, line: ram.line }, False); + if (!cRqIsPrefetch[n]) begin + if (cRq.child[0] == 1) begin + instrPrefetcher.reportMiss(cRq.addr); + end + else begin + dataPrefetcher.reportMiss(cRq.addr); + end + end endaction endfunction @@ -1171,6 +1273,14 @@ endfunction dirPend: dirPend }); end + if (!cRqIsPrefetch[n]) begin + if (cRq.child[0] == 1) begin + instrPrefetcher.reportMiss(cRq.addr); + end + else begin + dataPrefetcher.reportMiss(cRq.addr); + end + end endaction endfunction @@ -1538,6 +1648,8 @@ endfunction LLCDmaMemLdLat: dmaMemLdLat; LLCNormalMemLdCnt: normalMemLdCnt; LLCNormalMemLdLat: normalMemLdLat; + LLCInstructionLdCnt: instructionLdCnt; + LLCInstructionLdLat: instructionLdLat; LLCMshrBlockCycles: mshrBlocks; LLCDownRespCnt: downRespCnt; LLCDownRespDataCnt: downRespDataCnt; diff --git a/src_Core/RISCY_OOO/coherence/src/Prefetcher.bsv b/src_Core/RISCY_OOO/coherence/src/Prefetcher.bsv new file mode 100644 index 0000000..6529ed6 --- /dev/null +++ b/src_Core/RISCY_OOO/coherence/src/Prefetcher.bsv @@ -0,0 +1,542 @@ +import ISA_Decls :: *; +import CacheUtils::*; +import CCTypes::*; +import Types::*; +import Vector::*; + +interface Prefetcher; + method Action reportHit(Addr hitAddr); + method Action reportMiss(Addr missAddr); + method ActionValue#(Addr) getNextPrefetchAddr(); + //method Action flush; + //method Bool flush_done; +endinterface + +module mkTestPrefetcher(Prefetcher); + Reg#(Addr) lastMissAddr <- mkReg(0); + Reg#(Bit#(2)) reqSent <- mkReg(0); + method Action reportHit(Addr hitAddr); + $display("%t I Prefetcher reportHit %h", $time, hitAddr); + endmethod + method Action reportMiss(Addr missAddr); + $display("%t I Prefetcher reportMiss %h", $time, missAddr); + if (missAddr == 'h0000000080000040) + lastMissAddr <= missAddr; + endmethod + method ActionValue#(Addr) getNextPrefetchAddr if (reqSent < 2 && lastMissAddr == 'h0000000080000040); + $display("%t I Prefetcher getNextPrefetchAddr", $time); + reqSent <= reqSent + 1; + if (reqSent == 0) begin + return 64'h0000000080000080; + end + else begin + return 64'h00000000800000c0; + end + endmethod +endmodule + +module mkDoNothingPrefetcher(Prefetcher); + method Action reportHit(Addr hitAddr); + endmethod + method Action reportMiss(Addr missAddr); + endmethod + method ActionValue#(Addr) getNextPrefetchAddr if (False); + return 64'h0000000080000080; + endmethod +endmodule + +module mkPrintPrefetcher(Prefetcher); + method Action reportHit(Addr hitAddr); + $display("%t PrintPrefetcher reportHit %h", $time, hitAddr); + endmethod + method Action reportMiss(Addr missAddr); + $display("%t PrintPrefetcher reportMiss %h", $time, missAddr); + endmethod + method ActionValue#(Addr) getNextPrefetchAddr if (False); + return 64'h0000000080000080; + endmethod +endmodule + +typedef 3 INextLinesOnMiss; +typedef 0 DNextLinesOnMiss; + +module mkNextLineOnMissPrefetcher(Prefetcher) + provisos ( + Alias#(rqCntT, Bit#(TLog#(TAdd#(INextLinesOnMiss, 1)))) + ); + Reg#(Addr) lastMissAddr <- mkReg(0); + Reg#(rqCntT) sentRequestCounter <- mkReg(fromInteger(valueOf(INextLinesOnMiss))); + method Action reportHit(Addr hitAddr); + $display("%t Prefetcher reportHit %h", $time, hitAddr); + endmethod + method Action reportMiss(Addr missAddr); + $display("%t Prefetcher reportMiss %h", $time, missAddr); + lastMissAddr <= missAddr; + sentRequestCounter <= 0; + endmethod + method ActionValue#(Addr) getNextPrefetchAddr if (sentRequestCounter < fromInteger(valueOf(INextLinesOnMiss))); + sentRequestCounter <= sentRequestCounter + 1; + let addrToRequest = lastMissAddr + (zeroExtend(sentRequestCounter) + 1)*fromInteger(valueOf(DataSz)); + $display("%t Prefetcher getNextPrefetchAddr requesting %h", $time, addrToRequest); + return addrToRequest; + endmethod +endmodule + +module mkNextLineOnAllPrefetcher(Prefetcher) + provisos ( + Alias#(rqCntT, Bit#(TLog#(TAdd#(INextLinesOnMiss, 1)))) + ); + Reg#(Addr) lastMissAddr <- mkReg(0); + Reg#(rqCntT) sentRequestCounter <- mkReg(fromInteger(valueOf(INextLinesOnMiss))); + method Action reportHit(Addr hitAddr); + $display("%t Prefetcher reportHit %h", $time, hitAddr); + lastMissAddr <= hitAddr; + sentRequestCounter <= 0; + endmethod + method Action reportMiss(Addr missAddr); + $display("%t Prefetcher reportMiss %h", $time, missAddr); + lastMissAddr <= missAddr; + sentRequestCounter <= 0; + endmethod + method ActionValue#(Addr) getNextPrefetchAddr if (sentRequestCounter < fromInteger(valueOf(INextLinesOnMiss))); + sentRequestCounter <= sentRequestCounter + 1; + let addrToRequest = lastMissAddr + (zeroExtend(sentRequestCounter) + 1)*fromInteger(valueOf(DataSz)); + $display("%t Prefetcher getNextPrefetchAddr requesting %h", $time, addrToRequest); + return addrToRequest; + endmethod +endmodule + +module mkNextLinePrefetcherBackwards(Prefetcher) + provisos ( + Alias#(rqCntT, Bit#(TLog#(TAdd#(DNextLinesOnMiss, 1)))) + ); + Reg#(Addr) lastMissAddr <- mkReg(0); + Reg#(rqCntT) sentRequestCounter <- mkReg(fromInteger(valueOf(DNextLinesOnMiss))); + method Action reportHit(Addr hitAddr); + $display("%t Prefetcher reportHit %h", $time, hitAddr); + endmethod + method Action reportMiss(Addr missAddr); + $display("%t Prefetcher reportMiss %h", $time, missAddr); + lastMissAddr <= missAddr; + sentRequestCounter <= 0; + endmethod + method ActionValue#(Addr) getNextPrefetchAddr if (sentRequestCounter < fromInteger(valueOf(DNextLinesOnMiss))); + sentRequestCounter <= sentRequestCounter + 1; + let addrToRequest = lastMissAddr - (zeroExtend(sentRequestCounter) + 1)*fromInteger(valueOf(DataSz)); + $display("%t Prefetcher getNextPrefetchAddr requesting %h", $time, addrToRequest); + return addrToRequest; + endmethod +endmodule + +module mkSingleWindowPrefetcher(Prefetcher); + Integer cacheLinesInRange = 3; + Reg#(LineAddr) rangeEnd <- mkReg(0); //Points to one CLine after end of range + Reg#(LineAddr) nextToAsk <- mkReg(0); + method Action reportHit(Addr hitAddr); + let cl = getLineAddr(hitAddr); + if (rangeEnd - fromInteger(cacheLinesInRange) - 1 < cl && cl < rangeEnd) begin + let nextEnd = cl + fromInteger(cacheLinesInRange) + 1; + $display("%t Prefetcher reportHit %h, moving window end to %h", $time, hitAddr, Addr'{nextEnd, '0}); + rangeEnd <= nextEnd; + end + endmethod + method Action reportMiss(Addr missAddr); + $display("%t Prefetcher reportMiss %h", $time, missAddr); + nextToAsk <= getLineAddr(missAddr) + 1; + rangeEnd <= getLineAddr(missAddr) + fromInteger(cacheLinesInRange) + 1; + //LgLineSzBytes + endmethod + method ActionValue#(Addr) getNextPrefetchAddr if (nextToAsk != rangeEnd); + nextToAsk <= nextToAsk + 1; + let retAddr = Addr'{nextToAsk, '0}; //extend cache line address to regular address + $display("%t Prefetcher getNextPrefetchAddr requesting %h", $time, retAddr); + return retAddr; + endmethod +endmodule + + +typedef struct { + LineAddr rangeEnd; + LineAddr nextToAsk; +} StreamEntry deriving (Bits); + +typedef 4 NumWindows; + +module mkMultiWindowPrefetcher(Prefetcher) +provisos( + Alias#(windowIdxT, Bit#(TLog#(NumWindows))) +); + Integer cacheLinesInRange = 2; + Vector#(NumWindows, Reg#(StreamEntry)) streams + <- replicateM(mkReg(StreamEntry {rangeEnd: '0, nextToAsk: '0})); + Vector#(NumWindows, Reg#(windowIdxT)) shiftReg <- genWithM(compose(mkReg, fromInteger)); + + //function + function Action moveWindowToFront(windowIdxT window) = + action + if (shiftReg[0] == window) begin + end + else if (shiftReg[1] == window) begin + shiftReg[0] <= window; + shiftReg[1] <= shiftReg[0]; + end + else if (shiftReg[2] == window) begin + shiftReg[0] <= window; + shiftReg[1] <= shiftReg[0]; + shiftReg[2] <= shiftReg[1]; + end + else if (shiftReg[3] == window) begin + shiftReg[0] <= window; + shiftReg[1] <= shiftReg[0]; + shiftReg[2] <= shiftReg[1]; + shiftReg[3] <= shiftReg[2]; + end + endaction; + + function ActionValue#(Maybe#(windowIdxT)) getMatchingWindow(Addr addr) = + actionvalue + //Finds the first window that contains addr, + //and moves it to the front of the LRU shift reg + let cl = getLineAddr(addr); + function Bool pred(StreamEntry se); + //TODO < gives 100 cycles less?????? + return (se.rangeEnd - fromInteger(cacheLinesInRange) - 1 <= cl + && cl < se.rangeEnd); + endfunction + //Find first window that contains cache line cl + if (findIndex(pred, readVReg(streams)) matches tagged Valid .idx) begin + return Valid(pack(idx)); + end + else begin + return Invalid; + end + endactionvalue; + + method Action reportHit(Addr hitAddr); + //Check if any stream line matches request + //if so, advance that stream line + //also advance LRU shift reg + let idxMaybe <- getMatchingWindow(hitAddr); + if (idxMaybe matches tagged Valid .idx) begin + moveWindowToFront(pack(idx)); //Update window as just used + let newRangeEnd = getLineAddr(hitAddr) + fromInteger(cacheLinesInRange) + 1; + streams[idx].rangeEnd <= newRangeEnd; + $display("%t Prefetcher reportHit %h, moving window end to %h for window idx %h", + $time, hitAddr, Addr'{newRangeEnd, '0}, idx); + end + else begin + $display("%t Prefetcher reportHit %h, no matching window found.", + $time, hitAddr); + end + endmethod + + method Action reportMiss(Addr missAddr); + //Check if any stream line matches request + //If so, advance that stream line and advance LRU shift reg + //Otherwise, allocate new stream line, and shift LRU reg completely, + let idxMaybe <- getMatchingWindow(missAddr); + if (idxMaybe matches tagged Valid .idx) begin + moveWindowToFront(pack(idx)); //Update window as just used + let newRangeEnd = getLineAddr(missAddr) + fromInteger(cacheLinesInRange) + 1; + //Also refresh nextToAsk on miss + streams[idx] <= + StreamEntry {nextToAsk: getLineAddr(missAddr) + 1, + rangeEnd: newRangeEnd}; + $display("%t Prefetcher reportMiss %h, moving window end to %h for window idx %h", + $time, missAddr, Addr'{newRangeEnd, '0}, idx); + end + else begin + $display("%t Prefetcher reportMiss %h, allocating new stream, idx %h", $time, missAddr, shiftReg[3]); + streams[shiftReg[3]] <= + StreamEntry {nextToAsk: getLineAddr(missAddr) + 1, + rangeEnd: getLineAddr(missAddr) + fromInteger(cacheLinesInRange) + 1}; + shiftReg[0] <= shiftReg[3]; + shiftReg[1] <= shiftReg[0]; + shiftReg[2] <= shiftReg[1]; + shiftReg[3] <= shiftReg[2]; + end + endmethod + + method ActionValue#(Addr) getNextPrefetchAddr + if (streams[shiftReg[0]].nextToAsk != streams[shiftReg[0]].rangeEnd); + + streams[shiftReg[0]].nextToAsk <= streams[shiftReg[0]].nextToAsk + 1; + let retAddr = Addr'{streams[shiftReg[0]].nextToAsk, '0}; //extend cache line address to regular address + $display("%t Prefetcher getNextPrefetchAddr requesting %h from window idx %h", $time, retAddr, shiftReg[0]); + return retAddr; + endmethod + +endmodule + +interface PCPrefetcher; + method Action reportAccess(Addr addr, Bit#(16) pcHash, HitOrMiss hitMiss); + method ActionValue#(Addr) getNextPrefetchAddr(); +endinterface + +module mkDoNothingPCPrefetcher(PCPrefetcher); + method Action reportAccess(Addr addr, Bit#(16) pcHash, HitOrMiss hitMiss); + endmethod + method ActionValue#(Addr) getNextPrefetchAddr if (False); + return 64'h0000000080000080; + endmethod +endmodule + +module mkPrintPCPrefetcher(PCPrefetcher); + method Action reportAccess(Addr addr, Bit#(16) pcHash, HitOrMiss hitMiss); + if (hitMiss == HIT) + $display("%t PCPrefetcher reportHit %h", $time, addr); + else + $display("%t PCPrefetcher reportMiss %h", $time, addr); + endmethod + method ActionValue#(Addr) getNextPrefetchAddr if (False); + return 64'h0000000080000080; + endmethod +endmodule + +typedef enum { + EMPTY = 2'b00, INIT = 2'b01, TRANSIENT = 2'b10, STEADY = 2'b11 +} StrideState deriving (Bits, Eq, FShow); + +typedef enum { + HIT = 1'b0, MISS = 1'b1 +} HitOrMiss deriving (Bits, Eq, FShow); + +typedef struct { + Addr lastAddr; //TODO maybe store less bits here? + Bit#(13) stride; + StrideState state; + Bit#(4) lastPrefetch; //Stores how many strides ahead of lastAddr was the last prefetch done +} StrideEntry deriving (Bits, Eq, FShow); + +typedef 8 HistoryLen; +typedef 64 StrideTableSize; +typedef 4 StridesAheadToPrefetch; +module mkStridePCPrefetcher(PCPrefetcher) +provisos( + Alias#(strideTableIndexT, Bit#(TLog#(StrideTableSize))) + ); + Reg#(Vector#(HistoryLen, strideTableIndexT)) historyVec <- mkReg(replicate(?)); + Vector#(StrideTableSize, Reg#(StrideEntry)) strideTable <- replicateM(mkReg(unpack(0))); + + function Maybe#(strideTableIndexT) getNextPrefetchIndex; + function Bool canPrefetch(strideTableIndexT idx); + return (strideTable[idx].state == STEADY && + strideTable[idx].lastPrefetch != fromInteger(valueof(StridesAheadToPrefetch))); + endfunction + + //Find first entry that allows more prefetches + case (find(canPrefetch, historyVec)) matches + tagged Valid .idx: return Valid(pack(idx)); + Invalid: return Invalid; + endcase + endfunction + + method ActionValue#(Addr) getNextPrefetchAddr if + (getNextPrefetchIndex() matches tagged Valid .idx); + //could store some most recent table entries, + //then check if any of those entries can be prefetched more + + //could just store the recent table entries in a circular buffer with duplication + // since shouldn't have duplicates within one loop iteration + // but we need to access all entries (or have rule that discards first entry, it we can't prefetch for it) + Reg#(StrideEntry) se = strideTable[idx]; + se.lastPrefetch <= se.lastPrefetch + 1; + return se.lastAddr + (signExtend(se.stride) * zeroExtend(se.lastPrefetch + 1)); + endmethod + method Action reportAccess(Addr addr, Bit#(16) pcHash, HitOrMiss hitMiss); + //Find slot in vector + //if miss and slot empty + //if slot init, put address, stride and move to transit + //if slot transit or steady, verify stride, and move to steady + // also put last_prefetched + //if stride wrong, move to transit + strideTableIndexT index = truncate(pcHash); + Reg#(StrideEntry) se = strideTable[index]; + StrideEntry seNext = se; + $writeh("Prefetcher: ", + fshow(hitMiss), " ", addr, + ". Entry state is ", fshow(se.state)); + + if (hitMiss == MISS && se.state == EMPTY) begin + seNext.lastAddr = addr; + seNext.state = INIT; + $display(", allocate entry"); + end + else if (se.state == INIT) begin + seNext.stride = truncate(addr - se.lastAddr); + seNext.state = TRANSIENT; + seNext.lastAddr = addr; + $display(", set stride to %h", seNext.stride); + end + else if (se.state == TRANSIENT || se.state == STEADY) begin + if (truncate(addr - se.lastAddr) == se.stride) begin + case (se.state) + TRANSIENT: seNext.lastPrefetch = 0; + STEADY: seNext.lastPrefetch = (seNext.lastPrefetch == 0) ? 0 : se.lastPrefetch - 1; + endcase + seNext.state = STEADY; + seNext.lastAddr = addr; + historyVec <= shiftInAt0(historyVec, index); + $display(", stride %h is confirmed!", seNext.stride); + end + else begin + seNext.state = TRANSIENT; + seNext.stride = truncate(addr - se.lastAddr); + seNext.lastAddr = addr; + $display(", old stride is broken! New stride: %h", seNext.stride); + end + end + se <= seNext; + endmethod +endmodule + +typedef struct { + Bit#(12) lastAddr; //TODO maybe store less bits here? + Bit#(13) stride; + StrideState state; + Bit#(4) cLinesPrefetched; //Stores how many cache lines have been prefetched for this instruction +} StrideEntry2 deriving (Bits, Eq, FShow); + +typedef 3 CLinesAheadToPrefetch; + +module mkStridePCPrefetcher2(PCPrefetcher) +provisos( + Alias#(strideTableIndexT, Bit#(TLog#(StrideTableSize))), + Alias#(historyVecIndexT, Bit#(TLog#(HistoryLen))) + ); + Reg#(Vector#(HistoryLen, Tuple2#(strideTableIndexT, Addr))) historyVec <- mkReg(replicate(?)); + Vector#(StrideTableSize, Reg#(StrideEntry2)) strideTable <- replicateM(mkReg(unpack(0))); + + function Maybe#(historyVecIndexT) getNextPrefetchHistoryIndex; + function Bool canPrefetch(Tuple2#(strideTableIndexT, Addr) entry); + strideTableIndexT idx = tpl_1(entry); + return (strideTable[idx].state == STEADY && + strideTable[idx].cLinesPrefetched != + fromInteger(valueof(CLinesAheadToPrefetch))); + endfunction + + //Find first entry that allows more prefetches + case (findIndex(canPrefetch, historyVec)) matches + tagged Valid .historyIdx: return Valid(pack(historyIdx)); + Invalid: return Invalid; + endcase + endfunction + + method ActionValue#(Addr) getNextPrefetchAddr if + (getNextPrefetchHistoryIndex() matches tagged Valid .historyIdx); + match {.strideIdx, .fullAddr} = historyVec[historyIdx]; + Reg#(StrideEntry2) se = strideTable[strideIdx]; + se.cLinesPrefetched <= se.cLinesPrefetched + 1; + Bit#(13) strideToUse; + Bit#(13) cLineSize = fromInteger(valueof(DataSz)); + if (se.stride[12] == 1 && se.stride > -cLineSize) begin + //stride is negative and jumps less than one cline + strideToUse = -cLineSize; + end + else if (se.stride[12] == 0 && se.stride < cLineSize) begin + //stride is positive and jumps less than one cline + strideToUse = cLineSize; + end + else + strideToUse = se.stride; + + let reqAddr = fullAddr + + (signExtend(strideToUse) * zeroExtend(se.cLinesPrefetched + 1)); + $display("%t Stride Prefetcher getNextPrefetchAddr requesting %h for entry %h", $time, reqAddr, strideIdx); + return reqAddr; + endmethod + method Action reportAccess(Addr addr, Bit#(16) pcHash, HitOrMiss hitMiss); + //Find slot in vector + //if miss and slot empty + //if slot init, put address, stride and move to transit + //if slot transit or steady, verify stride, and move to steady + // also put last_prefetched + //if stride wrong, move to transit + strideTableIndexT index = truncate(pcHash); + Reg#(StrideEntry2) se = strideTable[index]; + StrideEntry2 seNext = se; + Bit#(13) observedStride = {1'b0, addr[11:0]} - {1'b0, se.lastAddr}; + $writeh("%t Stride Prefetcher reportAccess ", $time, + fshow(hitMiss), " ", addr, + ". Entry ", index, " state is ", fshow(se.state)); + if (se.state == EMPTY) begin + if (hitMiss == MISS) begin + seNext.lastAddr = truncate(addr); + seNext.state = INIT; + $display(", allocate entry"); + end + else begin + $display(", ignore"); + end + end + else if (se.state == INIT && observedStride != 0) begin + seNext.stride = observedStride; + seNext.state = TRANSIENT; + seNext.lastAddr = truncate(addr); + $display(", set stride to %h", seNext.stride); + end + else if ((se.state == TRANSIENT || se.state == STEADY) && observedStride != 0) begin + if (observedStride == se.stride) begin + if (se.state == TRANSIENT) begin + //Here we transition from TRANSIENT to STEADY, so init this field + seNext.cLinesPrefetched = 0; + end + else begin + //state == STEADY + if (se.lastAddr[11:6] != addr[11:6]) begin + //This means we have crossed a cache line since last access + seNext.cLinesPrefetched = + (se.cLinesPrefetched == 0) ? 0 : se.cLinesPrefetched - 1; + end + end + seNext.state = STEADY; + seNext.lastAddr = truncate(addr); + historyVec <= shiftInAt0(historyVec, tuple2(index, addr)); + $display(", stride %h is confirmed!", seNext.stride); + end + else begin + seNext.state = TRANSIENT; + seNext.stride = observedStride; + seNext.lastAddr = truncate(addr); + $display(", old stride is broken! New stride: %h", seNext.stride); + end + end + else + $display(""); + se <= seNext; + endmethod + + + +endmodule + +module mkL1IPrefetcher(Prefetcher); + //let m <- mkNextLinePrefetcher; + //let m <- mkMultiWindowPrefetcher; + //let m <- mkNextLineOnAllPrefetcher; + let m <- mkDoNothingPrefetcher; + return m; +endmodule + +module mkL1DPrefetcher(PCPrefetcher); + //let m <- mkNextLineOnAllPrefetcher; + //let m <- mkStridePCPrefetcher2; + let m <- mkDoNothingPCPrefetcher; + return m; +endmodule + +module mkLLIPrefetcher(Prefetcher); + //let m <- mkNextLineOnMissPrefetcher; + let m <- mkMultiWindowPrefetcher; + //let m <- mkStridePCPrefetcher2; + //let m <- mkPrintPrefetcher; + //let m <- mkDoNothingPrefetcher; + return m; +endmodule + +module mkLLDPrefetcher(Prefetcher); + //let m <- mkNextLineOnAllPrefetcher; + let m <- mkPrintPrefetcher; + //let m <- mkDoNothingPrefetcher; + return m; +endmodule \ No newline at end of file diff --git a/src_Core/RISCY_OOO/coherence/src/test/Prefetcher_test.bsv b/src_Core/RISCY_OOO/coherence/src/test/Prefetcher_test.bsv new file mode 100644 index 0000000..5b4c012 --- /dev/null +++ b/src_Core/RISCY_OOO/coherence/src/test/Prefetcher_test.bsv @@ -0,0 +1,249 @@ +import Prefetcher::*; +import StmtFSM::*; +import Types::*; + + +module mkMultiWindowPrefetcherTest(Empty); + //let p <- mkMultipleWindowPrefetcher; + //TODO pass in value of cachelinesinrange + let p <- mkMultiWindowPrefetcher; + mkAutoFSM( + seq + // ----- Send misses and stuff to one window ----- + action + p.reportMiss('h80000040); + endaction + action + let x <- p.getNextPrefetchAddr; + doAssert(x == 'h80000080, "test fail!"); + endaction + action + let x <- p.getNextPrefetchAddr; + doAssert(x == 'h800000c0, "test fail!"); + endaction + action + p.reportHit('h800000c0); //Report hit inside window + endaction + action + let x <- p.getNextPrefetchAddr; + doAssert(x == 'h80000100, "test fail!"); + endaction + action + p.reportHit('h80004000); //Report hit outside window + endaction + action + let x <- p.getNextPrefetchAddr; //Previous window still recommended + doAssert(x == 'h80000140, "test fail!"); + endaction + action + p.reportMiss('h80000140); //Report miss inside window + endaction + action + let x <- p.getNextPrefetchAddr; //Previous window still recommended + doAssert(x == 'h80000180, "test fail!"); + endaction + + // ----- Allocate other windows ----- + action + p.reportMiss('h70000000); //Report miss outside window + endaction + action + let x <- p.getNextPrefetchAddr; //new window recommended + doAssert(x == 'h70000040, "test fail!"); + endaction + action + p.reportMiss('h90000000); //Report miss outside window + endaction + action + let x <- p.getNextPrefetchAddr; //new window recommended + doAssert(x == 'h90000040, "test fail!"); + endaction + action + p.reportMiss('h60000000); //Report miss outside window + endaction + action + let x <- p.getNextPrefetchAddr; //new window recommended + doAssert(x == 'h60000040, "test fail!"); + endaction + action + p.reportHit('h80000180); //Report hit inside oldest window + endaction + action + let x <- p.getNextPrefetchAddr; //oldest window recommended + doAssert(x == 'h800001c0, "test fail!"); + endaction + + // ----- Trigger window deletion ----- + action + p.reportMiss('h50000000); //Report miss outside window, + //discard window with 'h70.. + endaction + action + let x <- p.getNextPrefetchAddr; //new window recommended + doAssert(x == 'h50000040, "test fail!"); + endaction + action + p.reportHit('h70000040); //Report hit inside now deleted window + endaction + action + let x <- p.getNextPrefetchAddr; //most recent window still recommended + doAssert(x == 'h50000080, "test fail!"); + endaction + + // ----- Reorder some more windows around + action + p.reportMiss('h800001c0); //Report hit inside now deleted window + endaction + action + let x <- p.getNextPrefetchAddr; //most recent window still recommended + doAssert(x == 'h80000200, "test fail!"); + endaction + + + endseq + ); +endmodule + + +module mkStridePCPrefetcher2Test(Empty); + //let p <- mkMultipleWindowPrefetcher; + //TODO pass in value of cachelinesinrange + let p <- mkStridePCPrefetcher2; + mkAutoFSM( + seq + // ----- Send misses and stuff to one window ----- + action p.reportAccess('h80000040, 'h0069, MISS); endaction + action p.reportAccess('h80000080, 'h0069, HIT); endaction + action p.reportAccess('h800000a0, 'h0069, HIT); endaction + action p.reportAccess('h800000c0, 'h0069, MISS); endaction + action p.reportAccess('h800000e0, 'h0069, MISS); endaction + action + let x <- p.getNextPrefetchAddr; + doAssert(x == 'h80000120, "test fail!"); + endaction + action p.reportAccess('h80000100, 'h0069, HIT); endaction + action p.reportAccess('h80000120, 'h0069, HIT); endaction + action p.reportAccess('h80000140, 'h0069, HIT); endaction + action + let x <- p.getNextPrefetchAddr; + doAssert(x == 'h80000180, "test fail!"); + endaction + action + let x <- p.getNextPrefetchAddr; + doAssert(x == 'h800001c0, "test fail!"); + endaction + action + let x <- p.getNextPrefetchAddr; + doAssert(x == 'h80000200, "test fail!"); + endaction + action p.reportAccess('h900001f0, 'h006a, MISS); endaction + action p.reportAccess('h900001c0, 'h006a, HIT); endaction + action p.reportAccess('h90000190, 'h006a, HIT); endaction + action + let x <- p.getNextPrefetchAddr; + doAssert(x == 'h90000150, "test fail!"); + endaction + action + let x <- p.getNextPrefetchAddr; + doAssert(x == 'h90000110, "test fail!"); + endaction + action p.reportAccess('h90000100, 'h006b, MISS); endaction + action p.reportAccess('h90000200, 'h006b, MISS); endaction + action p.reportAccess('h90000300, 'h006b, MISS); endaction + action + let x <- p.getNextPrefetchAddr; + doAssert(x == 'h90000400, "test fail!"); + endaction + action + let x <- p.getNextPrefetchAddr; + doAssert(x == 'h90000500, "test fail!"); + endaction + action p.reportAccess('h90000160, 'h006a, HIT); endaction + // -- use older entry + action + let x <- p.getNextPrefetchAddr; + doAssert(x == 'h900000e0, "test fail!"); + endaction + action + let x <- p.getNextPrefetchAddr; + doAssert(x == 'h900000a0, "test fail!"); + endaction + action + let x <- p.getNextPrefetchAddr; + doAssert(x == 'h90000600, "test fail!"); + endaction + endseq + ); +endmodule + + +module mkStridePCPrefetcherTest(Empty); + //let p <- mkMultipleWindowPrefetcher; + //TODO pass in value of cachelinesinrange + let p <- mkStridePCPrefetcher; + mkAutoFSM( + seq + // ----- Send misses and stuff to one window ----- + action + p.reportAccess('h80000040, 'h0069, MISS); + endaction + action + p.reportAccess('h80000080, 'h0069, HIT); + endaction + action + p.reportAccess('h800000a0, 'h0069, HIT); + endaction + action + p.reportAccess('h800000c0, 'h0069, MISS); + endaction + action + let x <- p.getNextPrefetchAddr; + doAssert(x == 'h80000100, "test fail!"); + endaction + action + let x <- p.getNextPrefetchAddr; + doAssert(x == 'h80000140, "test fail!"); + endaction + action + p.reportAccess('h800000e0, 'h0069, MISS); + endaction + action + let x <- p.getNextPrefetchAddr; + doAssert(x == 'h80000180, "test fail!"); + endaction + action + p.reportAccess('h80000100, 'h0069, MISS); + endaction + action + p.reportAccess('h80000120, 'h0069, MISS); + endaction + action + p.reportAccess('h80000140, 'h0069, MISS); + endaction + action + let x <- p.getNextPrefetchAddr; + doAssert(x == 'h80000160, "test fail!"); + endaction + action + p.reportAccess('h90000040, 'h0000, MISS); + endaction + action + p.reportAccess('h90000140, 'h0000, MISS); + endaction + action + p.reportAccess('h90000240, 'h0000, MISS); + endaction + action + let x <- p.getNextPrefetchAddr; + doAssert(x == 'h90000340, "test fail!"); + endaction + action + p.reportAccess('h80000160, 'h0069, MISS); + endaction + action + let x <- p.getNextPrefetchAddr; + doAssert(x == 'h80000180, "test fail!"); + endaction + endseq + ); +endmodule \ No newline at end of file diff --git a/src_Core/RISCY_OOO/procs/RV64G_OOO/MemExePipeline.bsv b/src_Core/RISCY_OOO/procs/RV64G_OOO/MemExePipeline.bsv index 4a8c473..8372de7 100644 --- a/src_Core/RISCY_OOO/procs/RV64G_OOO/MemExePipeline.bsv +++ b/src_Core/RISCY_OOO/procs/RV64G_OOO/MemExePipeline.bsv @@ -328,12 +328,12 @@ module mkMemExePipeline#(MemExeInput inIfc)(MemExePipeline); Fifo#(1, WaitStResp) waitStRespQ <- mkCFFifo; `endif // fifo for req mem - Fifo#(1, Tuple3#(LdQTag, Addr, Bool)) reqLdQ <- mkBypassFifo; + Fifo#(1, Tuple4#(LdQTag, Addr, Bool, Bit#(16))) reqLdQ <- mkBypassFifo; Fifo#(1, ProcRq#(DProcReqId)) reqLrScAmoQ <- mkBypassFifo; `ifdef TSO_MM - Fifo#(1, Addr) reqStQ <- mkBypassFifo; + Fifo#(1, Tuple2#(Addr, Bit#(16))) reqStQ <- mkBypassFifo; `else - Fifo#(1, Tuple2#(SBIndex, Addr)) reqStQ <- mkBypassFifo; + Fifo#(1, Tuple2#(SBIndex, Addr, Bit#(16))) reqStQ <- mkBypassFifo; `endif // fifo for load result Fifo#(2, Tuple2#(LdQTag, MemResp)) forwardQ <- mkCFFifo; @@ -691,7 +691,6 @@ module mkMemExePipeline#(MemExeInput inIfc)(MemExePipeline); function Bool is_16b_inst (Bit #(n) inst); return (inst [1:0] != 2'b11); endfunction - let pc = inIfc.rob_getPC(x.tag); let ppc = inIfc.rob_getPredPC(x.tag); let inst = inIfc.rob_getOrig_Inst(x.tag); let validPc = is_16b_inst(inst) ? addPc(pc,2) : addPc(pc,4); @@ -702,6 +701,7 @@ module mkMemExePipeline#(MemExeInput inIfc)(MemExePipeline); end `endif `endif + let pc = inIfc.rob_getPC(x.tag); // update LSQ LSQUpdateAddrResult updRes <- lsq.updateAddr( @@ -723,7 +723,8 @@ module mkMemExePipeline#(MemExeInput inIfc)(MemExePipeline); issueLd.wset(LSQIssueLdInfo { tag: ldTag, paddr: paddr, - shiftedBE: x.shiftedBE + shiftedBE: x.shiftedBE, + pcHash: hash(getAddr(pc)) }); end @@ -779,7 +780,7 @@ module mkMemExePipeline#(MemExeInput inIfc)(MemExePipeline); `endif end else if(issRes == ToCache) begin - reqLdQ.enq(tuple3(zeroExtend(info.tag), info.paddr, info.shiftedBE == TagMemAccess)); + reqLdQ.enq(tuple4(zeroExtend(info.tag), info.paddr, info.shiftedBE == TagMemAccess, info.pcHash)); // perf: load mem latency ldMemLatTimer.start(info.tag); end @@ -955,7 +956,8 @@ module mkMemExePipeline#(MemExeInput inIfc)(MemExePipeline); byteEn: ?, data: ?, amoInst: ?, - loadTags: False + loadTags: False, + pcHash: ? }; reqLrScAmoQ.enq(req); if(verbose) $display("[doDeqLdQ_Lr_issue] ", fshow(lsqDeqLd), "; ", fshow(req)); @@ -1172,7 +1174,7 @@ module mkMemExePipeline#(MemExeInput inIfc)(MemExePipeline); ); // send to mem Addr addr = lsqDeqSt.paddr; - reqStQ.enq(addr); + reqStQ.enq(tuple2(addr, lsqDeqSt.pcHash)); // record waiting for store resp waitStRespQ.enq(WaitStResp { offset: getLineMemDataOffset(addr), @@ -1196,7 +1198,7 @@ module mkMemExePipeline#(MemExeInput inIfc)(MemExePipeline); ); lsq.deqSt; // send to SB - stb.enq(sbIdx, lsqDeqSt.paddr, lsqDeqSt.shiftedBE, lsqDeqSt.stData); + stb.enq(sbIdx, lsqDeqSt.paddr, lsqDeqSt.shiftedBE, lsqDeqSt.stData, lsqDeqSt.pcHash); // ROB should have already been set to executed if(verbose) $display("[doDeqStQ_St] ", fshow(lsqDeqSt)); // normal store should not have .rl, so no need to check SB empty @@ -1206,7 +1208,7 @@ module mkMemExePipeline#(MemExeInput inIfc)(MemExePipeline); // send store to mem rule doIssueSB; let {sbIdx, en} <- stb.issue; - reqStQ.enq(tuple2(sbIdx, {en.addr, 0})); + reqStQ.enq(tuple3(sbIdx, {en.addr, 0}, en.pcHash)); // perf: store mem latency stMemLatTimer.start(sbIdx); endrule @@ -1300,7 +1302,8 @@ module mkMemExePipeline#(MemExeInput inIfc)(MemExePipeline); aq: lsqDeqSt.acq, rl: lsqDeqSt.rel }, - loadTags: False + loadTags: False, + pcHash: ? }; reqLrScAmoQ.enq(req); if(verbose) $display("[doDeqStQ_ScAmo_issue] ", fshow(lsqDeqSt), "; ", fshow(req)); @@ -1514,7 +1517,7 @@ module mkMemExePipeline#(MemExeInput inIfc)(MemExePipeline); // send req to D$ rule sendLdToMem; - let {lsqTag, addr, loadTags} <- toGet(reqLdQ).get; + let {lsqTag, addr, loadTags, pcHash} <- toGet(reqLdQ).get; dMem.procReq.req(ProcRq { id: zeroExtend(lsqTag), addr: addr, @@ -1523,16 +1526,17 @@ module mkMemExePipeline#(MemExeInput inIfc)(MemExePipeline); byteEn: ?, data: ?, amoInst: ?, - loadTags: loadTags + loadTags: loadTags, + pcHash: pcHash }); endrule (* descending_urgency = "sendLdToMem, sendStToMem" *) // prioritize Ld over St rule sendStToMem; `ifdef TSO_MM - let addr <- toGet(reqStQ).get; + let {addr, pcHash} <- toGet(reqStQ).get; DProcReqId id = 0; `else - let {sbIdx, addr} <- toGet(reqStQ).get; + let {sbIdx, addr, pcHash} <- toGet(reqStQ).get; DProcReqId id = zeroExtend(sbIdx); `endif dMem.procReq.req(ProcRq { @@ -1543,7 +1547,8 @@ module mkMemExePipeline#(MemExeInput inIfc)(MemExePipeline); byteEn: ?, data: ?, amoInst: ?, - loadTags: False + loadTags: False, + pcHash: pcHash }); endrule (* descending_urgency = "sendLrScAmoToMem, sendStToMem" *) // prioritize Lr/Sc/Amo over St diff --git a/src_Core/RISCY_OOO/procs/RV64G_OOO/RenameStage.bsv b/src_Core/RISCY_OOO/procs/RV64G_OOO/RenameStage.bsv index 4c0950f..7405ef5 100644 --- a/src_Core/RISCY_OOO/procs/RV64G_OOO/RenameStage.bsv +++ b/src_Core/RISCY_OOO/procs/RV64G_OOO/RenameStage.bsv @@ -741,7 +741,7 @@ module mkRenameStage#(RenameInput inIfc)(RenameStage); lsq.enqLd(inst_tag, mem_inst, allow_cap, phy_regs.dst, spec_bits, hash(getAddr(pc))); end else begin - lsq.enqSt(inst_tag, mem_inst, phy_regs.dst, spec_bits); + lsq.enqSt(inst_tag, mem_inst, phy_regs.dst, spec_bits, hash(getAddr(pc))); end end else begin @@ -1075,7 +1075,7 @@ module mkRenameStage#(RenameInput inIfc)(RenameStage); lsq.enqLd(inst_tag, mem_inst, phy_regs.dst, spec_bits, hash(getAddr(pc))); end else begin - lsq.enqSt(inst_tag, mem_inst, phy_regs.dst, spec_bits); + lsq.enqSt(inst_tag, mem_inst, phy_regs.dst, spec_bits, hash(getAddr(pc))); end end else begin diff --git a/src_Core/RISCY_OOO/procs/lib/DirPredictor.bsv b/src_Core/RISCY_OOO/procs/lib/DirPredictor.bsv index 3435f02..477e379 100644 --- a/src_Core/RISCY_OOO/procs/lib/DirPredictor.bsv +++ b/src_Core/RISCY_OOO/procs/lib/DirPredictor.bsv @@ -94,7 +94,7 @@ module mkDirPredictor(DirPredictor#(DirPredTrainInfo)); `endif `ifdef DIR_PRED_TOUR -`ifdef SECURITY +`ifdef SECURITY_BRPRED let m <- mkTourPredSecure; `else let m <- mkTourPred; diff --git a/src_Core/RISCY_OOO/procs/lib/Performance.bsv b/src_Core/RISCY_OOO/procs/lib/Performance.bsv index 67e0dbe..68041e5 100644 --- a/src_Core/RISCY_OOO/procs/lib/Performance.bsv +++ b/src_Core/RISCY_OOO/procs/lib/Performance.bsv @@ -52,6 +52,8 @@ typedef enum { LLCDmaMemLdLat, LLCNormalMemLdCnt, LLCNormalMemLdLat, + LLCInstructionLdCnt, + LLCInstructionLdLat, LLCMshrBlockCycles, // full MSHR blocks new cRq LLCDownRespCnt, LLCDownRespDataCnt, diff --git a/src_Core/RISCY_OOO/procs/lib/SplitLSQ.bsv b/src_Core/RISCY_OOO/procs/lib/SplitLSQ.bsv index 8a689fb..c570cb1 100644 --- a/src_Core/RISCY_OOO/procs/lib/SplitLSQ.bsv +++ b/src_Core/RISCY_OOO/procs/lib/SplitLSQ.bsv @@ -295,6 +295,7 @@ typedef struct { LdQTag tag; Addr paddr; ByteOrTagEn shiftedBE; + Bit#(16) pcHash; } LSQIssueLdInfo deriving(Bits, Eq, FShow); typedef struct { @@ -342,6 +343,7 @@ typedef struct { MemTaggedData stData; Bool allowCapAmoLd; Maybe#(Trap) fault; + Bit#(16) pcHash; } StQDeqEntry deriving (Bits, Eq, FShow); interface SplitLSQ; @@ -354,11 +356,12 @@ interface SplitLSQ; MemInst mem_inst, Maybe#(PhyDst) dst, SpecBits spec_bits, - Bit#(16) pc_hash); + Bit#(16) pcHash); method Action enqSt(InstTag inst_tag, MemInst mem_inst, Maybe#(PhyDst) dst, - SpecBits spec_bits); + SpecBits spec_bits, + Bit#(16) pcHash); // A mem inst needs orignal BE (not shifted) at addr translation method ByteOrTagEn getOrigBE(LdStQTag t); // Retrieve information when we want to wakeup RS early in case @@ -663,7 +666,7 @@ module mkSplitLSQ(SplitLSQ); Vector#(LdQSize, Reg#(Bool)) ld_acq <- replicateM(mkConfigRegU); Vector#(LdQSize, Reg#(Bool)) ld_rel <- replicateM(mkConfigRegU); Vector#(LdQSize, Reg#(Maybe#(PhyDst))) ld_dst <- replicateM(mkConfigRegU); - Vector#(LdQSize, Reg#(Bit#(16))) ld_pc_hash <- replicateM(mkConfigRegU); + Vector#(LdQSize, Reg#(Bit#(16))) ld_pcHash <- replicateM(mkConfigRegU); Vector#(LdQSize, Reg#(Bool)) ld_waitForOlderSt <- replicateM(mkConfigRegU); Vector#(LdQSize, Ehr#(2, Addr)) ld_paddr <- replicateM(mkEhr(?)); Vector#(LdQSize, Ehr#(2, Bool)) ld_isMMIO <- replicateM(mkEhr(?)); @@ -856,6 +859,7 @@ module mkSplitLSQ(SplitLSQ); Vector#(StQSize, Reg#(Bool)) st_acq <- replicateM(mkRegU); Vector#(StQSize, Reg#(Bool)) st_rel <- replicateM(mkRegU); Vector#(StQSize, Reg#(Maybe#(PhyDst))) st_dst <- replicateM(mkRegU); + Vector#(StQSize, Reg#(Bit#(16))) st_pcHash <- replicateM(mkRegU); Vector#(StQSize, Ehr#(2, Addr)) st_paddr <- replicateM(mkEhr(?)); Vector#(StQSize, Ehr#(2, Bool)) st_isMMIO <- replicateM(mkEhr(?)); Vector#(StQSize, Ehr#(2, MemDataByteEn)) st_shiftedBE <- replicateM(mkEhr(?)); @@ -1126,7 +1130,8 @@ module mkSplitLSQ(SplitLSQ); let info = LSQIssueLdInfo { tag: tag, paddr: ld_paddr_findIss[tag], - shiftedBE: ld_shiftedBE_findIss[tag] + shiftedBE: ld_shiftedBE_findIss[tag], + pcHash: ld_pcHash[tag] }; issueLdInfo.wset(info); if(verbose) begin @@ -1458,7 +1463,7 @@ module mkSplitLSQ(SplitLSQ); MemInst mem_inst, Maybe#(PhyDst) dst, SpecBits spec_bits, - Bit#(16) pc_hash) if(ld_can_enq_wire && !wrongSpec_conflict); + Bit#(16) pcHash) if(ld_can_enq_wire && !wrongSpec_conflict); if(verbose) begin $display("[LSQ - enqLd] enqP %d; ", ld_enqP, "; ", fshow(inst_tag), @@ -1487,8 +1492,8 @@ module mkSplitLSQ(SplitLSQ); ld_executing_enq[ld_enqP] <= False; ld_done_enq[ld_enqP] <= False; ld_killed_enq[ld_enqP] <= Invalid; - ld_pc_hash[ld_enqP] <= pc_hash; - ld_waitForOlderSt[ld_enqP] <= stlPred.pred(pc_hash); + ld_pcHash[ld_enqP] <= pcHash; + ld_waitForOlderSt[ld_enqP] <= stlPred.pred(pcHash); ld_readFrom_enq[ld_enqP] <= Invalid; ld_depLdQDeq_enq[ld_enqP] <= Invalid; ld_depStQDeq_enq[ld_enqP] <= Invalid; @@ -1516,7 +1521,8 @@ module mkSplitLSQ(SplitLSQ); method Action enqSt(InstTag inst_tag, MemInst mem_inst, Maybe#(PhyDst) dst, - SpecBits spec_bits) if(st_can_enq_wire && !wrongSpec_conflict); + SpecBits spec_bits, + Bit#(16) pcHash) if(st_can_enq_wire && !wrongSpec_conflict); if(verbose) begin $display("[LSQ - enqSt] enqP %d; ", st_enqP, "; ", fshow(inst_tag), @@ -1540,6 +1546,7 @@ module mkSplitLSQ(SplitLSQ); st_rel[st_enqP] <= mem_inst.rl; st_dst[st_enqP] <= dst; st_fault_enq[st_enqP] <= Invalid; + st_pcHash[st_enqP] <= pcHash; st_allowCapAmoLd_enq[st_enqP] <= False; st_computed_enq[st_enqP] <= False; st_verified_enq[st_enqP] <= False; @@ -1716,7 +1723,7 @@ module mkSplitLSQ(SplitLSQ); LdKilledBy by = lsqTag matches tagged Ld .unuse ? Ld : St; ld_killed_updAddr[killTag] <= Valid (by); if(verbose) begin - $display("[LSQ - updateAddr] kill tag %d", killTag, " ld_hash: %x", ld_pc_hash[killTag]); + $display("[LSQ - updateAddr] kill tag %d", killTag, " ld_hash: %x", ld_pcHash[killTag]); end // checks doAssert(ld_computed_updAddr[killTag], "must be computed"); @@ -2119,7 +2126,7 @@ module mkSplitLSQ(SplitLSQ); end Bool waited = ld_waitForOlderSt[deqP]; // Don't negative train if we waited for older stores. // Update predictor. - stlPred.update(ld_pc_hash[deqP], waited, killedLd); + stlPred.update(ld_pcHash[deqP], waited, killedLd); // remove the entry ld_valid_deqLd[deqP] <= False; @@ -2152,7 +2159,8 @@ module mkSplitLSQ(SplitLSQ); shiftedBE: st_shiftedBE_deqSt[deqP], stData: st_stData_deqSt[deqP], allowCapAmoLd: st_allowCapAmoLd_deqSt[deqP], - fault: st_fault_deqSt[deqP] + fault: st_fault_deqSt[deqP], + pcHash: st_pcHash[deqP] }; endmethod diff --git a/src_Core/RISCY_OOO/procs/lib/StoreBuffer.bsv b/src_Core/RISCY_OOO/procs/lib/StoreBuffer.bsv index ec13646..5b560f9 100644 --- a/src_Core/RISCY_OOO/procs/lib/StoreBuffer.bsv +++ b/src_Core/RISCY_OOO/procs/lib/StoreBuffer.bsv @@ -68,6 +68,7 @@ typedef struct { SBBlockAddr addr; SBByteEn byteEn; CLine line; + Bit#(16) pcHash; } SBEntry deriving(Bits, Eq, FShow); // result of searching (e.g. load byass) @@ -79,7 +80,7 @@ typedef struct { interface StoreBuffer; method Bool isEmpty; method Maybe#(SBIndex) getEnqIndex(Addr paddr); - method Action enq(SBIndex idx, Addr paddr, MemDataByteEn be, MemTaggedData data); + method Action enq(SBIndex idx, Addr paddr, MemDataByteEn be, MemTaggedData data, Bit#(16) pcHash); method ActionValue#(SBEntry) deq(SBIndex idx); method ActionValue#(Tuple2#(SBIndex, SBEntry)) issue; method SBSearchRes search(Addr paddr, ByteOrTagEn be); // load bypass/stall or atomic inst stall @@ -191,7 +192,7 @@ module mkStoreBufferEhr(StoreBuffer); end endmethod - method Action enq(SBIndex idx, Addr paddr, MemDataByteEn be, MemTaggedData d) if(inited); + method Action enq(SBIndex idx, Addr paddr, MemDataByteEn be, MemTaggedData d, Bit#(16) pcHash) if(inited); // get data offset SBBlockMemDataSel sel = getSBBlockMemDataSel(paddr); // check whether the entry already exists @@ -211,7 +212,8 @@ module mkStoreBufferEhr(StoreBuffer); entry[idx][enqPort] <= SBEntry { addr: getSBBlockAddr(paddr), byteEn: unpack(pack(byteEn)), - line: block + line: block, + pcHash: pcHash }; // this entry must have been sent to issueQ end @@ -228,7 +230,8 @@ module mkStoreBufferEhr(StoreBuffer); entry[idx][enqPort] <= SBEntry { addr: getSBBlockAddr(paddr), byteEn: unpack(pack(byteEn)), - line: block + line: block, + pcHash: pcHash }; // send this entry to issueQ doAssert(issueQ.notFull, "SB issueQ should not be full"); @@ -311,7 +314,7 @@ endmodule module mkDummyStoreBuffer(StoreBuffer); method Bool isEmpty = True; method Maybe#(SBIndex) getEnqIndex(Addr paddr) = Invalid; - method Action enq(SBIndex idx, Addr paddr, MemDataByteEn be, MemTaggedData data); + method Action enq(SBIndex idx, Addr paddr, MemDataByteEn be, MemTaggedData data, Bit#(16) pcHash); doAssert(False, "enq should never be called)"); endmethod method ActionValue#(SBEntry) deq(SBIndex idx);