diff --git a/src/mmu/pmpadrdec.sv b/src/mmu/pmpadrdec.sv index aa8728c90..d753a7a3d 100644 --- a/src/mmu/pmpadrdec.sv +++ b/src/mmu/pmpadrdec.sv @@ -52,52 +52,40 @@ module pmpadrdec import cvw::*; #(parameter cvw_t P) ( logic TORMatch, NAMatch; logic PAltPMPAdr; - logic [P.PA_BITS-1:0] PMPAdrTORGrain, PMPAdrNAPOTGrain, CurrentAdrFull; + logic [P.PA_BITS-1:0] PMPAdrFull; logic [1:0] AdrMode; logic [P.PA_BITS-1:0] PMPTop1, PMPTopTOR, PMPTopNaturallyAligned; assign AdrMode = PMPCfg[4:3]; - // The two lsb of the physical address don't matter for this checking. - // The following code includes them, but hardwires the PMP checker lsbs to 00 - // and masks them later. Logic synthesis should optimize away these bottom bits. - + // Bottom two bits of PMPAdr are 00 + assign PMPAdrFull = {PMPAdr, 2'b00}; + // Top-of-range (TOR) // Append two implicit trailing 0's to PMPAdr value - assign PMPAdrTORGrain = (P.PMP_G > 0) ? {PMPAdr[P.PA_BITS-3:P.PMP_G], {P.PMP_G{1'b0}}} : PMPAdr; // In TOR, bottom G bits read as 0 - assign CurrentAdrFull = {PMPAdrTORGrain, 2'b00}; - assign PAltPMPAdr = {1'b0, PhysicalAddress} < {1'b0, CurrentAdrFull}; // unsigned comparison + assign PAltPMPAdr = {1'b0, PhysicalAddress} < {1'b0, PMPAdrFull}; // unsigned comparison assign PAgePMPAdrOut = ~PAltPMPAdr; assign TORMatch = PAgePMPAdrIn & PAltPMPAdr; // exclusion-tag: PAgePMPAdrIn // Naturally aligned regions logic [P.PA_BITS-1:0] NAMask, NABase; - assign PMPAdrNAPOTGrain = {PMPAdr[P.PA_BITS-3:Gm1], {Gm1{1'b1}}}; // in NAPOT, if G >= 2, bottom G-1 bits read as all 1s assign NAMask[1:0] = {2'b11}; - - // assign NAMask[P.PA_BITS-1:2] = (PMPAdr + {{(P.PA_BITS-3){1'b0}}, (AdrMode == NAPOT)}) ^ PMPAdr; - assign NAMask[P.PA_BITS-1:2] = (PMPAdrNAPOTGrain + {{(P.PA_BITS-3){1'b0}}, (AdrMode == NAPOT)}) ^ PMPAdrNAPOTGrain; + assign NAMask[P.PA_BITS-1:2] = (PMPAdr + {{(P.PA_BITS-3){1'b0}}, (AdrMode == NAPOT)}) ^ PMPAdr; // form a mask where the bottom k bits are 1, corresponding to a size of 2^k bytes for this memory region. // This assumes we're using at least an NA4 region, but works for any size NAPOT region. - - -/* in progress, fix soon dh 5/8/25 - assign NABase = {(PMPAdrNAPOTGrain & ~NAMask[P.PA_BITS-1:2]), 2'b00}; // base physical address of the pmp region - assign NAMatch = &((NABase ~^ PhysicalAddress) | NAMask); // check if upper bits of base address match, ignore lower bits correspoonding to inside the memory range -*/ assign NABase = {(PMPAdr & ~NAMask[P.PA_BITS-1:2]), 2'b00}; // base physical address of the pmp region assign NAMatch = &((NABase ~^ PhysicalAddress) | NAMask); // check if upper bits of base address match, ignore lower bits corresponding to inside the memory range // finally pick the appropriate match for the access type assign Match = (AdrMode == TOR) ? TORMatch : (AdrMode == NA4 | AdrMode == NAPOT) ? NAMatch : - 1'b0; + 1'b0; // OFF never matches // Report top of region for first matching region // PMP should match but fail if the size is too big (8-byte accesses spanning to TOR or NA4 region) - assign PMPTopTOR = {PMPAdrTORGrain-1, 2'b11}; // TOR goes to (pmpaddr << 2) - 1 - assign PMPTopNaturallyAligned = {PMPAdrNAPOTGrain, 2'b00} | NAMask; // top of the pmp region for NA4 and NAPOT. All 1s in the lower bits. Used to check the address doesn't pass the top + assign PMPTopTOR = {PMPAdr-1, 2'b11}; // TOR goes to (pmpaddr << 2) - 1 + assign PMPTopNaturallyAligned = PMPAdrFull | NAMask; // top of the pmp region for NA4 and NAPOT. All 1s in the lower bits. Used to check the address doesn't pass the top assign PMPTop1 = (AdrMode == TOR) ? PMPTopTOR : PMPTopNaturallyAligned; assign PMPTop = FirstMatch ? PMPTop1 : '0; // AND portion of distributed AND-OR mux (OR portion in pmpchhecker) diff --git a/src/mmu/pmpchecker.sv b/src/mmu/pmpchecker.sv index e73c7e4a5..ebe83a710 100644 --- a/src/mmu/pmpchecker.sv +++ b/src/mmu/pmpchecker.sv @@ -96,6 +96,9 @@ module pmpchecker import cvw::*; #(parameter cvw_t P) ( endcase // Then find the top of the access and see if it is beyond the top of the region assign PhysicalAddressTop = PhysicalAddress + {{P.PA_BITS-3{1'b0}}, SizeBytesMinus1}; // top of the access range + // DH 5/27/25 *** TooBig should never occur because granularity is a line size, and anything wrapping line should be decomposed into multiple accesses. + // Therefore, it should be possilbe to remove TooBig and all the logic that depends on it + // including PhysicalAddressTop, SizeBytesMinus1, and the pmpadrdecs PMPTop output, which is expensive assign TooBig = PhysicalAddressTop > MatchingPMPTop; // check if the access goes beyond the top of the PMP region // Only enforce PMP checking for effective S and U modes (accounting for mstatus.MPRV) or in Machine mode when L bit is set in selected region diff --git a/src/privileged/csrm.sv b/src/privileged/csrm.sv index b47f9fdb8..72660846a 100644 --- a/src/privileged/csrm.sv +++ b/src/privileged/csrm.sv @@ -46,14 +46,15 @@ module csrm import cvw::*; #(parameter cvw_t P) ( output logic [15:0] MEDELEG_REGW, output logic [11:0] MIDELEG_REGW, /* verilator lint_off UNDRIVEN */ // PMP registers are only used when PMP_ENTRIES > 0 + output var logic [P.PA_BITS-3:0] PMPADDR_ARRAY_REGW[P.PMP_ENTRIES-1:0], output var logic [7:0] PMPCFG_ARRAY_REGW[P.PMP_ENTRIES-1:0], - output var logic [P.PA_BITS-3:0] PMPADDR_ARRAY_REGW [P.PMP_ENTRIES-1:0], /* verilator lint_on UNDRIVEN */ output logic WriteMSTATUSM, WriteMSTATUSHM, output logic IllegalCSRMAccessM, IllegalCSRMWriteReadonlyM, output logic [63:0] MENVCFG_REGW ); + logic [P.PA_BITS-3:0] PMPADDR_ARRAY_PREGRAIN_REGW[P.PMP_ENTRIES-1:0]; logic [P.XLEN-1:0] MISA_REGW, MHARTID_REGW; logic [P.XLEN-1:0] MSCRATCH_REGW, MTVAL_REGW, MCAUSE_REGW; logic [P.XLEN-1:0] MENVCFGH_REGW; @@ -113,9 +114,9 @@ module csrm import cvw::*; #(parameter cvw_t P) ( logic [7:0] CSRPMPWriteValM[P.PMP_ENTRIES-1:0]; logic [7:0] CSRPMPLegalizedWriteValM[P.PMP_ENTRIES-1:0]; logic [1:0] CSRPMPWRLegalizedWriteValM[P.PMP_ENTRIES-1:0]; - logic CSRPMPA0LegalizedWriteValM[P.PMP_ENTRIES-1:0]; + logic [1:0] CSRPMPALegalizedWriteValM[P.PMP_ENTRIES-1:0]; logic [P.PMP_ENTRIES-1:0] ADDRLocked, CFGLocked; - for(i=0; i