From 32d094082bbe6d7addc8240518533f59860576dc Mon Sep 17 00:00:00 2001 From: Jonathan Woodruff Date: Mon, 8 Jan 2024 15:28:24 +0000 Subject: [PATCH] Some tracing for performance in the memory pipeline. Also, add some ports to registers in DTLB to potentially allow single-cycle lookup. --- .../procs/RV64G_OOO/MemExePipeline.bsv | 10 +- src_Core/RISCY_OOO/procs/lib/DTlb.bsv | 99 +++++++++++-------- 2 files changed, 62 insertions(+), 47 deletions(-) diff --git a/src_Core/RISCY_OOO/procs/RV64G_OOO/MemExePipeline.bsv b/src_Core/RISCY_OOO/procs/RV64G_OOO/MemExePipeline.bsv index 662889d..df50821 100644 --- a/src_Core/RISCY_OOO/procs/RV64G_OOO/MemExePipeline.bsv +++ b/src_Core/RISCY_OOO/procs/RV64G_OOO/MemExePipeline.bsv @@ -252,7 +252,7 @@ interface MemExePipeline; endinterface module mkMemExePipeline#(MemExeInput inIfc)(MemExePipeline); - Bool verbose = False; + Bool verbose = True; // we change cache request in case of single core, becaues our MSI protocol // is not good with single core @@ -455,7 +455,7 @@ module mkMemExePipeline#(MemExeInput inIfc)(MemExePipeline); rule doDispatchMem; rsMem.doDispatch; let x = rsMem.dispatchData; - if(verbose) $display("[doDispatchMem] ", fshow(x)); + if(verbose) $display("%t : [doDispatchMem] ", $time, fshow(x)); // check store not having dst reg: this is for setting store to be // executed after address transation @@ -488,7 +488,7 @@ module mkMemExePipeline#(MemExeInput inIfc)(MemExePipeline); dispToRegQ.deq; let dispToReg = dispToRegQ.first; let x = dispToReg.data; - if(verbose) $display("[doRegReadMem] ", fshow(dispToReg)); + if(verbose) $display("%t : [doRegReadMem] ", $time, fshow(dispToReg)); // check conservative scoreboard let regsReady = inIfc.sbCons_lazyLookup(x.regs); @@ -531,7 +531,7 @@ module mkMemExePipeline#(MemExeInput inIfc)(MemExePipeline); regToExeQ.deq; let regToExe = regToExeQ.first; let x = regToExe.data; - if(verbose) $display("[doExeMem] ", fshow(regToExe)); + if(verbose) $display("%t : [doExeMem] ", $time, fshow(regToExe)); // get virtual addr & St/Sc/Amo data CapPipe vaddr = modifyOffset(x.rVal1, signExtend(x.imm), True).value; @@ -608,7 +608,7 @@ module mkMemExePipeline#(MemExeInput inIfc)(MemExePipeline); Maybe#(Trap) cause = Invalid; if (expCause matches tagged Valid .c) cause = Valid(Exception(c)); - if(verbose) $display("[doFinishMem] ", fshow(dTlbResp)); + if(verbose) $display("%t : [doFinishMem] ", $time, fshow(dTlbResp)); if(isValid(cause) && verbose) $display(" [doFinishMem - dTlb response] PAGEFAULT!"); Data store_data = ?; diff --git a/src_Core/RISCY_OOO/procs/lib/DTlb.bsv b/src_Core/RISCY_OOO/procs/lib/DTlb.bsv index e24c47c..5998c7e 100644 --- a/src_Core/RISCY_OOO/procs/lib/DTlb.bsv +++ b/src_Core/RISCY_OOO/procs/lib/DTlb.bsv @@ -163,11 +163,11 @@ module mkDTlb#( // pendWait = WaitPeer means this entry is waiting for a resp initiated by // another req. Thus, pendWait must be None when entry is invalid. Vector#(DTlbReqNum, Ehr#(2, Bool)) pendValid <- replicateM(mkEhr(False)); - Vector#(DTlbReqNum, Reg#(DTlbWait)) pendWait <- replicateM(mkReg(None)); - Vector#(DTlbReqNum, Reg#(Bool)) pendPoisoned <- replicateM(mkRegU); - Vector#(DTlbReqNum, Reg#(instT)) pendInst <- replicateM(mkRegU); - Vector#(DTlbReqNum, Reg#(TlbResp)) pendResp <- replicateM(mkRegU); - Vector#(DTlbReqNum, Ehr#(2, SpecBits)) pendSpecBits <- replicateM(mkEhr(?)); + Vector#(DTlbReqNum, Ehr#(2, DTlbWait)) pendWait <- replicateM(mkEhr(None)); + Vector#(DTlbReqNum, Ehr#(2, Bool)) pendPoisoned <- replicateM(mkEhr(?)); + Vector#(DTlbReqNum, Ehr#(2, instT)) pendInst <- replicateM(mkEhr(?)); + Vector#(DTlbReqNum, Ehr#(2, TlbResp)) pendResp <- replicateM(mkEhr(?)); + Vector#(DTlbReqNum, Ehr#(3, SpecBits)) pendSpecBits <- replicateM(mkEhr(?)); // ordering of methods/rules that access pend reqs // procReq mutually exclusive with doPRs (no procReq when pRs ready) @@ -181,16 +181,31 @@ module mkDTlb#( RWire#(void) wrongSpec_doPRs_conflict <- mkRWire; RWire#(void) wrongSpec_procReq_conflict <- mkRWire; + Integer req_port = 1; + Integer resp_port = 0; + let pendValid_noMiss = getVEhrPort(pendValid, 0); let pendValid_wrongSpec = getVEhrPort(pendValid, 0); - let pendValid_procResp = getVEhrPort(pendValid, 0); // write + let pendValid_procResp = getVEhrPort(pendValid, resp_port); // write let pendValid_doPRs = getVEhrPort(pendValid, 1); // assert - let pendValid_procReq = getVEhrPort(pendValid, 1); // write + let pendValid_procReq = getVEhrPort(pendValid, req_port); // write + + let pendWait_Resp = getVEhrPort(pendWait,resp_port); + let pendWait_Req = getVEhrPort(pendWait,req_port); + + let pendPoisoned_Resp = getVEhrPort(pendPoisoned,resp_port); + let pendPoisoned_Req = getVEhrPort(pendPoisoned,req_port); + + let pendInst_Resp = getVEhrPort(pendInst,resp_port); + let pendInst_Req = getVEhrPort(pendInst,req_port); + + let pendResp_Resp = getVEhrPort(pendResp,resp_port); + let pendResp_Req = getVEhrPort(pendResp,req_port); let pendSpecBits_wrongSpec = getVEhrPort(pendSpecBits, 0); - let pendSpecBits_procResp = getVEhrPort(pendSpecBits, 0); - let pendSpecBits_procReq = getVEhrPort(pendSpecBits, 0); // write - let pendSpecBits_correctSpec = getVEhrPort(pendSpecBits, 1); + let pendSpecBits_procResp = getVEhrPort(pendSpecBits, resp_port); + let pendSpecBits_procReq = getVEhrPort(pendSpecBits, req_port); // write + let pendSpecBits_correctSpec = getVEhrPort(pendSpecBits, 2); // free list of pend entries, to cut off path from procResp to procReq Fifo#(DTlbReqNum, DTlbReqIdx) freeQ <- mkCFFifo; @@ -241,7 +256,7 @@ module mkDTlb#( rule incrAllMissCycles(doStats); function Bool isMiss(DTlbWait x) = x != None; - when(all(isMiss, readVReg(pendWait)), allMissCycles.incr(1)); + when(all(isMiss, readVReg(pendWait_Resp)), allMissCycles.incr(1)); endrule `endif `ifdef PERFORMANCE_MONITORING @@ -279,9 +294,9 @@ module mkDTlb#( // the current req being served is either the initiating req or other // req pending on the same resp let idx = fromMaybe(pRs.id, respForOtherReq); - TlbReq r = getTlbReq(pendInst[idx]); + TlbReq r = getTlbReq(pendInst_Req[idx]); - if(pendPoisoned[idx]) begin + if(pendPoisoned_Req[idx]) begin // poisoned inst, do nothing if(verbose) $display("[DTLB] refill poisoned: idx %d; ", idx, fshow(r)); end @@ -304,7 +319,7 @@ module mkDTlb#( // fill TLB, and record resp tlb.addEntry(en); let trans_addr = translate(r.addr, en.ppn, en.level); - pendResp[idx] <= tuple3(trans_addr, Invalid, permCheck.allowCap); + pendResp_Req[idx] <= tuple3(trans_addr, Invalid, permCheck.allowCap); if(verbose) begin $display("[DTLB] refill: idx %d; ", idx, fshow(r), "; ", fshow(trans_addr)); @@ -313,7 +328,7 @@ module mkDTlb#( else begin // page fault Exception fault = permCheck.excCode; - pendResp[idx] <= tuple3(?, Valid (fault), False); + pendResp_Req[idx] <= tuple3(?, Valid (fault), False); if(verbose) begin $display("[DTLB] refill no permission: idx %d; ", idx, fshow(r)); end @@ -322,26 +337,26 @@ module mkDTlb#( else begin // page fault Exception fault = r.write ? excStorePageFault : excLoadPageFault; - pendResp[idx] <= tuple3(?, Valid (fault), False); + pendResp_Req[idx] <= tuple3(?, Valid (fault), False); if(verbose) $display("[DTLB] refill page fault: idx %d; ", idx, fshow(r)); end // get parent resp, miss resolved, reset wait bit - pendWait[idx] <= None; + pendWait_Req[idx] <= None; doAssert(pendValid_doPRs[idx], "entry must be valid"); if(isValid(respForOtherReq)) begin - doAssert(pendWait[idx] == WaitPeer (pRs.id), "entry must be waiting for resp"); + doAssert(pendWait_Req[idx] == WaitPeer (pRs.id), "entry must be waiting for resp"); end else begin - doAssert(pendWait[idx] == WaitParent, "entry must be waiting for resp"); + doAssert(pendWait_Req[idx] == WaitParent, "entry must be waiting for resp"); end // find another req waiting for this resp function Bool waitForResp(DTlbReqIdx i); // we can ignore pendValid here, because not-None pendWait implies // pendValid is true - return pendWait[i] == WaitPeer (pRs.id) && i != idx; + return pendWait_Req[i] == WaitPeer (pRs.id) && i != idx; endfunction Vector#(DTlbReqNum, DTlbReqIdx) idxVec = genWith(fromInteger); if(find(waitForResp, idxVec) matches tagged Valid .i) begin @@ -391,7 +406,7 @@ module mkDTlb#( // idx of entries that are ready to resp to proc function Maybe#(DTlbReqIdx) validProcRespIdx; function Bool validResp(DTlbReqIdx i); - return pendValid_procResp[i] && pendWait[i] == None && !pendPoisoned[i]; + return pendValid_procResp[i] && pendWait_Resp[i] == None && !pendPoisoned_Resp[i]; endfunction Vector#(DTlbReqNum, DTlbReqIdx) idxVec = genWith(fromInteger); return find(validResp, idxVec); @@ -399,7 +414,7 @@ module mkDTlb#( function Maybe#(DTlbReqIdx) poisonedProcRespIdx; function Bool poisonedResp(DTlbReqIdx i); - return pendValid_procResp[i] && pendWait[i] == None && pendPoisoned[i]; + return pendValid_procResp[i] && pendWait_Resp[i] == None && pendPoisoned_Resp[i]; endfunction Vector#(DTlbReqNum, DTlbReqIdx) idxVec = genWith(fromInteger); return find(poisonedResp, idxVec); @@ -443,11 +458,11 @@ module mkDTlb#( freeQ.deq; DTlbReqIdx idx = freeQ.first; doAssert(!pendValid_procReq[idx], "free entry cannot be valid"); - doAssert(pendWait[idx] == None, "entry cannot wait for parent resp"); + doAssert(pendWait_Req[idx] == None, "entry cannot wait for parent resp"); pendValid_procReq[idx] <= True; - pendPoisoned[idx] <= False; - pendInst[idx] <= req.inst; + pendPoisoned_Req[idx] <= False; + pendInst_Req[idx] <= req.inst; pendSpecBits_procReq[idx] <= req.specBits; // pendWait and pendResp are set later in this method @@ -462,8 +477,8 @@ module mkDTlb#( // assume that we allow shared load all the time when in M mode. // (Because we are always non speculative in M mode) if (!vm_info.sanctum_authShared && outOfProtectionDomain(vm_info, r.addr))begin - pendWait[idx] <= None; - pendResp[idx] <= tuple3(?, Valid (excLoadAccessFault), False); + pendWait_Req[idx] <= None; + pendWait_Req[idx] <= tuple3(?, Valid (excLoadAccessFault), False); end `else // No security check @@ -477,8 +492,8 @@ module mkDTlb#( if (!validVirtualAddress(r.addr)) begin // page fault Exception fault = r.write ? excStorePageFault : excLoadPageFault; - pendWait[idx] <= None; - pendResp[idx] <= tuple3(?, Valid (fault), False); + pendWait_Req[idx] <= None; + pendResp_Req[idx] <= tuple3(?, Valid (fault), False); if(verbose) $display("[DTLB] req invalid virtual address: idx %d; ", idx, fshow(r)); end else if (trans_result.hit) begin // TLB hit @@ -502,8 +517,8 @@ module mkDTlb#( tlb.updateRepByHit(trans_result.index); // translate addr Addr trans_addr = translate(r.addr, entry.ppn, entry.level); - pendWait[idx] <= None; - pendResp[idx] <= tuple3(trans_addr, Invalid, permCheck.allowCap); + pendWait_Req[idx] <= None; + pendResp_Req[idx] <= tuple3(trans_addr, Invalid, permCheck.allowCap); if(verbose) begin $display("[DTLB] req (hit): idx %d; ", idx, fshow(r), "; ", fshow(trans_result)); @@ -518,8 +533,8 @@ module mkDTlb#( else begin // page fault Exception fault = permCheck.excCode; - pendWait[idx] <= None; - pendResp[idx] <= tuple3(?, Valid (fault), False); + pendWait_Req[idx] <= None; + pendResp_Req[idx] <= tuple3(?, Valid (fault), False); if(verbose) $display("[DTLB] req no permission: idx %d; ", idx, fshow(r)); end end @@ -529,13 +544,13 @@ module mkDTlb#( function Bool reqSamePage(DTlbReqIdx i); // we can ignore pendValid here, because not-None pendWait implies // pendValid is true - let r_i = getTlbReq(pendInst[i]); - return pendWait[i] == WaitParent && getVpn(r.addr) == getVpn(r_i.addr); + let r_i = getTlbReq(pendInst_Req[i]); + return pendWait_Req[i] == WaitParent && getVpn(r.addr) == getVpn(r_i.addr); endfunction Vector#(DTlbReqNum, DTlbReqIdx) idxVec = genWith(fromInteger); if(find(reqSamePage, idxVec) matches tagged Valid .i) begin // peer entry has already requested, so don't send duplicate req - pendWait[idx] <= WaitPeer (i); + pendWait_Req[idx] <= WaitPeer (i); doAssert(pendValid_procReq[i], "peer entry must be valid"); if(verbose) begin $display("[DTLB] req miss, pend on peer: idx %d, ", @@ -544,7 +559,7 @@ module mkDTlb#( end else begin // this is the first req for this VPN - pendWait[idx] <= WaitParent; + pendWait_Req[idx] <= WaitParent; rqToPQ.enq(DTlbRqToP { vpn: vpn, id: idx @@ -560,8 +575,8 @@ module mkDTlb#( end else begin // bare mode - pendWait[idx] <= None; - pendResp[idx] <= tuple3(r.addr, Invalid, True); + pendWait_Req[idx] <= None; + pendResp_Req[idx] <= tuple3(r.addr, Invalid, True); if(verbose) $display("DTLB %m req (bare): ", fshow(r)); end @@ -593,8 +608,8 @@ module mkDTlb#( validProcRespIdx matches tagged Valid .idx &&& freeQInited ); return DTlbResp { - inst: pendInst[idx], - resp: pendResp[idx], + inst: pendInst_Resp[idx], + resp: pendResp_Resp[idx], specBits: pendSpecBits_procResp[idx] }; endmethod @@ -613,7 +628,7 @@ module mkDTlb#( // poison entries for(Integer i = 0 ; i < valueOf(DTlbReqNum) ; i = i+1) begin if(kill_all || pendSpecBits_wrongSpec[i][x] == 1'b1) begin - pendPoisoned[i] <= True; + pendPoisoned_Resp[i] <= True; end end // make conflicts with procReq, doPRs, procResp