Possible fix for Linux bug and bug 203. ImperasDV mismatches in linux boot around 571M instructions after the login prompt.

This bug occurs when there are back to back HPTW requests and the first generates an access fault during the walk. The old implementation uses a delayed version of the fault to prevent the HTPW fsm from transitioning out of the IDLE state.  Because the first request generates the fault and the second request is pipelined the second request appears as if it also faults so the FSM does not perform the walk.
The new implementation adds a FAULT state.  When the HPTW generates an access fault it transitions to this state removes the HPTWStall and then transitions to IDLE.  There may still be a remaining bug here if the pipeline is stalled for another reason.  However I don't think it is possible by construction.  The only possible sources of stalls at this point would be IFU and LSU stalls and both are required to make this condition happen.
This commit is contained in:
Ross Thompson 2023-05-30 15:20:24 -05:00
parent 04d0fd94f0
commit 8e1476cb8c

View File

@ -69,7 +69,8 @@ module hptw import cvw::*; #(parameter cvw_t P) (
L1_ADR, L1_RD,
L2_ADR, L2_RD,
L3_ADR, L3_RD,
LEAF, IDLE, UPDATE_PTE} statetype;
LEAF, IDLE, UPDATE_PTE,
FAULT} statetype;
logic DTLBWalk; // register TLBs translation miss requests
logic [P.PPN_BITS-1:0] BasePageTablePPN;
@ -258,38 +259,44 @@ module hptw import cvw::*; #(parameter cvw_t P) (
flopenl #(.TYPE(statetype)) WalkerStateReg(clk, reset | FlushW, 1'b1, NextWalkerState, IDLE, WalkerState);
always_comb
case (WalkerState)
IDLE: if (TLBMiss & ~DCacheStallM & ~HPTWAccessFaultDelay) NextWalkerState = InitialWalkerState;
IDLE: if (TLBMiss & ~DCacheStallM) NextWalkerState = InitialWalkerState;
else NextWalkerState = IDLE;
L3_ADR: NextWalkerState = L3_RD; // first access in SV48
L3_RD: if (DCacheStallM) NextWalkerState = L3_RD;
else if(LSUAccessFaultM) NextWalkerState = IDLE;
else if(LSUAccessFaultM) NextWalkerState = FAULT;
else NextWalkerState = L2_ADR;
L2_ADR: if (InitialWalkerState == L2_ADR | ValidNonLeafPTE) NextWalkerState = L2_RD; // first access in SV39
else NextWalkerState = LEAF;
L2_RD: if (DCacheStallM) NextWalkerState = L2_RD;
else if(LSUAccessFaultM) NextWalkerState = IDLE;
else if(LSUAccessFaultM) NextWalkerState = FAULT;
else NextWalkerState = L1_ADR;
L1_ADR: if (InitialWalkerState == L1_ADR | ValidNonLeafPTE) NextWalkerState = L1_RD; // first access in SV32
else NextWalkerState = LEAF;
L1_RD: if (DCacheStallM) NextWalkerState = L1_RD;
else if(LSUAccessFaultM) NextWalkerState = IDLE;
else if(LSUAccessFaultM) NextWalkerState = FAULT;
else NextWalkerState = L0_ADR;
L0_ADR: if (ValidNonLeafPTE) NextWalkerState = L0_RD;
else NextWalkerState = LEAF;
L0_RD: if (DCacheStallM) NextWalkerState = L0_RD;
else if(LSUAccessFaultM) NextWalkerState = IDLE;
else if(LSUAccessFaultM) NextWalkerState = FAULT;
else NextWalkerState = LEAF;
LEAF: if (P.SVADU_SUPPORTED & HPTWUpdateDA) NextWalkerState = UPDATE_PTE;
LEAF: if (P.SVADU_SUPPORTED & HPTWUpdateDA) NextWalkerState = UPDATE_PTE;
else NextWalkerState = IDLE;
UPDATE_PTE: if(DCacheStallM) NextWalkerState = UPDATE_PTE;
else NextWalkerState = LEAF;
FAULT: NextWalkerState = IDLE;
default: NextWalkerState = IDLE; // should never be reached
endcase // case (WalkerState)
assign IgnoreRequestTLB = (WalkerState == IDLE & TLBMiss) | (LSUAccessFaultM); // RT : 05 April 2023 if hptw request has pmp/a fault suppress bus access.
assign SelHPTW = WalkerState != IDLE;
// RT 30 May 2023: When there is an access fault caused by the hptw itself, the fsm jumps to FAULT, removes
// stall and asserts one of HPTWLoadAccessFault, HPTWStoreAmoAccessFault or HPTWInstrAccessFaultDelay.
// The FSM directly transistions to IDLE to ready for the next operation when the delayed version will not be high.
assign HPTWAccessFaultDelay = HPTWLoadAccessFaultDelay | HPTWStoreAmoAccessFaultDelay | HPTWInstrAccessFaultDelay;
assign HPTWStall = (WalkerState != IDLE) | (WalkerState == IDLE & TLBMiss & ~(HPTWAccessFaultDelay));
assign HPTWStall = (WalkerState != IDLE & WalkerState != FAULT) | (WalkerState == IDLE & TLBMiss);
assign ITLBMissOrUpdateDAF = ITLBMissF | (P.SVADU_SUPPORTED & InstrUpdateDAF);
assign DTLBMissOrUpdateDAM = DTLBMissM | (P.SVADU_SUPPORTED & DataUpdateDAM);