From 8e1476cb8c2979c959a32cd5d4dc554d3710b49d Mon Sep 17 00:00:00 2001 From: Ross Thompson Date: Tue, 30 May 2023 15:20:24 -0500 Subject: [PATCH] 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. --- src/mmu/hptw.sv | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/src/mmu/hptw.sv b/src/mmu/hptw.sv index 17a98acd3..244bd2cbd 100644 --- a/src/mmu/hptw.sv +++ b/src/mmu/hptw.sv @@ -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);