From bd6eef2a516d86d29f78a0ec0f6bea97f5ec42fe Mon Sep 17 00:00:00 2001 From: David Harris Date: Fri, 25 Aug 2023 18:33:08 -0700 Subject: [PATCH] Initial implementation of SVNAPOT and SVPBMT does not break regression --- src/ifu/ifu.sv | 3 +- src/lsu/lsu.sv | 3 +- src/mmu/mmu.sv | 11 ++++--- src/mmu/pmachecker.sv | 14 +++++--- src/mmu/tlb/tlb.sv | 30 +++++++++++------ src/mmu/tlb/tlbcam.sv | 5 +-- src/mmu/tlb/tlbcamline.sv | 7 ++-- src/mmu/tlb/tlbcontrol.sv | 33 ++++++++++++------- src/mmu/tlb/tlbmixer.sv | 57 ++++++++++++++++++++++++++------- src/mmu/tlb/tlbram.sv | 9 +++--- src/mmu/tlb/tlbramline.sv | 26 ++++++++++----- src/privileged/csr.sv | 2 +- src/privileged/privileged.sv | 3 +- src/wally/wallypipelinedcore.sv | 8 +++-- 14 files changed, 148 insertions(+), 63 deletions(-) diff --git a/src/ifu/ifu.sv b/src/ifu/ifu.sv index 2bceb6175..320b9e330 100644 --- a/src/ifu/ifu.sv +++ b/src/ifu/ifu.sv @@ -85,6 +85,7 @@ module ifu import cvw::*; #(parameter cvw_t P) ( input logic STATUS_SUM, // Status CSR: Supervisor access to user memory input logic STATUS_MPRV, // Status CSR: modify machine privilege input logic [1:0] STATUS_MPP, // Status CSR: previous machine privilege level + input logic ENVCFG_PBMTE, // Page-based memory types enabled input logic sfencevmaM, // Virtual memory address fence, invalidate TLB entries output logic ITLBMissF, // ITLB miss causes HPTW (hardware pagetable walker) walk output logic InstrUpdateDAF, // ITLB hit needs to update dirty or access bits @@ -170,7 +171,7 @@ module ifu import cvw::*; #(parameter cvw_t P) ( assign TLBFlush = sfencevmaM & ~StallMQ; mmu #(.P(P), .TLB_ENTRIES(P.ITLB_ENTRIES), .IMMU(1)) - immu(.clk, .reset, .SATP_REGW, .STATUS_MXR, .STATUS_SUM, .STATUS_MPRV, .STATUS_MPP, + immu(.clk, .reset, .SATP_REGW, .STATUS_MXR, .STATUS_SUM, .STATUS_MPRV, .STATUS_MPP, .ENVCFG_PBMTE, .PrivilegeModeW, .DisableTranslation(1'b0), .VAdr(PCFExt), .Size(2'b10), diff --git a/src/lsu/lsu.sv b/src/lsu/lsu.sv index aeadec262..e120d454b 100644 --- a/src/lsu/lsu.sv +++ b/src/lsu/lsu.sv @@ -80,6 +80,7 @@ module lsu import cvw::*; #(parameter cvw_t P) ( input logic [P.XLEN-1:0] SATP_REGW, // SATP (supervisor address translation and protection) CSR input logic STATUS_MXR, STATUS_SUM, STATUS_MPRV, // STATUS CSR bits: make executable readable, supervisor user memory, machine privilege input logic [1:0] STATUS_MPP, // Machine previous privilege mode + input logic ENVCFG_PBMTE, // Page-based memory types enabled input logic [P.XLEN-1:0] PCSpillF, // Fetch PC input logic ITLBMissF, // ITLB miss causes HPTW (hardware pagetable walker) walk input logic InstrUpdateDAF, // ITLB hit needs to update dirty or access bits @@ -189,7 +190,7 @@ module lsu import cvw::*; #(parameter cvw_t P) ( assign DisableTranslation = SelHPTW | FlushDCacheM; assign WriteAccessM = PreLSURWM[0] | (|CMOpM); mmu #(.P(P), .TLB_ENTRIES(P.DTLB_ENTRIES), .IMMU(0)) - dmmu(.clk, .reset, .SATP_REGW, .STATUS_MXR, .STATUS_SUM, .STATUS_MPRV, .STATUS_MPP, + dmmu(.clk, .reset, .SATP_REGW, .STATUS_MXR, .STATUS_SUM, .STATUS_MPRV, .STATUS_MPP, .ENVCFG_PBMTE, .PrivilegeModeW, .DisableTranslation, .VAdr(IHAdrM), .Size(LSUFunct3M[1:0]), .PTE, .PageTypeWriteVal(PageType), .TLBWrite(DTLBWriteM), .TLBFlush(sfencevmaM), .PhysicalAddress(PAdrM), .TLBMiss(DTLBMissM), .Cacheable(CacheableM), .Idempotent(), .SelTIM(SelDTIM), diff --git a/src/mmu/mmu.sv b/src/mmu/mmu.sv index f05073fcf..e8e06fde0 100644 --- a/src/mmu/mmu.sv +++ b/src/mmu/mmu.sv @@ -34,6 +34,7 @@ module mmu import cvw::*; #(parameter cvw_t P, input logic STATUS_SUM, // Status CSR: Supervisor access to user memory input logic STATUS_MPRV, // Status CSR: modify machine privilege input logic [1:0] STATUS_MPP, // Status CSR: previous machine privilege level + input logic ENVCFG_PBMTE, // Page-based memory types enabled input logic [1:0] PrivilegeModeW, // Current privilege level of the processeor input logic DisableTranslation, // virtual address translation disabled during D$ flush and HPTW walk that use physical addresses input logic [P.XLEN+1:0] VAdr, // virtual/physical address from IEU or physical address from HPTW @@ -70,6 +71,7 @@ module mmu import cvw::*; #(parameter cvw_t P, logic TLBHit; // Hit in TLB logic TLBPageFault; // Page fault from TLB logic ReadNoAmoAccessM; // Read that is not part of atomic operation causes Load faults. Otherwise StoreAmo faults + logic [1:0] PBMemoryType; // PBMT field of PTE during TLB hit, or 00 otherwise // only instantiate TLB if Virtual Memory is supported if (P.VIRTMEM_SUPPORTED) begin:tlb @@ -80,16 +82,17 @@ module mmu import cvw::*; #(parameter cvw_t P, .clk, .reset, .SATP_MODE(SATP_REGW[P.XLEN-1:P.XLEN-P.SVMODE_BITS]), .SATP_ASID(SATP_REGW[P.ASID_BASE+P.ASID_BITS-1:P.ASID_BASE]), - .VAdr(VAdr[P.XLEN-1:0]), .STATUS_MXR, .STATUS_SUM, .STATUS_MPRV, .STATUS_MPP, + .VAdr(VAdr[P.XLEN-1:0]), .STATUS_MXR, .STATUS_SUM, .STATUS_MPRV, .STATUS_MPP, .ENVCFG_PBMTE, .PrivilegeModeW, .ReadAccess, .WriteAccess, .DisableTranslation, .PTE, .PageTypeWriteVal, .TLBWrite, .TLBFlush, .TLBPAdr, .TLBMiss, .TLBHit, - .Translate, .TLBPageFault, .UpdateDA); + .Translate, .TLBPageFault, .UpdateDA, .PBMemoryType); end else begin:tlb // just pass address through as physical assign Translate = 0; assign TLBMiss = 0; assign TLBHit = 1; // *** is this necessary assign TLBPageFault = 0; + assign PBMemoryType = 2'b00; end // If translation is occuring, select translated physical address from TLB @@ -103,8 +106,8 @@ module mmu import cvw::*; #(parameter cvw_t P, /////////////////////////////////////////// pmachecker #(P) pmachecker(.PhysicalAddress, .Size, - .AtomicAccessM, .ExecuteAccessF, .WriteAccessM, .ReadAccessM, - .Cacheable, .Idempotent, .SelTIM, + .AtomicAccessM, .ExecuteAccessF, .WriteAccessM, .ReadAccessM, .PBMemoryType, + .Cacheable, .Idempotent, .SelTIM, .PMAInstrAccessFaultF, .PMALoadAccessFaultM, .PMAStoreAmoAccessFaultM); if (P.PMP_ENTRIES > 0) begin : pmp diff --git a/src/mmu/pmachecker.sv b/src/mmu/pmachecker.sv index 41d8f9b74..ce129af51 100644 --- a/src/mmu/pmachecker.sv +++ b/src/mmu/pmachecker.sv @@ -35,6 +35,7 @@ module pmachecker import cvw::*; #(parameter cvw_t P) ( input logic ExecuteAccessF, // Execute access input logic WriteAccessM, // Write access input logic ReadAccessM, // Read access + input logic [1:0] PBMemoryType, // PBMT field of PTE during TLB hit, or 00 otherwise output logic Cacheable, Idempotent, SelTIM, output logic PMAInstrAccessFaultF, output logic PMALoadAccessFaultM, @@ -45,6 +46,7 @@ module pmachecker import cvw::*; #(parameter cvw_t P) ( logic AccessRW, AccessRWX, AccessRX; logic [10:0] SelRegions; logic AtomicAllowed; + logic CacheableRegion, IdempotentRegion; // Determine what type of access is being made assign AccessRW = ReadAccessM | WriteAccessM; @@ -54,11 +56,15 @@ module pmachecker import cvw::*; #(parameter cvw_t P) ( // Determine which region of physical memory (if any) is being accessed adrdecs #(P) adrdecs(PhysicalAddress, AccessRW, AccessRX, AccessRWX, Size, SelRegions); - // Only non-core RAM/ROM memory regions are cacheable - assign Cacheable = SelRegions[8] | SelRegions[7] | SelRegions[6]; // exclusion-tag: unused-cachable + // Only non-core RAM/ROM memory regions are cacheable. PBMT can override cachable; NC and IO are uncachable + assign CacheableRegion = SelRegions[8] | SelRegions[7] | SelRegions[6]; + assign Cacheable = (PBMemoryType == 2'b00) ? CacheableRegion : 0; // exclusion-tag: unused-cachable + // Nonidemdempotent means access could have side effect and must not be done speculatively or redundantly - // I/O is nonidempotent. - assign Idempotent = SelRegions[10] | SelRegions[9] | SelRegions[8] | SelRegions[7] | SelRegions[6]; // exclusion-tag: unused-idempotent + // I/O is nonidempotent. PBMT can override PMA; NC is idempotent and IO is non-idempotent + assign IdempotentRegion = SelRegions[10] | SelRegions[9] | SelRegions[8] | SelRegions[7] | SelRegions[6]; + assign Idempotent = (PBMemoryType == 2'b00) ? IdempotentRegion : (PBMemoryType == 2'b01); // exclusion-tag: unused-idempotent + // Atomic operations are only allowed on RAM assign AtomicAllowed = SelRegions[10] | SelRegions[8] | SelRegions[6]; // exclusion-tag: unused-atomic // Check if tightly integrated memories are selected diff --git a/src/mmu/tlb/tlb.sv b/src/mmu/tlb/tlb.sv index c0468aede..497a97fe5 100644 --- a/src/mmu/tlb/tlb.sv +++ b/src/mmu/tlb/tlb.sv @@ -57,12 +57,13 @@ module tlb import cvw::*; #(parameter cvw_t P, input logic [P.ASID_BITS-1:0] SATP_ASID, input logic STATUS_MXR, STATUS_SUM, STATUS_MPRV, input logic [1:0] STATUS_MPP, + input logic ENVCFG_PBMTE, // Page-based memory types enabled input logic [1:0] PrivilegeModeW, // Current privilege level of the processeor input logic ReadAccess, input logic WriteAccess, input logic DisableTranslation, input logic [P.XLEN-1:0] VAdr, // address input before translation (could be physical or virtual) - input logic [P.XLEN-1:0] PTE, + input logic [P.XLEN-1:0] PTE, // page table entry to write input logic [1:0] PageTypeWriteVal, input logic TLBWrite, input logic TLBFlush, @@ -71,10 +72,11 @@ module tlb import cvw::*; #(parameter cvw_t P, output logic TLBHit, output logic Translate, output logic TLBPageFault, - output logic UpdateDA + output logic UpdateDA, + output logic [1:0] PBMemoryType // PBMT field of PTE during TLB hit, or 00 otherwise ); - logic [TLB_ENTRIES-1:0] Matches, WriteEnables, PTE_Gs; // used as the one-hot encoding of WriteIndex + logic [TLB_ENTRIES-1:0] Matches, WriteEnables, PTE_Gs, PTE_NAPOTs; // used as the one-hot encoding of WriteIndex // Sections of the virtual and physical addresses logic [P.VPN_BITS-1:0] VPN; logic [P.PPN_BITS-1:0] PPN; @@ -84,7 +86,9 @@ module tlb import cvw::*; #(parameter cvw_t P, logic CAMHit; logic SV39Mode; logic Misaligned; + logic BadPTEWrite; // trying to write malformed PTE logic MegapageMisaligned; + logic PTE_N; // NAPOT page table entry if(P.XLEN == 32) begin assign MegapageMisaligned = |(PPN[9:0]); // must have zero PPN0 @@ -101,20 +105,28 @@ module tlb import cvw::*; #(parameter cvw_t P, assign VPN = VAdr[P.VPN_BITS+11:12]; - tlbcontrol #(P, ITLB) tlbcontrol(.SATP_MODE, .VAdr, .STATUS_MXR, .STATUS_SUM, .STATUS_MPRV, .STATUS_MPP, + // check if reserved, N, or PBMT bits are malformed when PTE is written in RV64 + assign BadPTEWrite = (P.XLEN == 64) & TLBWrite & ( + PTE[P.XLEN-1] & ~P.SVNAPOT_SUPPORTED | // N must be 0 if SVNAPOT is not supported + PTE[P.XLEN-2:P.XLEN-3] != 0 & ~P.SVPBMT_SUPPORTED | // PBMT must be 0 if SVBPMT is not supported + PTE[P.XLEN-2:P.XLEN-3] == 3 | // PBMT of 3 is reserved and never legal + PTE[P.XLEN-4:P.XLEN-10] != 0 ); // Reserved bits must be 0 + + tlbcontrol #(P, ITLB) tlbcontrol(.SATP_MODE, .VAdr, .STATUS_MXR, .STATUS_SUM, .STATUS_MPRV, .STATUS_MPP, .ENVCFG_PBMTE, .PrivilegeModeW, .ReadAccess, .WriteAccess, .DisableTranslation, .TLBFlush, - .PTEAccessBits, .CAMHit, .Misaligned, .TLBMiss, .TLBHit, .TLBPageFault, - .UpdateDA, .SV39Mode, .Translate); + .PTEAccessBits, .CAMHit, .Misaligned, .BadPTEWrite, + .TLBMiss, .TLBHit, .TLBPageFault, + .UpdateDA, .SV39Mode, .Translate, .PTE_N, .PBMemoryType); tlblru #(TLB_ENTRIES) lru(.clk, .reset, .TLBWrite, .TLBFlush, .Matches, .CAMHit, .WriteEnables); tlbcam #(P, TLB_ENTRIES, P.VPN_BITS + P.ASID_BITS, P.VPN_SEGMENT_BITS) - tlbcam(.clk, .reset, .VPN, .PageTypeWriteVal, .SV39Mode, .TLBFlush, .WriteEnables, .PTE_Gs, + tlbcam(.clk, .reset, .VPN, .PageTypeWriteVal, .SV39Mode, .TLBFlush, .WriteEnables, .PTE_Gs, .PTE_NAPOTs, .SATP_ASID, .Matches, .HitPageType, .CAMHit); - tlbram #(P, TLB_ENTRIES) tlbram(.clk, .reset, .PTE, .Matches, .WriteEnables, .PPN, .PTEAccessBits, .PTE_Gs); + tlbram #(P, TLB_ENTRIES) tlbram(.clk, .reset, .PTE, .Matches, .WriteEnables, .PPN, .PTEAccessBits, .PTE_Gs, .PTE_NAPOTs); // Replace segments of the virtual page number with segments of the physical // page number. For 4 KB pages, the entire virtual page number is replaced. // For superpages, some segments are considered offsets into a larger page. - tlbmixer #(P) Mixer(.VPN, .PPN, .HitPageType, .Offset(VAdr[11:0]), .TLBHit, .TLBPAdr); + tlbmixer #(P) Mixer(.VPN, .PPN, .HitPageType, .Offset(VAdr[11:0]), .TLBHit, .PTE_N, .TLBPAdr); endmodule diff --git a/src/mmu/tlb/tlbcam.sv b/src/mmu/tlb/tlbcam.sv index 7a4100829..e591498c4 100644 --- a/src/mmu/tlb/tlbcam.sv +++ b/src/mmu/tlb/tlbcam.sv @@ -38,7 +38,8 @@ module tlbcam import cvw::*; #(parameter cvw_t P, input logic TLBFlush, input logic [TLB_ENTRIES-1:0] WriteEnables, input logic [TLB_ENTRIES-1:0] PTE_Gs, - input logic [P.ASID_BITS-1:0] SATP_ASID, + input logic [TLB_ENTRIES-1:0] PTE_NAPOTs, // entry is in NAPOT mode (N bit set and PPN[3:0] = 1000) + input logic [P.ASID_BITS-1:0] SATP_ASID, output logic [TLB_ENTRIES-1:0] Matches, output logic [1:0] HitPageType, output logic CAMHit @@ -53,7 +54,7 @@ module tlbcam import cvw::*; #(parameter cvw_t P, // page number segments. tlbcamline #(P, KEY_BITS, SEGMENT_BITS) camlines[TLB_ENTRIES-1:0]( - .clk, .reset, .VPN, .SATP_ASID, .SV39Mode, .PTE_G(PTE_Gs), .PageTypeWriteVal, .TLBFlush, + .clk, .reset, .VPN, .SATP_ASID, .SV39Mode, .PTE_G(PTE_Gs), .PTE_NAPOT(PTE_NAPOTs), .PageTypeWriteVal, .TLBFlush, .WriteEnable(WriteEnables), .PageTypeRead, .Match(Matches)); assign CAMHit = |Matches & ~TLBFlush; or_rows #(TLB_ENTRIES,2) PageTypeOr(PageTypeRead, HitPageType); diff --git a/src/mmu/tlb/tlbcamline.sv b/src/mmu/tlb/tlbcamline.sv index 55023006f..9471fb3d9 100644 --- a/src/mmu/tlb/tlbcamline.sv +++ b/src/mmu/tlb/tlbcamline.sv @@ -37,6 +37,7 @@ module tlbcamline import cvw::*; #(parameter cvw_t P, input logic SV39Mode, input logic WriteEnable, // Write a new entry to this line input logic PTE_G, + input logic PTE_NAPOT, // entry is in NAPOT mode (N bit set and PPN[3:0] = 1000) input logic [1:0] PageTypeWriteVal, input logic TLBFlush, // Flush this line (set valid to 0) output logic [1:0] PageTypeRead, // *** should this be the stored version or the always updated one? @@ -76,7 +77,7 @@ module tlbcamline import cvw::*; #(parameter cvw_t P, end else begin: match logic [SEGMENT_BITS-1:0] Key2, Key3, Query2, Query3; - logic Match2, Match3; + logic Match2, Match3, MatchNAPOT; assign {Query3, Query2, Query1, Query0} = VPN; assign {Key_ASID, Key3, Key2, Key1, Key0} = Key; @@ -84,7 +85,9 @@ module tlbcamline import cvw::*; #(parameter cvw_t P, // Calculate the actual match value based on the input vpn and the page type. // For example, a gigapage in SV39 only cares about VPN[2], so VPN[0] and VPN[1] // should automatically match. - assign Match0 = (Query0 == Key0) | (PageType > 2'd0); // least signifcant section + // In Svnapot, if N bit is set and bottom 4 bits of PPN = 1000, then these bits don't need to match + assign MatchNAPOT = P.SVNAPOT_SUPPORTED & PTE_NAPOT & (Query0[SEGMENT_BITS-1:4] == Key0[SEGMENT_BITS-1:4]); + assign Match0 = (Query0 == Key0) | (PageType > 2'd0) | MatchNAPOT; // least significant section assign Match1 = (Query1 == Key1) | (PageType > 2'd1); assign Match2 = (Query2 == Key2) | (PageType > 2'd2); assign Match3 = (Query3 == Key3) | SV39Mode; // this should always match in sv39 because they aren't used diff --git a/src/mmu/tlb/tlbcontrol.sv b/src/mmu/tlb/tlbcontrol.sv index f996ce55d..bfd8a9251 100644 --- a/src/mmu/tlb/tlbcontrol.sv +++ b/src/mmu/tlb/tlbcontrol.sv @@ -31,6 +31,7 @@ module tlbcontrol import cvw::*; #(parameter cvw_t P, ITLB = 0) ( input logic [P.XLEN-1:0] VAdr, input logic STATUS_MXR, STATUS_SUM, STATUS_MPRV, input logic [1:0] STATUS_MPP, + input logic ENVCFG_PBMTE, // Page-based memory types enabled input logic [1:0] PrivilegeModeW, // Current privilege level of the processeor input logic ReadAccess, WriteAccess, input logic DisableTranslation, @@ -38,22 +39,27 @@ module tlbcontrol import cvw::*; #(parameter cvw_t P, ITLB = 0) ( input logic [10:0] PTEAccessBits, input logic CAMHit, input logic Misaligned, + input logic BadPTEWrite, // trying to write malformed PTE output logic TLBMiss, output logic TLBHit, output logic TLBPageFault, output logic UpdateDA, output logic SV39Mode, - output logic Translate + output logic Translate, + output logic PTE_N, // NAPOT page table entry + output logic [1:0] PBMemoryType // PBMT field of PTE during TLB hit, or 00 otherwise ); // Sections of the page table entry logic [1:0] EffectivePrivilegeMode; - logic PTE_N, PTE_D, PTE_A, PTE_U, PTE_X, PTE_W, PTE_R, PTE_V; // Useful PTE Control Bits + logic PTE_D, PTE_A, PTE_U, PTE_X, PTE_W, PTE_R, PTE_V; // Useful PTE Control Bits logic [1:0] PTE_PBMT; logic UpperBitsUnequal; logic TLBAccess; logic ImproperPrivilege; + logic BadPBMT; + logic CausePageFault; // Grab the sv mode from SATP and determine whether translation should occur assign EffectivePrivilegeMode = (ITLB == 1) ? PrivilegeModeW : (STATUS_MPRV ? STATUS_MPP : PrivilegeModeW); // DTLB uses MPP mode when MPRV is 1 @@ -66,10 +72,16 @@ module tlbcontrol import cvw::*; #(parameter cvw_t P, ITLB = 0) ( vm64check #(P) vm64check(.SATP_MODE, .VAdr, .SV39Mode, .UpperBitsUnequal); // unswizzle useful PTE bits - assign PTE_N = PTEAccessBits[10] & P.SVNAPOT_SUPPORTED; - assign PTE_PBMT = PTEAccessBits[9:8] & {2{P.SVPBMT_SUPPORTED}}; + assign PTE_N = PTEAccessBits[10]; + assign PTE_PBMT = PTEAccessBits[9:8]; assign {PTE_D, PTE_A} = PTEAccessBits[7:6]; assign {PTE_U, PTE_X, PTE_W, PTE_R, PTE_V} = PTEAccessBits[4:0]; + + // Page fault if PBMT is nonzero when SVPBMT is not supported and enabled + assign BadPBMT = PTE_PBMT != 0 & ~(P.SVPBMT_SUPPORTED & ENVCFG_PBMTE); + + // Send PMA a 2-bit MemoryType that is PBMT during leaf page table accesses and 0 otherwise + assign PBMemoryType = PTE_PBMT & {2{Translate & TLBHit & P.SVPBMT_SUPPORTED}}; // Check whether the access is allowed, page faulting if not. if (ITLB == 1) begin:itlb // Instruction TLB fault checking @@ -77,14 +89,11 @@ module tlbcontrol import cvw::*; #(parameter cvw_t P, ITLB = 0) ( // only execute non-user mode pages. assign ImproperPrivilege = ((EffectivePrivilegeMode == P.U_MODE) & ~PTE_U) | ((EffectivePrivilegeMode == P.S_MODE) & PTE_U); - if(P.SVADU_SUPPORTED) begin : hptwwrites - assign UpdateDA = Translate & TLBHit & ~PTE_A & ~TLBPageFault; - assign TLBPageFault = Translate & TLBHit & (ImproperPrivilege | ~PTE_X | UpperBitsUnequal | Misaligned | ~PTE_V); - end else begin - // fault for software handling if access bit is off - assign UpdateDA = ~PTE_A; - assign TLBPageFault = Translate & TLBHit & (ImproperPrivilege | ~PTE_X | UpdateDA | UpperBitsUnequal | Misaligned | ~PTE_V); - end + assign CausePageFault = ImproperPrivilege | ~PTE_X | UpperBitsUnequal | BadPTEWrite | BadPBMT | Misaligned | ~PTE_V | (~PTE_A & P.SVADU_SUPPORTED); + assign TLBPageFault = Translate & TLBHit & CausePageFault; + // Determine wheter to update DA bits + if(P.SVADU_SUPPORTED) assign UpdateDA = Translate & TLBHit & ~PTE_A & ~TLBPageFault; + else assign UpdateDA = ~PTE_A; end else begin:dtlb // Data TLB fault checking logic InvalidRead, InvalidWrite; diff --git a/src/mmu/tlb/tlbmixer.sv b/src/mmu/tlb/tlbmixer.sv index 07d6eb985..a19d5a2eb 100644 --- a/src/mmu/tlb/tlbmixer.sv +++ b/src/mmu/tlb/tlbmixer.sv @@ -30,18 +30,19 @@ //////////////////////////////////////////////////////////////////////////////////////////////// module tlbmixer import cvw::*; #(parameter cvw_t P) ( - input logic [P.VPN_BITS-1:0] VPN, - input logic [P.PPN_BITS-1:0] PPN, - input logic [1:0] HitPageType, - input logic [11:0] Offset, - input logic TLBHit, - output logic [P.PA_BITS-1:0] TLBPAdr + input logic [P.VPN_BITS-1:0] VPN, + input logic [P.PPN_BITS-1:0] PPN, + input logic [1:0] HitPageType, + input logic [11:0] Offset, + input logic TLBHit, + input logic PTE_N, // NAPOT page table entry + output logic [P.PA_BITS-1:0] TLBPAdr ); localparam EXTRA_BITS = P.PPN_BITS - P.VPN_BITS; logic [P.PPN_BITS-1:0] ZeroExtendedVPN; logic [P.PPN_BITS-1:0] PageNumberMask; - logic [P.PPN_BITS-1:0] PPNMixed; + logic [P.PPN_BITS-1:0] PPNMixed, PPNMixed2; // produce PageNumberMask with 1s where virtual page number bits should be untranslaetd for superpages if (P.XLEN == 32) @@ -57,11 +58,45 @@ module tlbmixer import cvw::*; #(parameter cvw_t P) ( // merge low segments of VPN with high segments of PPN decided by the pagetype. assign ZeroExtendedVPN = {{EXTRA_BITS{1'b0}}, VPN}; // forces the VPN to be the same width as PPN. - assign PPNMixed = PPN | ZeroExtendedVPN & PageNumberMask; // - //mux2 #(1) mixmux[P.PPN_BITS-1:0](ZeroExtendedVPN, PPN, PageNumberMask, PPNMixed); - //assign PPNMixed = (ZeroExtendedVPN & ~PageNumberMask) | (PPN & PageNumberMask); + assign PPNMixed = PPN | ZeroExtendedVPN & PageNumberMask; // low bits of PPN are already zero + + // In Svnapot, when N=1, use bottom bits of VPN for contiugous translations + if (P.SVNAPOT_SUPPORTED) begin + // 64 KiB contiguous NAPOT translations suported + logic [3:0] PPNMixedBot; + mux2 #(4) napotmux(PPNMixed[3:0], VPN, PTE_N, PPNMixedBot); + assign PPNMixed2 = {PPNMixed[P.PPN_BITS-1:4], PPNMixedBot}; + + /* // Generalized NAPOT implementation supporting various sized contiguous regions + // This would also require a priority encoder in the tlbcam + // Not yet tested + logic [8:0] NAPOTMask, NAPOTPN, PPNMixedBot; + always_comb begin + casez(PPN[8:0]) + 9'b100000000: NAPOTMask = 9'b111111111; + 9'b?10000000: NAPOTMask = 9'b011111111; + 9'b??1000000: NAPOTMask = 9'b001111111; + 9'b???100000: NAPOTMask = 9'b000111111; + 9'b????10000: NAPOTMask = 9'b000011111; + 9'b?????1000: NAPOTMask = 9'b000001111; + 9'b??????100: NAPOTMask = 9'b000000111; + 9'b???????10: NAPOTMask = 9'b000000011; + 9'b????????1: NAPOTMask = 9'b000000001; + default: NAPOTMask = 9'b000000000; + endcase + end + // check malformed NAPOT PPN, which should cause page fault + // Replace PPN with VPN in lower bits of page number based on mask + assign NAPOTPN = VPN & NAPOTMask | PPN & ~NAPOTMask; + mux2 #(9) napotmux(PPNMixed[8:0], NAPOTPN, PTE_N, PPNMixedBot); + assign PPNMixed2 = {PPNMixed[PPN_BITS-1:9], PPNMixedBot}; */ + + end else begin // no Svnapot + assign PPNMixed2 = PPNMixed; + end + // Output the hit physical address if translation is currently on. // Provide physical address of zero if not TLBHits, to cause segmentation error if miss somehow percolated through signal - mux2 #(P.PA_BITS) hitmux('0, {PPNMixed, Offset}, TLBHit, TLBPAdr); // set PA to 0 if TLB misses, to cause segementation error if this miss somehow passes through system + mux2 #(P.PA_BITS) hitmux('0, {PPNMixed2, Offset}, TLBHit, TLBPAdr); // set PA to 0 if TLB misses, to cause segementation error if this miss somehow passes through system endmodule diff --git a/src/mmu/tlb/tlbram.sv b/src/mmu/tlb/tlbram.sv index 50f6883b3..07d9dd87c 100644 --- a/src/mmu/tlb/tlbram.sv +++ b/src/mmu/tlb/tlbram.sv @@ -36,19 +36,20 @@ module tlbram import cvw::*; #(parameter cvw_t P, input logic [TLB_ENTRIES-1:0] Matches, WriteEnables, output logic [P.PPN_BITS-1:0] PPN, output logic [10:0] PTEAccessBits, - output logic [TLB_ENTRIES-1:0] PTE_Gs + output logic [TLB_ENTRIES-1:0] PTE_Gs, + output logic [TLB_ENTRIES-1:0] PTE_NAPOTs // entry is in NAPOT mode (N bit set and PPN[3:0] = 1000) ); logic [P.XLEN-1:0] RamRead[TLB_ENTRIES-1:0]; // stores the page table entries logic [P.XLEN-1:0] PageTableEntry; // RAM implemented with array of flops and AND/OR read logic - tlbramline #(P.XLEN) tlbramline[TLB_ENTRIES-1:0] + tlbramline #(P) tlbramline[TLB_ENTRIES-1:0] (.clk, .reset, .re(Matches), .we(WriteEnables), - .d(PTE), .q(RamRead), .PTE_G(PTE_Gs)); + .d(PTE), .q(RamRead), .PTE_G(PTE_Gs), .PTE_NAPOT(PTE_NAPOTs)); or_rows #(TLB_ENTRIES, P.XLEN) PTEOr(RamRead, PageTableEntry); // Rename the bits read from the TLB RAM - assign PTEAccessBits = {PageTableEntry[P.XLEN-1:P.XLEN-3], PageTableEntry[7:0]}; // include N and PBMT bits + assign PTEAccessBits = {PageTableEntry[P.XLEN-1:P.XLEN-3] & {3{P.XLEN == 64}}, PageTableEntry[7:0]}; // include N and PBMT bits assign PPN = PageTableEntry[P.PPN_BITS+9:10]; endmodule diff --git a/src/mmu/tlb/tlbramline.sv b/src/mmu/tlb/tlbramline.sv index cc393f72a..971e804ac 100644 --- a/src/mmu/tlb/tlbramline.sv +++ b/src/mmu/tlb/tlbramline.sv @@ -26,16 +26,26 @@ // and limitations under the License. //////////////////////////////////////////////////////////////////////////////////////////////// -module tlbramline #(parameter WIDTH = 22) - (input logic clk, reset, - input logic re, we, - input logic [WIDTH-1:0] d, - output logic [WIDTH-1:0] q, - output logic PTE_G); +module tlbramline import cvw::*; #(parameter cvw_t P) + (input logic clk, reset, + input logic re, we, + input logic [P.XLEN-1:0] d, + output logic [P.XLEN-1:0] q, + output logic PTE_G, + output logic PTE_NAPOT // entry is in NAPOT mode (N bit set and PPN[3:0] = 1000) +); - logic [WIDTH-1:0] line; + logic [P.XLEN-1:0] line; + + if (P.XLEN == 64) begin // save 7 reserved bits + // could optimize out N and PBMT from d[63:61] if they aren't supported + logic [56:0] ptereg; + flopenr #(57) pteflop(clk, reset, we, {d[63:61], d[53:0]}, ptereg); + assign line = {ptereg[56:54], 7'b0, ptereg[53:0]}; + end else // rv32 + flopenr #(P.XLEN) pteflop(clk, reset, we, d, line); - flopenr #(WIDTH) pteflop(clk, reset, we, d, line); assign q = re ? line : 0; assign PTE_G = line[5]; // send global bit to CAM as part of ASID matching + assign PTE_NAPOT = P.SVNAPOT_SUPPORTED & line[P.XLEN-1] & (line[13:10] == 4'b1000); // send NAPOT bit to CAM as part of matching lsbs of VPN endmodule diff --git a/src/privileged/csr.sv b/src/privileged/csr.sv index ccca40a00..f99ee28b1 100644 --- a/src/privileged/csr.sv +++ b/src/privileged/csr.sv @@ -85,6 +85,7 @@ module csr import cvw::*; #(parameter cvw_t P) ( output var logic [P.PA_BITS-3:0] PMPADDR_ARRAY_REGW[P.PMP_ENTRIES-1:0], output logic [2:0] FRM_REGW, output logic [3:0] ENVCFG_CBE, + output logic ENVCFG_PBMTE, // Page-based memory type enable // output logic [P.XLEN-1:0] CSRReadValW, // value read from CSR output logic [P.XLEN-1:0] UnalignedPCNextF, // Next PC, accounting for traps and returns @@ -127,7 +128,6 @@ module csr import cvw::*; #(parameter cvw_t P) ( logic [63:0] MENVCFG_REGW; logic [P.XLEN-1:0] SENVCFG_REGW; logic ENVCFG_STCE; // supervisor timer counter enable - logic ENVCFG_PBMTE; // page-based memory types enable logic ENVCFG_FIOM; // fence implies io (presently not used) // only valid unflushed instructions can access CSRs diff --git a/src/privileged/privileged.sv b/src/privileged/privileged.sv index 46c69f17d..619ed2b32 100644 --- a/src/privileged/privileged.sv +++ b/src/privileged/privileged.sv @@ -83,6 +83,7 @@ module privileged import cvw::*; #(parameter cvw_t P) ( output var logic [P.PA_BITS-3:0] PMPADDR_ARRAY_REGW [P.PMP_ENTRIES-1:0], // PMP address entries to MMU output logic [2:0] FRM_REGW, // FPU rounding mode output logic [3:0] ENVCFG_CBE, // Cache block operation enables + output logic ENVCFG_PBMTE, // Page-based memory type enable // PC logic output in privileged unit output logic [P.XLEN-1:0] UnalignedPCNextF, // Next PC from trap/return PC logic // control outputs @@ -137,7 +138,7 @@ module privileged import cvw::*; #(parameter cvw_t P) ( .STATUS_MIE, .STATUS_SIE, .STATUS_MXR, .STATUS_SUM, .STATUS_MPRV, .STATUS_TW, .STATUS_FS, .MEDELEG_REGW, .MIP_REGW, .MIE_REGW, .MIDELEG_REGW, .SATP_REGW, .PMPCFG_ARRAY_REGW, .PMPADDR_ARRAY_REGW, - .SetFflagsM, .FRM_REGW, .ENVCFG_CBE, + .SetFflagsM, .FRM_REGW, .ENVCFG_CBE, .ENVCFG_PBMTE, .CSRReadValW,.UnalignedPCNextF, .IllegalCSRAccessM, .BigEndianM); // pipeline early-arriving trap sources diff --git a/src/wally/wallypipelinedcore.sv b/src/wally/wallypipelinedcore.sv index 793ea5777..5fbc89a26 100644 --- a/src/wally/wallypipelinedcore.sv +++ b/src/wally/wallypipelinedcore.sv @@ -78,6 +78,7 @@ module wallypipelinedcore import cvw::*; #(parameter cvw_t P) ( logic LoadStallD, StoreStallD, MDUStallD, CSRRdStallD; logic SquashSCW; logic MDUActiveE; // Mul/Div instruction being executed + logic ENVCFG_PBMTE; // Page-based memory type enable logic [3:0] ENVCFG_CBE; // Cache Block operation enables logic [3:0] CMOpM; // 1: cbo.inval; 2: cbo.flush; 4: cbo.clean; 8: cbo.zero logic IFUPrefetchE, LSUPrefetchM; // instruction / data prefetch hints @@ -184,7 +185,7 @@ module wallypipelinedcore import cvw::*; #(parameter cvw_t P) ( .IllegalBaseInstrD, .IllegalFPUInstrD, .InstrPageFaultF, .IllegalIEUFPUInstrD, .InstrMisalignedFaultM, // mmu management .PrivilegeModeW, .PTE, .PageType, .SATP_REGW, .STATUS_MXR, .STATUS_SUM, .STATUS_MPRV, - .STATUS_MPP, .ITLBWriteF, .sfencevmaM, .ITLBMissF, + .STATUS_MPP, .ENVCFG_PBMTE, .ITLBWriteF, .sfencevmaM, .ITLBMissF, // pmp/pma (inside mmu) signals. .PMPCFG_ARRAY_REGW, .PMPADDR_ARRAY_REGW, .InstrAccessFaultF, .InstrUpdateDAF); @@ -231,7 +232,8 @@ module wallypipelinedcore import cvw::*; #(parameter cvw_t P) ( .STATUS_MXR, // from csr .STATUS_SUM, // from csr .STATUS_MPRV, // from csr - .STATUS_MPP, // from csr + .STATUS_MPP, // from csr + .ENVCFG_PBMTE, // from csr .sfencevmaM, // connects to privilege .DCacheStallM, // connects to privilege .LoadPageFaultM, // connects to privilege @@ -294,7 +296,7 @@ module wallypipelinedcore import cvw::*; #(parameter cvw_t P) ( .PrivilegeModeW, .SATP_REGW, .STATUS_MXR, .STATUS_SUM, .STATUS_MPRV, .STATUS_MPP, .STATUS_FS, .PMPCFG_ARRAY_REGW, .PMPADDR_ARRAY_REGW, - .FRM_REGW, .ENVCFG_CBE, .BreakpointFaultM, .EcallFaultM, .wfiM, .IntPendingM, .BigEndianM); + .FRM_REGW, .ENVCFG_CBE, .ENVCFG_PBMTE, .BreakpointFaultM, .EcallFaultM, .wfiM, .IntPendingM, .BigEndianM); end else begin assign CSRReadValW = 0; assign UnalignedPCNextF = PC2NextF;