Roll back DTlB to two cycles for timing on DE10.
This commit is contained in:
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user