From 6f8c371a5ca2380c7a14518045a2ba76a03309e2 Mon Sep 17 00:00:00 2001 From: Jonathan Woodruff Date: Mon, 25 Mar 2024 12:52:51 +0000 Subject: [PATCH] Roll back DTlB to two cycles for timing on DE10. --- src_Core/RISCY_OOO/procs/lib/DTlb.bsv | 128 +++++++++++--------------- 1 file changed, 56 insertions(+), 72 deletions(-) diff --git a/src_Core/RISCY_OOO/procs/lib/DTlb.bsv b/src_Core/RISCY_OOO/procs/lib/DTlb.bsv index cfcd314..e24c47c 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, 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(?)); + 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(?)); // ordering of methods/rules that access pend reqs // procReq mutually exclusive with doPRs (no procReq when pRs ready) @@ -181,34 +181,19 @@ module mkDTlb#( RWire#(void) wrongSpec_doPRs_conflict <- mkRWire; RWire#(void) wrongSpec_procReq_conflict <- mkRWire; - Integer req_port = 0; - Integer resp_port = 1; - let pendValid_noMiss = getVEhrPort(pendValid, 0); let pendValid_wrongSpec = getVEhrPort(pendValid, 0); - let pendValid_procResp = getVEhrPort(pendValid, resp_port); // write + let pendValid_procResp = getVEhrPort(pendValid, 0); // write let pendValid_doPRs = getVEhrPort(pendValid, 1); // assert - 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 pendValid_procReq = getVEhrPort(pendValid, 1); // write let pendSpecBits_wrongSpec = getVEhrPort(pendSpecBits, 0); - let pendSpecBits_procResp = getVEhrPort(pendSpecBits, resp_port); - let pendSpecBits_procReq = getVEhrPort(pendSpecBits, req_port); // write - let pendSpecBits_correctSpec = getVEhrPort(pendSpecBits, 2); + let pendSpecBits_procResp = getVEhrPort(pendSpecBits, 0); + let pendSpecBits_procReq = getVEhrPort(pendSpecBits, 0); // write + let pendSpecBits_correctSpec = getVEhrPort(pendSpecBits, 1); // free list of pend entries, to cut off path from procResp to procReq - Fifo#(TAdd#(DTlbReqNum,1), DTlbReqIdx) freeQ <- mkCFFifo; + Fifo#(DTlbReqNum, DTlbReqIdx) freeQ <- mkCFFifo; Reg#(Bool) freeQInited <- mkReg(False); Reg#(DTlbReqIdx) freeQInitIdx <- mkReg(0); @@ -256,7 +241,7 @@ module mkDTlb#( rule incrAllMissCycles(doStats); function Bool isMiss(DTlbWait x) = x != None; - when(all(isMiss, readVReg(pendWait_Resp)), allMissCycles.incr(1)); + when(all(isMiss, readVReg(pendWait)), allMissCycles.incr(1)); endrule `endif `ifdef PERFORMANCE_MONITORING @@ -294,9 +279,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_Req[idx]); + TlbReq r = getTlbReq(pendInst[idx]); - if(pendPoisoned_Req[idx]) begin + if(pendPoisoned[idx]) begin // poisoned inst, do nothing if(verbose) $display("[DTLB] refill poisoned: idx %d; ", idx, fshow(r)); end @@ -319,7 +304,7 @@ module mkDTlb#( // fill TLB, and record resp tlb.addEntry(en); let trans_addr = translate(r.addr, en.ppn, en.level); - pendResp_Req[idx] <= tuple3(trans_addr, Invalid, permCheck.allowCap); + pendResp[idx] <= tuple3(trans_addr, Invalid, permCheck.allowCap); if(verbose) begin $display("[DTLB] refill: idx %d; ", idx, fshow(r), "; ", fshow(trans_addr)); @@ -328,7 +313,7 @@ module mkDTlb#( else begin // page fault Exception fault = permCheck.excCode; - pendResp_Req[idx] <= tuple3(?, Valid (fault), False); + pendResp[idx] <= tuple3(?, Valid (fault), False); if(verbose) begin $display("[DTLB] refill no permission: idx %d; ", idx, fshow(r)); end @@ -337,26 +322,26 @@ module mkDTlb#( else begin // page fault Exception fault = r.write ? excStorePageFault : excLoadPageFault; - pendResp_Req[idx] <= tuple3(?, Valid (fault), False); + pendResp[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_Req[idx] <= None; + pendWait[idx] <= None; doAssert(pendValid_doPRs[idx], "entry must be valid"); if(isValid(respForOtherReq)) begin - doAssert(pendWait_Req[idx] == WaitPeer (pRs.id), "entry must be waiting for resp"); + doAssert(pendWait[idx] == WaitPeer (pRs.id), "entry must be waiting for resp"); end else begin - doAssert(pendWait_Req[idx] == WaitParent, "entry must be waiting for resp"); + doAssert(pendWait[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_Req[i] == WaitPeer (pRs.id) && i != idx; + return pendWait[i] == WaitPeer (pRs.id) && i != idx; endfunction Vector#(DTlbReqNum, DTlbReqIdx) idxVec = genWith(fromInteger); if(find(waitForResp, idxVec) matches tagged Valid .i) begin @@ -406,7 +391,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_Resp[i] == None && !pendPoisoned_Resp[i]; + return pendValid_procResp[i] && pendWait[i] == None && !pendPoisoned[i]; endfunction Vector#(DTlbReqNum, DTlbReqIdx) idxVec = genWith(fromInteger); return find(validResp, idxVec); @@ -414,7 +399,7 @@ module mkDTlb#( function Maybe#(DTlbReqIdx) poisonedProcRespIdx; function Bool poisonedResp(DTlbReqIdx i); - return pendValid_procResp[i] && pendWait_Resp[i] == None && pendPoisoned_Resp[i]; + return pendValid_procResp[i] && pendWait[i] == None && pendPoisoned[i]; endfunction Vector#(DTlbReqNum, DTlbReqIdx) idxVec = genWith(fromInteger); return find(poisonedResp, idxVec); @@ -458,22 +443,16 @@ module mkDTlb#( freeQ.deq; DTlbReqIdx idx = freeQ.first; doAssert(!pendValid_procReq[idx], "free entry cannot be valid"); - doAssert(pendWait_Req[idx] == None, "entry cannot wait for parent resp"); + doAssert(pendWait[idx] == None, "entry cannot wait for parent resp"); pendValid_procReq[idx] <= True; - pendPoisoned_Req[idx] <= False; - pendInst_Req[idx] <= req.inst; + pendPoisoned[idx] <= False; + pendInst[idx] <= req.inst; pendSpecBits_procReq[idx] <= req.specBits; // pendWait and pendResp are set later in this method - // attempt the tlb translation which will be correct if we hit. - // This shortens the path for trans_addr for a zero-cycle TLB. + // try to translate TlbReq r = getTlbReq(req.inst); - let vpn = getVpn(r.addr); - let trans_result = tlb.translate(vpn, vm_info.asid); - Addr trans_addr = translate(r.addr, trans_result.entry.ppn, trans_result.entry.level); - Maybe#(Exception) trans_exp = Invalid; - Bool trans_cap = False; `ifdef SECURITY // Security check @@ -483,22 +462,29 @@ 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_Req[idx] <= None; - pendWait_Req[idx] <= tuple3(?, Valid (excLoadAccessFault), False); - end else + pendWait[idx] <= None; + pendResp[idx] <= tuple3(?, Valid (excLoadAccessFault), False); + end +`else + // No security check + if (False) begin + noAction; + end `endif - if (vm_info.sv39) begin + else if (vm_info.sv39) begin + let vpn = getVpn(r.addr); + let trans_result = tlb.translate(vpn, vm_info.asid); if (!validVirtualAddress(r.addr)) begin // page fault Exception fault = r.write ? excStorePageFault : excLoadPageFault; - pendWait_Req[idx] <= None; - trans_exp = Valid (fault); + pendWait[idx] <= None; + pendResp[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 let entry = trans_result.entry; // check permission - $display("procReq: vm_info: ", fshow(vm_info), + $display("procReq: vm_info: ", fshow(vm_info), " en : ", fshow(entry), " r : ", fshow(r) ); @@ -514,9 +500,10 @@ module mkDTlb#( if (permCheck.allowed) begin // update TLB replacement info tlb.updateRepByHit(trans_result.index); - // We're ready to consume this translation. - pendWait_Req[idx] <= None; - trans_cap = permCheck.allowCap; + // translate addr + Addr trans_addr = translate(r.addr, entry.ppn, entry.level); + pendWait[idx] <= None; + pendResp[idx] <= tuple3(trans_addr, Invalid, permCheck.allowCap); if(verbose) begin $display("[DTLB] req (hit): idx %d; ", idx, fshow(r), "; ", fshow(trans_result)); @@ -531,8 +518,8 @@ module mkDTlb#( else begin // page fault Exception fault = permCheck.excCode; - pendWait_Req[idx] <= None; - trans_exp = Valid (fault); + pendWait[idx] <= None; + pendResp[idx] <= tuple3(?, Valid (fault), False); if(verbose) $display("[DTLB] req no permission: idx %d; ", idx, fshow(r)); end end @@ -542,13 +529,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_Req[i]); - return pendWait_Req[i] == WaitParent && getVpn(r.addr) == getVpn(r_i.addr); + let r_i = getTlbReq(pendInst[i]); + return pendWait[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_Req[idx] <= WaitPeer (i); + pendWait[idx] <= WaitPeer (i); doAssert(pendValid_procReq[i], "peer entry must be valid"); if(verbose) begin $display("[DTLB] req miss, pend on peer: idx %d, ", @@ -557,7 +544,7 @@ module mkDTlb#( end else begin // this is the first req for this VPN - pendWait_Req[idx] <= WaitParent; + pendWait[idx] <= WaitParent; rqToPQ.enq(DTlbRqToP { vpn: vpn, id: idx @@ -573,14 +560,11 @@ module mkDTlb#( end else begin // bare mode - pendWait_Req[idx] <= None; - trans_addr = r.addr; - trans_cap = True; + pendWait[idx] <= None; + pendResp[idx] <= tuple3(r.addr, Invalid, True); if(verbose) $display("DTLB %m req (bare): ", fshow(r)); end - pendResp_Req[idx] <= tuple3(trans_addr, trans_exp, trans_cap); - `ifdef PERF_COUNT // perf: access if(doStats) begin @@ -609,8 +593,8 @@ module mkDTlb#( validProcRespIdx matches tagged Valid .idx &&& freeQInited ); return DTlbResp { - inst: pendInst_Resp[idx], - resp: pendResp_Resp[idx], + inst: pendInst[idx], + resp: pendResp[idx], specBits: pendSpecBits_procResp[idx] }; endmethod @@ -629,7 +613,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_Req[i] <= True; + pendPoisoned[i] <= True; end end // make conflicts with procReq, doPRs, procResp