diff --git a/sim/coverage-exclusions-rv64gc.do b/sim/coverage-exclusions-rv64gc.do index d8e05c7d4..d64b730be 100644 --- a/sim/coverage-exclusions-rv64gc.do +++ b/sim/coverage-exclusions-rv64gc.do @@ -246,6 +246,30 @@ coverage exclude -scope /dut/core/ifu/ifu/immu/immu/tlb/tlb/tlbcontrol -linerang # never reaches this when ENVCFG_ADUE_1 because HPTW updates A bit first coverage exclude -scope /dut/core/ifu/ifu/immu/immu/tlb/tlb/tlbcontrol -linerange [GetLineNum ../src/mmu/tlb/tlbcontrol.sv "assign PrePageFault"] -item e 1 -fecexprrow 18 +############### +# HPTW exclusions +############### + +# RV64GC HPTW never starts at L1_ADR +set line [GetLineNum ../src/mmu/hptw.sv "InitialWalkerState == L1_ADR"] +coverage exclude -scope /dut/core/lsu/lsu/hptw/hptw -linerange $line-$line -item c 1 -feccondrow 2 + +# Never possible to get a page fault when neither reading nor writing +set line [GetLineNum ../src/mmu/hptw.sv "assign HPTWLoadPageFault"] +coverage exclude -scope /dut/core/lsu/lsu/hptw/hptw -linerange $line-$line -item e 1 -fecexprrow 7 + +# Never possible to get a store page fault from an ITLB walk +set line [GetLineNum ../src/mmu/hptw.sv "assign HPTWStoreAmoPageFault"] +coverage exclude -scope /dut/core/lsu/lsu/hptw/hptw -linerange $line-$line -item e 1 -fecexprrow 3 + +# Never possible to get Access = 0 on a nonleaf PTE with no OtherPageFault (because InvalidRead/Write will be 1 on the nonleaf) +set line [GetLineNum ../src/mmu/hptw.sv "assign HPTWUpdateDA"] +coverage exclude -scope /dut/core/lsu/lsu/hptw/hptw -linerange $line-$line -item e 1 -fecexprrow 3 + +############### +# Other exclusions +############### + # IMMU PMP does not support CBO instructions coverage exclude -scope /dut/core/ifu/immu/immu/pmp/pmpchecker -linerange [GetLineNum ../src/mmu/pmpchecker.sv "exclusion-tag: immu-pmpcbom"] coverage exclude -scope /dut/core/ifu/immu/immu/pmp/pmpchecker -linerange [GetLineNum ../src/mmu/pmpchecker.sv "exclusion-tag: immu-pmpcboz"] diff --git a/sim/imperas.ic b/sim/imperas.ic index 4cebcf526..51344b75a 100644 --- a/sim/imperas.ic +++ b/sim/imperas.ic @@ -11,7 +11,7 @@ --override cpu/mvendorid=0x602 --override cpu/marchid=0x24 --override refRoot/cpu/tvec_align=64 ---override refRoot/cpu/envcfg_mask=1 +--override refRoot/cpu/envcfg_mask=1 # dh 1/26/24 this should be deleted when ImperasDV is updated to allow envcfg.FIOM to be written # bit manipulation --override cpu/add_Extensions=B diff --git a/src/mmu/hptw.sv b/src/mmu/hptw.sv index 82eeaef87..2a99b14fd 100644 --- a/src/mmu/hptw.sv +++ b/src/mmu/hptw.sv @@ -93,7 +93,6 @@ module hptw import cvw::*; #(parameter cvw_t P) ( logic [P.PA_BITS-1:0] HPTWReadAdr; logic SelHPTWAdr; logic [P.XLEN+1:0] HPTWAdrExt; - logic ITLBMissOrUpdateDAF; logic DTLBMissOrUpdateDAM; logic LSUAccessFaultM; logic [P.PA_BITS-1:0] HPTWAdr; @@ -113,12 +112,12 @@ module hptw import cvw::*; #(parameter cvw_t P) ( // map hptw access faults onto either the original LSU load/store fault or instruction access fault assign LSUAccessFaultM = LSULoadAccessFaultM | LSUStoreAmoAccessFaultM; assign HPTWFaultM = LSUAccessFaultM | PBMTFaultM; - assign HPTWLoadAccessFault = LSUAccessFaultM & DTLBWalk & MemRWM[1] & ~MemRWM[0]; + assign HPTWLoadAccessFault = LSUAccessFaultM & DTLBWalk & MemRWM[1] & ~MemRWM[0]; assign HPTWStoreAmoAccessFault = LSUAccessFaultM & DTLBWalk & MemRWM[0]; assign HPTWInstrAccessFault = LSUAccessFaultM & ~DTLBWalk; - assign HPTWLoadPageFault = PBMTFaultM & DTLBWalk & MemRWM[1] & ~MemRWM[0]; - assign HPTWStoreAmoPageFault = PBMTFaultM & DTLBWalk & MemRWM[0]; - assign HPTWInstrPageFault = PBMTFaultM & ~DTLBWalk; + assign HPTWLoadPageFault = PBMTFaultM & DTLBWalk & MemRWM[1] & ~MemRWM[0]; + assign HPTWStoreAmoPageFault = PBMTFaultM & DTLBWalk & MemRWM[0]; + assign HPTWInstrPageFault = PBMTFaultM & ~DTLBWalk; flopr #(7) HPTWAccesFaultReg(clk, reset, {TakeHPTWFault, HPTWLoadAccessFault, HPTWStoreAmoAccessFault, HPTWInstrAccessFault, HPTWLoadPageFault, HPTWStoreAmoPageFault, HPTWInstrPageFault}, @@ -127,17 +126,18 @@ module hptw import cvw::*; #(parameter cvw_t P) ( assign TakeHPTWFault = WalkerState != IDLE; - assign LoadAccessFaultM = TakeHPTWFault ? HPTWLoadAccessFaultDelay : LSULoadAccessFaultM; + // Improve timing by taking HPTW faults off critical path because these are multicycle operations anyway + assign LoadAccessFaultM = TakeHPTWFault ? HPTWLoadAccessFaultDelay : LSULoadAccessFaultM; assign StoreAmoAccessFaultM = TakeHPTWFault ? HPTWStoreAmoAccessFaultDelay : LSUStoreAmoAccessFaultM; assign HPTWInstrAccessFaultF = TakeHPTWFault ? HPTWInstrAccessFaultDelay : 1'b0; - assign LoadPageFaultM = TakeHPTWFault ? HPTWLoadPageFaultDelay : LSULoadPageFaultM; - assign StoreAmoPageFaultM = TakeHPTWFault ? HPTWStoreAmoPageFaultDelay : LSUStoreAmoPageFaultM; - assign HPTWInstrPageFaultF = TakeHPTWFault ? HPTWInstrPageFaultDelay : 1'b0; + assign LoadPageFaultM = TakeHPTWFault ? HPTWLoadPageFaultDelay : LSULoadPageFaultM; + assign StoreAmoPageFaultM = TakeHPTWFault ? HPTWStoreAmoPageFaultDelay : LSUStoreAmoPageFaultM; + assign HPTWInstrPageFaultF = TakeHPTWFault ? HPTWInstrPageFaultDelay : 1'b0; // Extract bits from CSRs and inputs assign SvMode = SATP_REGW[P.XLEN-1:P.XLEN-P.SVMODE_BITS]; assign BasePageTablePPN = SATP_REGW[P.PPN_BITS-1:0]; - assign TLBMiss = (DTLBMissOrUpdateDAM | ITLBMissOrUpdateDAF); + assign TLBMiss = (DTLBMissOrUpdateDAM | ITLBMissF); // Determine which address to translate mux2 #(P.XLEN) vadrmux(PCSpillF, IEUAdrExtM[P.XLEN-1:0], DTLBWalk, TranslationVAdr); @@ -203,7 +203,7 @@ module hptw import cvw::*; #(parameter cvw_t P) ( // memory access. If there is the PTE needs to be updated seting Access // and possibly also Dirty. Dirty is set if the operation is a store/amo. // However any other fault should not cause the update, and updates are in software when ENVCFG_ADUE = 0 - assign HPTWUpdateDA = ValidLeafPTE & (~Accessed | SetDirty) & ENVCFG_ADUE & ~OtherPageFault; + assign HPTWUpdateDA = ValidLeafPTE & (~Accessed | SetDirty) & ENVCFG_ADUE & ~OtherPageFault; assign HPTWRW[0] = (WalkerState == UPDATE_PTE); // HPTWRW[0] will always be 0 if ADUE = 0 because HPTWUpdateDA will be 0 so WalkerState never is UPDATE_PTE assign UpdatePTE = (WalkerState == LEAF) & HPTWUpdateDA; // UpdatePTE will always be 0 if ADUE = 0 because HPTWUpdateDA will be 0 @@ -283,7 +283,7 @@ 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 & ~DCacheBusStallM) NextWalkerState = InitialWalkerState; + IDLE: if (TLBMiss) NextWalkerState = InitialWalkerState; else NextWalkerState = IDLE; L3_ADR: NextWalkerState = L3_RD; // first access in SV48 L3_RD: if (DCacheBusStallM) NextWalkerState = L3_RD; @@ -294,7 +294,7 @@ module hptw import cvw::*; #(parameter cvw_t P) ( L2_RD: if (DCacheBusStallM) NextWalkerState = L2_RD; else if(HPTWFaultM) NextWalkerState = FAULT; else NextWalkerState = L1_ADR; - L1_ADR: if (InitialWalkerState == L1_ADR | ValidNonLeafPTE) NextWalkerState = L1_RD; // first access in SV32 + L1_ADR: if (InitialWalkerState == L1_ADR | ValidNonLeafPTE) NextWalkerState = L1_RD; // first access in SV32 else NextWalkerState = LEAF; L1_RD: if (DCacheBusStallM) NextWalkerState = L1_RD; else if(HPTWFaultM) NextWalkerState = FAULT; @@ -320,9 +320,8 @@ module hptw import cvw::*; #(parameter cvw_t P) ( // 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 != FAULT) | (WalkerState == IDLE & TLBMiss); + assign HPTWStall = (WalkerState != IDLE & WalkerState != FAULT) | (WalkerState == IDLE & TLBMiss); - assign ITLBMissOrUpdateDAF = ITLBMissF | (P.SVADU_SUPPORTED & InstrUpdateDAF); assign DTLBMissOrUpdateDAM = DTLBMissM | (P.SVADU_SUPPORTED & DataUpdateDAM); // HTPW address/data/control muxing diff --git a/tests/coverage/tlbmisc.S b/tests/coverage/tlbmisc.S index d62a4f2d6..a51436e3a 100644 --- a/tests/coverage/tlbmisc.S +++ b/tests/coverage/tlbmisc.S @@ -123,6 +123,27 @@ main: li t0, 0x80806000 jalr ra, t0 # jump to page to exercise ITLB with PBMT !=0 when ENVCFG_PMTE=0 + # Load and AMO operation on page table entry that causes access fault + li t0, 0x81000000 + lw t1, 0(t0) + sfence.vma + amoadd.w t0, t0, 0(t0) + + # Access fault on top level PTE + li t0, 0x1000000000 + lw t1, 0(t0) + + # Access fault on megapage + li t0, 0x81400000 + lw t1, 0(t0) + + # AMO operation on page table entry that causes page fault due to malformed PBMT + li t0, 0x81200000 + jalr t0 # Attempt to fetch instruction from address causing faulty page walk + lw t1, 0(t0) + sfence.vma + amoadd.w t0, t0, 0(t0) + # change back to default trap handler after checking everything that might cause an instruction page fault jal changetodefaulthandler @@ -178,8 +199,6 @@ main: li a0, 1 ecall - - # wrap up li a0, 3 # switch back to machine mode because code at 0x80000000 may not have clean page table entry ecall @@ -237,32 +256,30 @@ ipf: .align 16 # root Page table situated at 0x80010000 pagetable: - .8byte 0x200044C1 # 0x00000000-0x80_00000000: PTE at 0x80011000 C1 dirty, accessed, valid + .8byte 0x200044C1 # 0x00000000-0x7F_FFFFFFFF: PTE at 0x80011000 C1 dirty, accessed, valid .8byte 0x00000000000010CF # misaligned terapage at 0x80_00000000 + .8byte 0x00000000000000CF # access fault terapage at 0x100_00000000 # next page table at 0x80011000 .align 12 .8byte 0x00000000000010CF # misaligned gigapage at 0x00000000 - .8byte 0x00000000200058C1 # PTE for pages at 0x40000000 + .8byte 0x00000000200058C1 # PTE for pages at 0x40000000 pointing to 0x80150000 .8byte 0x00000000200048C1 # gigapage at 0x80000000 pointing to 0x80120000 # Next page table at 0x80012000 for gigapage at 0x80000000 .align 12 - .8byte 0x0000000020004CC1 # for VA starting at 80000000 (pointer to NAPOT 64 KiB pages) + .8byte 0x0000000020004CC1 # for VA starting at 80000000 (pointer to NAPOT 64 KiB pages Page table at 80013000) .8byte 0x0000000020014CCF # for VA starting at 80200000 (misaligned megapage) - .8byte 0x00000000200050C1 # for VA starting at 80400000 (bad PBMT pages) + .8byte 0x00000000200050C1 # for VA starting at 80400000 (bad PBMT pages page table at 0x80014000) .8byte 0x4000000020004CC1 # for VA starting at 80600000 (bad entry: nonleaf PTE can't have PBMT != 0) - .8byte 0x00000000200054C1 # for VA starting at 80800000 (testing rwx permissiosn with cbom/cboz) - .8byte 0x0000000020004CC1 # for VA starting at 80A00000 (pointer to NAPOT 64 KiB pages like at 80000000) + .8byte 0x00000000200054C1 # for VA starting at 80800000 (testing rwx permissiosn with cbom/cboz . page table at 0x80015000) + .8byte 0x0000000020004CC1 # for VA starting at 80A00000 (pointer to NAPOT 64 KiB pages like at 80000000. page table at 0x80013000) .8byte 0x0F00000020004CCF # for VA starting at 80C00000 (bad reserved field in bits 60:54) - .8byte 0x000000002000000F # for VA starting at 80E00000 (not dirty or accessed) - .8byte 0x0000000020004CC1 - .8byte 0x0000000020004CC1 - .8byte 0x0000000020004CC1 - .8byte 0x0000000020004CC1 - .8byte 0x0000000020004CC1 - .8byte 0x0000000020004CC1 + .8byte 0x000000002000000F # for VA starting at 80E00000 (megapage not dirty or accessed) + .8byte 0x0000000000004CC1 # for VA starting at 81000000 (nonleaf pointing to unimplemented memory causes access fault) + .8byte 0x4000000020004CC1 # for VA starting at 81200000 (nonleaf with PBMT nonzero causes page fault) + .8byte 0x00000000000000CF # for VA starting at 81400000 (megapage with access fault) .8byte 0x0000000020004CC1 .8byte 0x0000000020004CC1 .8byte 0x0000000020004CC1 @@ -288,7 +305,7 @@ pagetable: .8byte 0x0000000020004CC1 .8byte 0x0000000020004CC1 -# Leaf page table at 0x80013000 with NAPOT pages +# Leaf page table at 0x80013000 with 64 KiB NAPOT pages .align 12 #80000000 .8byte 0xA0000000200020CF