From d526d288048b0635a4ca1849edc8a05042860c02 Mon Sep 17 00:00:00 2001 From: David Harris Date: Wed, 4 Oct 2023 09:34:28 -0700 Subject: [PATCH 1/3] Added MENVCFG.HADE bit and updated SVADU to depend on this bit --- src/ifu/ifu.sv | 27 +++++------ src/lsu/lsu.sv | 5 +- src/mmu/hptw.sv | 12 +++-- src/mmu/mmu.sv | 3 +- src/mmu/tlb/tlb.sv | 3 +- src/mmu/tlb/tlbcontrol.sv | 46 ++----------------- src/privileged/csr.sv | 2 + src/privileged/csrm.sv | 3 +- src/privileged/privileged.sv | 3 +- src/wally/wallypipelinedcore.sv | 6 ++- .../WALLY-mmu-sv32-svadu-01.reference_output | 11 ++++- .../rv32i_m/privilege/src/WALLY-TEST-LIB-32.h | 12 +++++ .../privilege/src/WALLY-mmu-sv32-svadu-01.S | 19 +++++++- ...9-svadu-svnapot-svpbmt-01.reference_output | 18 +++++++- .../WALLY-mmu-sv48-svadu-01.reference_output | 18 +++++++- .../WALLY-mmu-sv39-svadu-svnapot-svpbmt-01.S | 20 +++++++- .../privilege/src/WALLY-mmu-sv48-svadu-01.S | 16 +++++++ 17 files changed, 147 insertions(+), 77 deletions(-) diff --git a/src/ifu/ifu.sv b/src/ifu/ifu.sv index 6c81c6b99..d63a987b2 100644 --- a/src/ifu/ifu.sv +++ b/src/ifu/ifu.sv @@ -70,23 +70,24 @@ module ifu import cvw::*; #(parameter cvw_t P) ( output logic IClassWrongM, // Class prediction is wrong output logic ICacheStallF, // I$ busy with multicycle operation // Faults - input logic IllegalBaseInstrD, // Illegal non-compressed instruction - input logic IllegalFPUInstrD, // Illegal FP instruction + input logic IllegalBaseInstrD, // Illegal non-compressed instruction + input logic IllegalFPUInstrD, // Illegal FP instruction output logic InstrPageFaultF, // Instruction page fault output logic IllegalIEUFPUInstrD, // Illegal instruction including compressed & FP output logic InstrMisalignedFaultM, // Branch target not aligned to 4 bytes if no compressed allowed (2 bytes if allowed) // mmu management - input logic [1:0] PrivilegeModeW, // Priviledge mode in Writeback stage - input logic [P.XLEN-1:0] PTE, // Hardware page table walker (HPTW) writes Page table entry (PTE) to ITLB - input logic [1:0] PageType, // Hardware page table walker (HPTW) writes PageType to ITLB - input logic ITLBWriteF, // Writes PTE and PageType to ITLB - input logic [P.XLEN-1:0] SATP_REGW, // Location of the root page table and page table configuration - input logic STATUS_MXR, // Status CSR: make executable page readable - 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 [1:0] PrivilegeModeW, // Priviledge mode in Writeback stage + input logic [P.XLEN-1:0] PTE, // Hardware page table walker (HPTW) writes Page table entry (PTE) to ITLB + input logic [1:0] PageType, // Hardware page table walker (HPTW) writes PageType to ITLB + input logic ITLBWriteF, // Writes PTE and PageType to ITLB + input logic [P.XLEN-1:0] SATP_REGW, // Location of the root page table and page table configuration + input logic STATUS_MXR, // Status CSR: make executable page readable + 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 + input logic ENVCFG_HADE, // HPTW A/D Update enable + 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 input var logic [7:0] PMPCFG_ARRAY_REGW[P.PMP_ENTRIES-1:0], // PMP configuration from privileged unit @@ -171,7 +172,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, .ENVCFG_PBMTE, + immu(.clk, .reset, .SATP_REGW, .STATUS_MXR, .STATUS_SUM, .STATUS_MPRV, .STATUS_MPP, .ENVCFG_PBMTE, .ENVCFG_HADE, .PrivilegeModeW, .DisableTranslation(1'b0), .VAdr(PCFExt), .Size(2'b10), diff --git a/src/lsu/lsu.sv b/src/lsu/lsu.sv index e120d454b..191599f12 100644 --- a/src/lsu/lsu.sv +++ b/src/lsu/lsu.sv @@ -81,6 +81,7 @@ module lsu import cvw::*; #(parameter cvw_t P) ( 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 ENVCFG_HADE, // HPTW A/D Update enable 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 @@ -153,7 +154,7 @@ module lsu import cvw::*; #(parameter cvw_t P) ( hptw #(P) hptw(.clk, .reset, .MemRWM, .AtomicM, .ITLBMissF, .ITLBWriteF, .DTLBMissM, .DTLBWriteM, .InstrUpdateDAF, .DataUpdateDAM, .FlushW, .DCacheStallM, .SATP_REGW, .PCSpillF, - .STATUS_MXR, .STATUS_SUM, .STATUS_MPRV, .STATUS_MPP, .PrivilegeModeW, + .STATUS_MXR, .STATUS_SUM, .STATUS_MPRV, .STATUS_MPP, .ENVCFG_HADE, .PrivilegeModeW, .ReadDataM(ReadDataM[P.XLEN-1:0]), // ReadDataM is LLEN, but HPTW only needs XLEN .WriteDataM, .Funct3M, .LSUFunct3M, .Funct7M, .LSUFunct7M, .IEUAdrExtM, .PTE, .IHWriteDataM, .PageType, .PreLSURWM, .LSUAtomicM, @@ -190,7 +191,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, .ENVCFG_PBMTE, + dmmu(.clk, .reset, .SATP_REGW, .STATUS_MXR, .STATUS_SUM, .STATUS_MPRV, .STATUS_MPP, .ENVCFG_PBMTE, .ENVCFG_HADE, .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/hptw.sv b/src/mmu/hptw.sv index 410d1bf91..64752a992 100644 --- a/src/mmu/hptw.sv +++ b/src/mmu/hptw.sv @@ -38,6 +38,7 @@ module hptw import cvw::*; #(parameter cvw_t P) ( // system status input logic STATUS_MXR, STATUS_SUM, STATUS_MPRV, input logic [1:0] STATUS_MPP, + input logic ENVCFG_HADE, // HPTW A/D Update enable input logic [1:0] PrivilegeModeW, input logic [P.XLEN-1:0] ReadDataM, // page table entry from LSU input logic [P.XLEN-1:0] WriteDataM, @@ -153,7 +154,7 @@ module hptw import cvw::*; #(parameter cvw_t P) ( logic [P.XLEN-1:0] AccessedPTE; assign AccessedPTE = {PTE[P.XLEN-1:8], (SetDirty | PTE[7]), 1'b1, PTE[5:0]}; // set accessed bit, conditionally set dirty bit - mux2 #(P.XLEN) NextPTEMux(ReadDataM, AccessedPTE, UpdatePTE, NextPTE); + mux2 #(P.XLEN) NextPTEMux(ReadDataM, AccessedPTE, UpdatePTE, NextPTE); // NextPTE = ReadDataM when HADE = 0 because UpdatePTE = 0 flopenr #(P.PA_BITS) HPTWAdrWriteReg(clk, reset, SaveHPTWAdr, HPTWReadAdr, HPTWWriteAdr); assign SaveHPTWAdr = WalkerState == L0_ADR; @@ -182,11 +183,12 @@ module hptw import cvw::*; #(parameter cvw_t P) ( // hptw needs to know if there is a Dirty or Access fault occuring on this // 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. - assign HPTWUpdateDA = ValidLeafPTE & (~Accessed | SetDirty) & ~OtherPageFault; + // However any other fault should not cause the update, and updates are in software when ENVCFG_HADE = 0 + assign HPTWUpdateDA = ValidLeafPTE & (~Accessed | SetDirty) & ENVCFG_HADE & ~OtherPageFault; + + assign HPTWRW[0] = (WalkerState == UPDATE_PTE); // HPTWRW[0] will always be 0 if HADE = 0 because HPTWUpdateDA will be 0 so WalkerState never is UPDATE_PTE + assign UpdatePTE = (WalkerState == LEAF) & HPTWUpdateDA; // UpdatePTE will always be 0 if HADE = 0 because HPTWUpdateDA will be 0 - assign HPTWRW[0] = (WalkerState == UPDATE_PTE); - assign UpdatePTE = (WalkerState == LEAF) & HPTWUpdateDA; end else begin // block: hptwwrites assign NextPTE = ReadDataM; assign HPTWAdr = HPTWReadAdr; diff --git a/src/mmu/mmu.sv b/src/mmu/mmu.sv index e8e06fde0..32fed853d 100644 --- a/src/mmu/mmu.sv +++ b/src/mmu/mmu.sv @@ -35,6 +35,7 @@ module mmu import cvw::*; #(parameter cvw_t P, 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 ENVCFG_HADE, // HPTW A/D Update enable 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 @@ -82,7 +83,7 @@ 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, .ENVCFG_PBMTE, + .VAdr(VAdr[P.XLEN-1:0]), .STATUS_MXR, .STATUS_SUM, .STATUS_MPRV, .STATUS_MPP, .ENVCFG_PBMTE, .ENVCFG_HADE, .PrivilegeModeW, .ReadAccess, .WriteAccess, .DisableTranslation, .PTE, .PageTypeWriteVal, .TLBWrite, .TLBFlush, .TLBPAdr, .TLBMiss, .TLBHit, diff --git a/src/mmu/tlb/tlb.sv b/src/mmu/tlb/tlb.sv index 9619c958d..861e721b6 100644 --- a/src/mmu/tlb/tlb.sv +++ b/src/mmu/tlb/tlb.sv @@ -58,6 +58,7 @@ module tlb import cvw::*; #(parameter cvw_t P, 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 ENVCFG_HADE, // HPTW A/D Update enable input logic [1:0] PrivilegeModeW, // Current privilege level of the processeor input logic ReadAccess, input logic WriteAccess, @@ -104,7 +105,7 @@ 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, .ENVCFG_PBMTE, + tlbcontrol #(P, ITLB) tlbcontrol(.SATP_MODE, .VAdr, .STATUS_MXR, .STATUS_SUM, .STATUS_MPRV, .STATUS_MPP, .ENVCFG_PBMTE, .ENVCFG_HADE, .PrivilegeModeW, .ReadAccess, .WriteAccess, .DisableTranslation, .TLBFlush, .PTEAccessBits, .CAMHit, .Misaligned, .TLBMiss, .TLBHit, .TLBPageFault, diff --git a/src/mmu/tlb/tlbcontrol.sv b/src/mmu/tlb/tlbcontrol.sv index 3c2f81697..666448b12 100644 --- a/src/mmu/tlb/tlbcontrol.sv +++ b/src/mmu/tlb/tlbcontrol.sv @@ -32,10 +32,11 @@ module tlbcontrol import cvw::*; #(parameter cvw_t P, ITLB = 0) ( 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 ENVCFG_HADE, // HPTW A/D Update enable + input logic [1:0] PrivilegeModeW, // Current privilege level of the processeor input logic ReadAccess, WriteAccess, input logic DisableTranslation, - input logic TLBFlush, // Invalidate all TLB entries + input logic TLBFlush, // Invalidate all TLB entries input logic [11:0] PTEAccessBits, input logic CAMHit, input logic Misaligned, @@ -114,50 +115,13 @@ module tlbcontrol import cvw::*; #(parameter cvw_t P, ITLB = 0) ( end // Determine wheter to update DA bits. With SVADU, it is done in hardware - if (P.SVADU_SUPPORTED) assign UpdateDA = PreUpdateDA & Translate & TLBHit & ~TLBPageFault; + if (P.SVADU_SUPPORTED) assign UpdateDA = PreUpdateDA & Translate & TLBHit & ~TLBPageFault & ENVCFG_HADE; else assign UpdateDA = PreUpdateDA; // Determine whether page fault occurs - assign PrePageFault = UpperBitsUnequal | Misaligned | ~PTE_V | ImproperPrivilege | (P.XLEN == 64 & (BadPBMT | BadNAPOT | BadReserved)) | (PreUpdateDA & ~P.SVADU_SUPPORTED); + assign PrePageFault = UpperBitsUnequal | Misaligned | ~PTE_V | ImproperPrivilege | (P.XLEN == 64 & (BadPBMT | BadNAPOT | BadReserved)) | (PreUpdateDA & (~P.SVADU_SUPPORTED | ~ENVCFG_HADE)); assign TLBPageFault = Translate & TLBHit & (PrePageFault | InvalidAccess); -/* - // Check whether the access is allowed, page faulting if not. - if (ITLB == 1) begin:itlb // Instruction TLB fault checking - // User mode may only execute user mode pages, and supervisor mode may - // only execute non-user mode pages. - assign ImproperPrivilege = ((EffectivePrivilegeMode == P.U_MODE) & ~PTE_U) | - ((EffectivePrivilegeMode == P.S_MODE) & PTE_U); - assign CausePageFault = ImproperPrivilege | ~PTE_X | UpperBitsUnequal | BadPTE | 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; - - // User mode may only load/store from user mode pages, and supervisor mode - // may only access user mode pages when STATUS_SUM is low. - assign ImproperPrivilege = ((EffectivePrivilegeMode == P.U_MODE) & ~PTE_U) | - ((EffectivePrivilegeMode == P.S_MODE) & PTE_U & ~STATUS_SUM); - // Check for read error. Reads are invalid when the page is not readable - // (and executable pages are not readable) or when the page is neither - // readable nor executable (and executable pages are readable). - assign InvalidRead = ReadAccess & ~PTE_R & (~STATUS_MXR | ~PTE_X); - // Check for write error. Writes are invalid when the page's write bit is - // low. - assign InvalidWrite = WriteAccess & ~PTE_W; - if(P.SVADU_SUPPORTED) begin : hptwwrites - assign UpdateDA = Translate & TLBHit & (~PTE_A | WriteAccess & ~PTE_D) & ~TLBPageFault; - assign TLBPageFault = (Translate & TLBHit & (ImproperPrivilege | InvalidRead | InvalidWrite | UpperBitsUnequal | Misaligned | ~PTE_V)); // *** update to match - end else begin - // Fault for software handling if access bit is off or writing a page with dirty bit off - assign UpdateDA = ~PTE_A | WriteAccess & ~PTE_D; - assign TLBPageFault = (Translate & TLBHit & (ImproperPrivilege | InvalidRead | InvalidWrite | UpdateDA | UpperBitsUnequal | Misaligned | ~PTE_V)); - end - end -*/ - assign TLBHit = CAMHit & TLBAccess; assign TLBMiss = ~CAMHit & TLBAccess & Translate ; endmodule diff --git a/src/privileged/csr.sv b/src/privileged/csr.sv index f99ee28b1..4cdce4989 100644 --- a/src/privileged/csr.sv +++ b/src/privileged/csr.sv @@ -86,6 +86,7 @@ module csr import cvw::*; #(parameter cvw_t P) ( output logic [2:0] FRM_REGW, output logic [3:0] ENVCFG_CBE, output logic ENVCFG_PBMTE, // Page-based memory type enable + output logic ENVCFG_HADE, // HPTW A/D Update 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 @@ -292,6 +293,7 @@ module csr import cvw::*; #(parameter cvw_t P) ( // Broadcast appropriate environment configuration based on privilege mode assign ENVCFG_STCE = MENVCFG_REGW[63]; // supervisor timer counter enable assign ENVCFG_PBMTE = MENVCFG_REGW[62]; // page-based memory types enable + assign ENVCFG_HADE = MENVCFG_REGW[61]; // Hardware A/D Update enable assign ENVCFG_CBE = (PrivilegeModeW == P.M_MODE) ? 4'b1111 : (PrivilegeModeW == P.S_MODE | !P.S_SUPPORTED) ? MENVCFG_REGW[7:4] : (MENVCFG_REGW[7:4] & SENVCFG_REGW[7:4]); diff --git a/src/privileged/csrm.sv b/src/privileged/csrm.sv index 359406b1f..ad1f9b75d 100644 --- a/src/privileged/csrm.sv +++ b/src/privileged/csrm.sv @@ -172,7 +172,8 @@ module csrm import cvw::*; #(parameter cvw_t P) ( assign MENVCFG_WriteValM = { MENVCFG_PreWriteValM[63] & P.SSTC_SUPPORTED, MENVCFG_PreWriteValM[62] & P.SVPBMT_SUPPORTED, - 54'b0, + MENVCFG_PreWriteValM[61] & P.SVADU_SUPPORTED, + 53'b0, MENVCFG_PreWriteValM[7] & P.ZICBOZ_SUPPORTED, MENVCFG_PreWriteValM[6:4] & {3{P.ZICBOM_SUPPORTED}}, 3'b0, diff --git a/src/privileged/privileged.sv b/src/privileged/privileged.sv index 619ed2b32..fff4af8b8 100644 --- a/src/privileged/privileged.sv +++ b/src/privileged/privileged.sv @@ -84,6 +84,7 @@ module privileged import cvw::*; #(parameter cvw_t P) ( 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 + output logic ENVCFG_HADE, // HPTW A/D Update enable // PC logic output in privileged unit output logic [P.XLEN-1:0] UnalignedPCNextF, // Next PC from trap/return PC logic // control outputs @@ -138,7 +139,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, .ENVCFG_PBMTE, + .SetFflagsM, .FRM_REGW, .ENVCFG_CBE, .ENVCFG_PBMTE, .ENVCFG_HADE, .CSRReadValW,.UnalignedPCNextF, .IllegalCSRAccessM, .BigEndianM); // pipeline early-arriving trap sources diff --git a/src/wally/wallypipelinedcore.sv b/src/wally/wallypipelinedcore.sv index 5fbc89a26..00b348660 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_HADE; // HPTW A/D Update enable 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 @@ -185,7 +186,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, .ENVCFG_PBMTE, .ITLBWriteF, .sfencevmaM, .ITLBMissF, + .STATUS_MPP, .ENVCFG_PBMTE, .ENVCFG_HADE, .ITLBWriteF, .sfencevmaM, .ITLBMissF, // pmp/pma (inside mmu) signals. .PMPCFG_ARRAY_REGW, .PMPADDR_ARRAY_REGW, .InstrAccessFaultF, .InstrUpdateDAF); @@ -234,6 +235,7 @@ module wallypipelinedcore import cvw::*; #(parameter cvw_t P) ( .STATUS_MPRV, // from csr .STATUS_MPP, // from csr .ENVCFG_PBMTE, // from csr + .ENVCFG_HADE, // from csr .sfencevmaM, // connects to privilege .DCacheStallM, // connects to privilege .LoadPageFaultM, // connects to privilege @@ -296,7 +298,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, .ENVCFG_PBMTE, .BreakpointFaultM, .EcallFaultM, .wfiM, .IntPendingM, .BigEndianM); + .FRM_REGW, .ENVCFG_CBE, .ENVCFG_PBMTE, .ENVCFG_HADE, .BreakpointFaultM, .EcallFaultM, .wfiM, .IntPendingM, .BigEndianM); end else begin assign CSRReadValW = 0; assign UnalignedPCNextF = PC2NextF; diff --git a/tests/wally-riscv-arch-test/riscv-test-suite/rv32i_m/privilege/references/WALLY-mmu-sv32-svadu-01.reference_output b/tests/wally-riscv-arch-test/riscv-test-suite/rv32i_m/privilege/references/WALLY-mmu-sv32-svadu-01.reference_output index 9d88117e6..6a88d9ec7 100644 --- a/tests/wally-riscv-arch-test/riscv-test-suite/rv32i_m/privilege/references/WALLY-mmu-sv32-svadu-01.reference_output +++ b/tests/wally-riscv-arch-test/riscv-test-suite/rv32i_m/privilege/references/WALLY-mmu-sv32-svadu-01.reference_output @@ -35,8 +35,15 @@ beef0110 0000000f 0000000c 00000bad -beef0770 # Test 11.3.1.3.5: check successful read/write when A=0 and SVADU=1 -beef0aa0 # Test 11.3.1.3.6: check successful read/write when D=0 and SVADU=1 +0000000f # Test 11.3.1.3.6(a) page fault on write when A = 0 +0000000d # Test 11.3.1.3.6(a) page fault on read when A = 0 +00000bad +0000000f # Test 11.3.1.3.7(a) page fault on write when D = 0 +deadbeef # Test 11.3.1.3.7(a) successful read when D = 0 +00000009 # call from going to m mode from s mode +0000000b # ecall from going to S mode from m mode +beef0770 # Test 11.3.1.3.6: check successful read/write when A=0 and MENVCFG.HADE=1 +beef0aa0 # Test 11.3.1.3.7: check successful read/write when D=0 and MENVCFG.HADE=1 beef0077 # Test 11.3.1.4.1: successful read back of saved value with new memory mapping 00000009 # Test 11.3.1.5.1: ecall from going to m mode from s mode 00000000 # previous value of mprv before being set diff --git a/tests/wally-riscv-arch-test/riscv-test-suite/rv32i_m/privilege/src/WALLY-TEST-LIB-32.h b/tests/wally-riscv-arch-test/riscv-test-suite/rv32i_m/privilege/src/WALLY-TEST-LIB-32.h index c51eec965..b6304fbc6 100644 --- a/tests/wally-riscv-arch-test/riscv-test-suite/rv32i_m/privilege/src/WALLY-TEST-LIB-32.h +++ b/tests/wally-riscv-arch-test/riscv-test-suite/rv32i_m/privilege/src/WALLY-TEST-LIB-32.h @@ -1324,6 +1324,18 @@ write_mideleg: csrw mideleg, t4 j test_loop +write_menvcfg: + // writes the value in t4 to the menvcfg register + // Doesn't log anything + csrw menvcfg, t4 + j test_loop + +write_menvcfgh: + // writes the value in t4 to the menvcfgh register + // Doesn't log anything + csrw menvcfgh, t4 + j test_loop + executable_test: // Execute the code at the address in t3, returning the value in t2. // Assumes the code modifies t2, to become the value stored in t4 for this test. diff --git a/tests/wally-riscv-arch-test/riscv-test-suite/rv32i_m/privilege/src/WALLY-mmu-sv32-svadu-01.S b/tests/wally-riscv-arch-test/riscv-test-suite/rv32i_m/privilege/src/WALLY-mmu-sv32-svadu-01.S index 1a4a32cba..6a40d3b17 100644 --- a/tests/wally-riscv-arch-test/riscv-test-suite/rv32i_m/privilege/src/WALLY-mmu-sv32-svadu-01.S +++ b/tests/wally-riscv-arch-test/riscv-test-suite/rv32i_m/privilege/src/WALLY-mmu-sv32-svadu-01.S @@ -157,13 +157,28 @@ test_cases: .4byte 0xBFFDE0, 0xbad, executable_test # instr page fault when X=0 # In the following two tests, SVADU is supported, so the hardware handles the A/D bits +# Initially test with HADE = 0, so needing to set A/D bits triggers page fault + +# test 11.3.1.3.6(a) Accessed flag == 0 +.4byte 0x3020, 0xBEEF0770, write32_test # store page fault when A=0 +.4byte 0x3020, 0xBEEF0770, read32_test # load page fault when A=0 + +# test 11.3.1.3.7(a) Dirty flag == 0 +.4byte 0x4658, 0xBEEF0AA0, write32_test # store page fault when D=0 +.4byte 0x4658, 0xDEADBEEF, read32_test # read success when D=0; default DEADBEEF value wasn't changed + +# Now set HADE bit +.4byte 0x0, 0x0, goto_m_mode # change to M mode, 0x9 written to output +.4byte 0x0, 0x20000000, write_menvcfgh # set menvcfg.HADE = 1 +.4byte 0x0, 0x0, goto_s_mode # change to S mode, 0xb written to output + # Since SVADU is 1, there are no faults when A/D=0 -# test 11.3.1.3.6 Accessed flag == 0 +# test 11.3.1.3.6(b) Accessed flag == 0 .4byte 0x3020, 0xBEEF0770, write32_test # Write success when A=0 and SVADU is enabled .4byte 0x3020, 0xBEEF0770, read32_test # Read success when A=0 and SVADU is enabled -# test 11.3.1.3.7 Dirty flag == 0 +# test 11.3.1.3.7(b) Dirty flag == 0 .4byte 0x4658, 0xBEEF0AA0, write32_test # write successs when D=0 and SVADU is enabled .4byte 0x4658, 0xBEEF0AA0, read32_test # read success when D=0 diff --git a/tests/wally-riscv-arch-test/riscv-test-suite/rv64i_m/privilege/references/WALLY-mmu-sv39-svadu-svnapot-svpbmt-01.reference_output b/tests/wally-riscv-arch-test/riscv-test-suite/rv64i_m/privilege/references/WALLY-mmu-sv39-svadu-svnapot-svpbmt-01.reference_output index 93e4557a5..320d3f9c4 100644 --- a/tests/wally-riscv-arch-test/riscv-test-suite/rv64i_m/privilege/references/WALLY-mmu-sv39-svadu-svnapot-svpbmt-01.reference_output +++ b/tests/wally-riscv-arch-test/riscv-test-suite/rv64i_m/privilege/references/WALLY-mmu-sv39-svadu-svnapot-svpbmt-01.reference_output @@ -84,9 +84,23 @@ beef0110 # Test 11.3.1.3.4: read test success 00000000 00000bad 00000000 -beef0770 # Test 11.3.1.3.6: check successful read/write when A=0 and SVADU=1 +0000000f # Test 11.3.1.3.6(a): write test with page fault +00000000 +0000000d # read test with page fault +00000000 +00000bad +00000000 +0000000f # Test 11.3.1.3.7(a): write test with page fault +00000000 +deadbeef # read test success but nothing was written so read back default +deadbeef +00000009 # ecall from going to M mode from S mode +00000000 +0000000B # ecall from going to S mode from M mode +00000000 +beef0770 # Test 11.3.1.3.6(b): check successful read/write when A=0 and SVADU=1 0990dead -beef0aa0 # Test 11.3.1.3.7: check successful read/write when D=0 and SVADU=1 +beef0aa0 # Test 11.3.1.3.7(b): check successful read/write when D=0 and SVADU=1 0440dead 0000000d # Test 11.3.1.3.8: read test with page fault for nonzero reserved bit 00000000 diff --git a/tests/wally-riscv-arch-test/riscv-test-suite/rv64i_m/privilege/references/WALLY-mmu-sv48-svadu-01.reference_output b/tests/wally-riscv-arch-test/riscv-test-suite/rv64i_m/privilege/references/WALLY-mmu-sv48-svadu-01.reference_output index 60fce42ef..dd3801705 100644 --- a/tests/wally-riscv-arch-test/riscv-test-suite/rv64i_m/privilege/references/WALLY-mmu-sv48-svadu-01.reference_output +++ b/tests/wally-riscv-arch-test/riscv-test-suite/rv64i_m/privilege/references/WALLY-mmu-sv48-svadu-01.reference_output @@ -92,9 +92,23 @@ beef0110 # Test 11.3.1.3.4: read test success 00000000 00000bad 00000000 -beef0770 # Test 11.3.1.3.5: check successful read/write when A=0 and SVADU=1 +0000000f # Test 11.3.1.3.6(a): write test with page fault +00000000 +0000000d # read test with page fault +00000000 +00000bad +00000000 +0000000f # Test 11.3.1.3.7(a): write test with page fault +00000000 +deadbeef # read test success but get deadbeef because nothing was written +deadbeef +00000009 # ecall from going to M mode from S mode +00000000 +0000000B # ecall from going to S mode from M mode +00000000 +beef0770 # Test 11.3.1.3.6(b): check successful read/write when A=0 and SVADU=1 0990dead -beef0aa0 # Test 11.3.1.3.6: check successful read/write when D=0 and SVADU=1 +beef0aa0 # Test 11.3.1.3.7(b): check successful read/write when D=0 and SVADU=1 0440dead beef0000 # Test 11.3.1.4.1: read test success on new page table mapping 0000dead diff --git a/tests/wally-riscv-arch-test/riscv-test-suite/rv64i_m/privilege/src/WALLY-mmu-sv39-svadu-svnapot-svpbmt-01.S b/tests/wally-riscv-arch-test/riscv-test-suite/rv64i_m/privilege/src/WALLY-mmu-sv39-svadu-svnapot-svpbmt-01.S index aae04dd68..7da29bb94 100644 --- a/tests/wally-riscv-arch-test/riscv-test-suite/rv64i_m/privilege/src/WALLY-mmu-sv39-svadu-svnapot-svpbmt-01.S +++ b/tests/wally-riscv-arch-test/riscv-test-suite/rv64i_m/privilege/src/WALLY-mmu-sv39-svadu-svnapot-svpbmt-01.S @@ -194,13 +194,29 @@ test_cases: # *** fetches on pages with X = 1 already tested in 11.3.1.3.1 .8byte 0x5AA0, 0x1, executable_test # instr page fault when X=0 + # In the following two tests, SVADU is supported, so the hardware handles the A/D bits +# Initially test with HADE = 0, so needing to set A/D bits triggers page fault + +# test 11.3.1.3.6(a) Accessed flag == 0 +.8byte 0x36D0, 0x0990DEADBEEF0770, write64_test# store page fault when A=0 +.8byte 0x3AB8, 0x0990DEADBEEF0990, read64_test# load page fault when A=0 + +# test 11.3.1.3.7(a) Dirty flag == 0 +.8byte 0x4658, 0x0440DEADBEEF0AA0, write64_test# store page fault when D=0 +.8byte 0x4AA0, 0xDEADBEEFDEADBEEF, read64_test# read success when D=0 + +# Now set HADE bit +.8byte 0x0, 0x0, goto_m_mode # change to M mode, 0x9 written to output +.8byte 0x0, 0x2000000000000000, write_menvcfg # set menvcfg.HADE = 1 +.8byte 0x0, 0x0, goto_s_mode # change to S mode, 0xb written to output + # Since SVADU is 1, there are no faults when A/D=0 -# test 11.3.1.3.6 Accessed flag == 0 +# test 11.3.1.3.6(b) Accessed flag == 0 .8byte 0x36D0, 0x0990DEADBEEF0770, write64_test # Write success when A=0 and SVADU is enabled .8byte 0x36D0, 0x0990DEADBEEF0770, read64_test # Read success when A=0 and SVADU is enabled -# test 11.3.1.3.7 Dirty flag == 0 +# test 11.3.1.3.7(b) Dirty flag == 0 .8byte 0x4658, 0x0440DEADBEEF0AA0, write64_test # Write success when D=0 and SVADU is enabled .8byte 0x4658, 0x0440DEADBEEF0AA0, read64_test # read success when D=0 diff --git a/tests/wally-riscv-arch-test/riscv-test-suite/rv64i_m/privilege/src/WALLY-mmu-sv48-svadu-01.S b/tests/wally-riscv-arch-test/riscv-test-suite/rv64i_m/privilege/src/WALLY-mmu-sv48-svadu-01.S index dc8424f14..96d5aec11 100644 --- a/tests/wally-riscv-arch-test/riscv-test-suite/rv64i_m/privilege/src/WALLY-mmu-sv48-svadu-01.S +++ b/tests/wally-riscv-arch-test/riscv-test-suite/rv64i_m/privilege/src/WALLY-mmu-sv48-svadu-01.S @@ -187,7 +187,23 @@ test_cases: # executes on pages with X = 1 already tested in 11.3.1.3.1 .8byte 0x010088888000, 0x2, executable_test # execute fault when X=0 + # In the following two tests, SVADU is supported, so the hardware handles the A/D bits +# Initially test with HADE = 0, so needing to set A/D bits triggers page fault + +# test 11.3.1.3.6(a) Accessed flag == 0 +.8byte 0x802036D0, 0x0990DEADBEEF0770, write64_test # store page fault when A=0 +.8byte 0x802036D0, 0x0990DEADBEEF0990, read64_test # load page fault when A=0 + +# test 11.3.1.3.7(a) Dirty flag == 0 +.8byte 0x80204658, 0x0440DEADBEEF0AA0, write64_test # store page fault when D=0 +.8byte 0x80204658, 0xDEADBEEFDEADBEEF, read64_test # read success when D=0 + +# Now set HADE bit +.8byte 0x0, 0x0, goto_m_mode # change to M mode, 0x9 written to output +.8byte 0x0, 0x2000000000000000, write_menvcfg # set menvcfg.HADE = 1 +.8byte 0x0, 0x0, goto_s_mode # change to S mode, 0xb written to output + # Since SVADU is 1, there are no faults when A/D=0 # test 11.3.1.3.6 Accessed flag == 0 From 19a6bbb01bf1c2b379446a4166e6cd1b96ae42f8 Mon Sep 17 00:00:00 2001 From: David Harris Date: Wed, 4 Oct 2023 09:57:13 -0700 Subject: [PATCH 2/3] UpdateDA cleanup: don't assert UpdateDA when there is no SVADU --- src/ifu/spill.sv | 1 + src/mmu/tlb/tlbcontrol.sv | 3 +-- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ifu/spill.sv b/src/ifu/spill.sv index a82f4e9bf..d6e6a75e4 100644 --- a/src/ifu/spill.sv +++ b/src/ifu/spill.sv @@ -83,6 +83,7 @@ module spill import cvw::*; #(parameter cvw_t P) ( assign SpillF = CacheableF ? SpillCachedF : SpillUncachedF; end else assign SpillF = PCF[1]; // *** might relax - only spill if next instruction is uncompressed + // Don't take the spill if there is a stall, TLB miss, or hardware update to the D/A bits assign TakeSpillF = SpillF & ~IFUCacheBusStallF & ~(ITLBMissF | (P.SVADU_SUPPORTED & InstrUpdateDAF)); always_ff @(posedge clk) diff --git a/src/mmu/tlb/tlbcontrol.sv b/src/mmu/tlb/tlbcontrol.sv index 666448b12..31312f767 100644 --- a/src/mmu/tlb/tlbcontrol.sv +++ b/src/mmu/tlb/tlbcontrol.sv @@ -115,8 +115,7 @@ module tlbcontrol import cvw::*; #(parameter cvw_t P, ITLB = 0) ( end // Determine wheter to update DA bits. With SVADU, it is done in hardware - if (P.SVADU_SUPPORTED) assign UpdateDA = PreUpdateDA & Translate & TLBHit & ~TLBPageFault & ENVCFG_HADE; - else assign UpdateDA = PreUpdateDA; + assign UpdateDA = P.SVADU_SUPPORTED & PreUpdateDA & Translate & TLBHit & ~TLBPageFault & ENVCFG_HADE; // Determine whether page fault occurs assign PrePageFault = UpperBitsUnequal | Misaligned | ~PTE_V | ImproperPrivilege | (P.XLEN == 64 & (BadPBMT | BadNAPOT | BadReserved)) | (PreUpdateDA & (~P.SVADU_SUPPORTED | ~ENVCFG_HADE)); From 28752303be0b8a0386aaa7a99ad64baba8700824 Mon Sep 17 00:00:00 2001 From: David Harris Date: Wed, 4 Oct 2023 12:28:12 -0700 Subject: [PATCH 3/3] Added ZCA/ZCF/ZCD/ZCB support. Doesn't break regression, but not tested. Need to get tests for Zcb. Draft tests are in riscv-arch-test but not yet committed there --- config/buildroot/config.vh | 6 ++ config/fpga/config.vh | 6 ++ config/rv32e/config.vh | 6 ++ config/rv32gc/config.vh | 6 ++ config/rv32i/config.vh | 6 ++ config/rv32imc/config.vh | 6 ++ config/rv64fpquad/config.vh | 6 ++ config/rv64gc/config.vh | 6 ++ config/rv64i/config.vh | 6 ++ config/shared/parameter-defs.vh | 4 + src/cvw.sv | 6 ++ src/ifu/decompress.sv | 116 ++++++++++++++++++++++------ src/ifu/ifu.sv | 4 +- testbench/common/riscvassertions.sv | 5 ++ 14 files changed, 163 insertions(+), 26 deletions(-) diff --git a/config/buildroot/config.vh b/config/buildroot/config.vh index 79ee99f3c..b25e8fe9c 100644 --- a/config/buildroot/config.vh +++ b/config/buildroot/config.vh @@ -158,6 +158,12 @@ localparam ZBB_SUPPORTED = 0; localparam ZBC_SUPPORTED = 0; localparam ZBS_SUPPORTED = 0; +// New compressed instructions +localparam ZCB_SUPPORTED = 1; +localparam ZCA_SUPPORTED = 0; +localparam ZCF_SUPPORTED = 0; +localparam ZCD_SUPPORTED = 0; + // Memory synthesis configuration localparam USE_SRAM = 0; diff --git a/config/fpga/config.vh b/config/fpga/config.vh index 27903d0be..2508b557e 100644 --- a/config/fpga/config.vh +++ b/config/fpga/config.vh @@ -171,6 +171,12 @@ localparam ZBB_SUPPORTED = 1; localparam ZBC_SUPPORTED = 1; localparam ZBS_SUPPORTED = 1; +// New compressed instructions +localparam ZCB_SUPPORTED = 1; +localparam ZCA_SUPPORTED = 0; +localparam ZCF_SUPPORTED = 0; +localparam ZCD_SUPPORTED = 0; + // Memory synthesis configuration localparam USE_SRAM = 0; diff --git a/config/rv32e/config.vh b/config/rv32e/config.vh index c67e71c13..35e85003d 100644 --- a/config/rv32e/config.vh +++ b/config/rv32e/config.vh @@ -159,6 +159,12 @@ localparam ZBB_SUPPORTED = 0; localparam ZBC_SUPPORTED = 0; localparam ZBS_SUPPORTED = 0; +// New compressed instructions +localparam ZCB_SUPPORTED = 0; +localparam ZCA_SUPPORTED = 0; +localparam ZCF_SUPPORTED = 0; +localparam ZCD_SUPPORTED = 0; + // Memory synthesis configuration localparam USE_SRAM = 0; diff --git a/config/rv32gc/config.vh b/config/rv32gc/config.vh index de966b1f2..06be2e01b 100644 --- a/config/rv32gc/config.vh +++ b/config/rv32gc/config.vh @@ -171,6 +171,12 @@ localparam ZBB_SUPPORTED = 1; localparam ZBC_SUPPORTED = 1; localparam ZBS_SUPPORTED = 1; +// New compressed instructions +localparam ZCB_SUPPORTED = 1; +localparam ZCA_SUPPORTED = 0; +localparam ZCF_SUPPORTED = 0; +localparam ZCD_SUPPORTED = 0; + // Memory synthesis configuration localparam USE_SRAM = 0; diff --git a/config/rv32i/config.vh b/config/rv32i/config.vh index a31e034df..5e03d3e93 100644 --- a/config/rv32i/config.vh +++ b/config/rv32i/config.vh @@ -159,6 +159,12 @@ localparam ZBB_SUPPORTED = 0; localparam ZBC_SUPPORTED = 0; localparam ZBS_SUPPORTED = 0; +// New compressed instructions +localparam ZCB_SUPPORTED = 0; +localparam ZCA_SUPPORTED = 0; +localparam ZCF_SUPPORTED = 0; +localparam ZCD_SUPPORTED = 0; + // Memory synthesis configuration localparam USE_SRAM = 0; diff --git a/config/rv32imc/config.vh b/config/rv32imc/config.vh index 61eea7325..cb031d2db 100644 --- a/config/rv32imc/config.vh +++ b/config/rv32imc/config.vh @@ -158,6 +158,12 @@ localparam ZBB_SUPPORTED = 0; localparam ZBC_SUPPORTED = 0; localparam ZBS_SUPPORTED = 0; +// New compressed instructions +localparam ZCB_SUPPORTED = 0; +localparam ZCA_SUPPORTED = 0; +localparam ZCF_SUPPORTED = 0; +localparam ZCD_SUPPORTED = 0; + // Memory synthesis configuration localparam USE_SRAM = 0; diff --git a/config/rv64fpquad/config.vh b/config/rv64fpquad/config.vh index d8bf3e6fc..63a35c7f5 100644 --- a/config/rv64fpquad/config.vh +++ b/config/rv64fpquad/config.vh @@ -161,6 +161,12 @@ localparam ZBB_SUPPORTED = 0; localparam ZBC_SUPPORTED = 0; localparam ZBS_SUPPORTED = 0; +// New compressed instructions +localparam ZCB_SUPPORTED = 0; +localparam ZCA_SUPPORTED = 0; +localparam ZCF_SUPPORTED = 0; +localparam ZCD_SUPPORTED = 0; + // Memory synthesis configuration localparam USE_SRAM = 0; diff --git a/config/rv64gc/config.vh b/config/rv64gc/config.vh index 36d99020e..f17761e33 100644 --- a/config/rv64gc/config.vh +++ b/config/rv64gc/config.vh @@ -164,6 +164,12 @@ localparam ZBB_SUPPORTED = 1; localparam ZBC_SUPPORTED = 1; localparam ZBS_SUPPORTED = 1; +// New compressed instructions +localparam ZCB_SUPPORTED = 1; +localparam ZCA_SUPPORTED = 0; +localparam ZCF_SUPPORTED = 0; +localparam ZCD_SUPPORTED = 0; + // Memory synthesis configuration localparam USE_SRAM = 0; diff --git a/config/rv64i/config.vh b/config/rv64i/config.vh index 6add96e78..d87708c18 100644 --- a/config/rv64i/config.vh +++ b/config/rv64i/config.vh @@ -161,6 +161,12 @@ localparam ZBB_SUPPORTED = 0; localparam ZBC_SUPPORTED = 0; localparam ZBS_SUPPORTED = 0; +// New compressed instructions +localparam ZCB_SUPPORTED = 0; +localparam ZCA_SUPPORTED = 0; +localparam ZCF_SUPPORTED = 0; +localparam ZCD_SUPPORTED = 0; + // Memory synthesis configuration localparam USE_SRAM = 0; diff --git a/config/shared/parameter-defs.vh b/config/shared/parameter-defs.vh index 4921f6a3d..f3f216062 100644 --- a/config/shared/parameter-defs.vh +++ b/config/shared/parameter-defs.vh @@ -96,6 +96,10 @@ localparam cvw_t P = '{ ZBB_SUPPORTED : ZBB_SUPPORTED, ZBC_SUPPORTED : ZBC_SUPPORTED, ZBS_SUPPORTED : ZBS_SUPPORTED, + ZCA_SUPPORTED : ZCA_SUPPORTED, + ZCB_SUPPORTED : ZCB_SUPPORTED, + ZCD_SUPPORTED : ZCD_SUPPORTED, + ZCF_SUPPORTED : ZCF_SUPPORTED, USE_SRAM : USE_SRAM, M_MODE : M_MODE, S_MODE : S_MODE, diff --git a/src/cvw.sv b/src/cvw.sv index f64618574..01e0d6376 100644 --- a/src/cvw.sv +++ b/src/cvw.sv @@ -161,6 +161,12 @@ typedef struct packed { logic ZBC_SUPPORTED; logic ZBS_SUPPORTED; +// compressed + logic ZCA_SUPPORTED; + logic ZCB_SUPPORTED; + logic ZCD_SUPPORTED; + logic ZCF_SUPPORTED; + // Memory synthesis configuration logic USE_SRAM; diff --git a/src/ifu/decompress.sv b/src/ifu/decompress.sv index 1605ed039..5c4395a12 100644 --- a/src/ifu/decompress.sv +++ b/src/ifu/decompress.sv @@ -30,7 +30,7 @@ //////////////////////////////////////////////////////////////////////////////////////////////// -module decompress #(parameter XLEN)( +module decompress import cvw::*; #(parameter cvw_t P) ( input logic [31:0] InstrRawD, // 32-bit instruction or raw compressed 16-bit instruction in bottom half output logic [31:0] InstrD, // Decompressed instruction output logic IllegalCompInstrD // Invalid decompressed instruction @@ -88,20 +88,60 @@ module decompress #(parameter XLEN)( IllegalCompInstrD = 1; InstrD = {16'b0, instr16}; // preserve instruction for mtval on trap end - 5'b00001: InstrD = {immCLD, rs1p, 3'b011, rdp, 7'b0000111}; // c.fld + 5'b00001: if (P.C_SUPPORTED & P.D_SUPPORTED | P.ZCD_SUPPORTED) + InstrD = {immCLD, rs1p, 3'b011, rdp, 7'b0000111}; // c.fld + else begin // unsupported instruction + IllegalCompInstrD = 1; + InstrD = {16'b0, instr16}; // preserve instruction for mtval on trap + end 5'b00010: InstrD = {immCL, rs1p, 3'b010, rdp, 7'b0000011}; // c.lw - 5'b00011: if (XLEN==32) - InstrD = {immCL, rs1p, 3'b010, rdp, 7'b0000111}; // c.flw + 5'b00011: if (P.XLEN==32) + if (P.C_SUPPORTED & P.F_SUPPORTED | P.ZCF_SUPPORTED) + InstrD = {immCL, rs1p, 3'b010, rdp, 7'b0000111}; // c.flw + else begin + IllegalCompInstrD = 1; + InstrD = {16'b0, instr16}; // preserve instruction for mtval on trap + end else InstrD = {immCLD, rs1p, 3'b011, rdp, 7'b0000011}; // c.ld; - 5'b00101: InstrD = {immCSD[11:5], rs2p, rs1p, 3'b011, immCSD[4:0], 7'b0100111}; // c.fsd + 5'b00100: if (P.ZCB_SUPPORTED) + if (instr16[12:10] == 3'b000) + InstrD = {10'b0, instr16[6:5], rs1p, 3'b100, rdp, 7'b0000011}; // c.lbu + else if (instr16[12:10] == 3'b001) begin + if (instr16[6]) + InstrD = {10'b0, instr16[5], 1'b0, rs1p, 3'b001, rdp, 7'b0000011}; // c.lh + else + InstrD = {10'b0, instr16[5], 1'b0, rs1p, 3'b101, rdp, 7'b0000011}; // c.lhu + end else if (instr16[12:10] == 3'b010) + InstrD = {7'b0, rs2p, rs1p, 3'b000, 3'b000, instr16[6:5], 7'b0000011}; // c.sb + else if (instr16[12:10] == 3'b011 & instr16[6] == 1'b0) + InstrD = {7'b0, rs2p, rs1p, 3'b001, 3'b000, instr16[5], 1'b0, 7'b0000011}; // c.sh + else begin + IllegalCompInstrD = 1; + InstrD = {16'b0, instr16}; // preserve instruction for mtval on trap + end + else begin + IllegalCompInstrD = 1; + InstrD = {16'b0, instr16}; // preserve instruction for mtval on trap + end + 5'b00101: if (P.C_SUPPORTED & P.D_SUPPORTED | P.ZCD_SUPPORTED) + InstrD = {immCSD[11:5], rs2p, rs1p, 3'b011, immCSD[4:0], 7'b0100111}; // c.fsd + else begin // unsupported instruction + IllegalCompInstrD = 1; + InstrD = {16'b0, instr16}; // preserve instruction for mtval on trap + end 5'b00110: InstrD = {immCS[11:5], rs2p, rs1p, 3'b010, immCS[4:0], 7'b0100011}; // c.sw - 5'b00111: if (XLEN==32) - InstrD = {immCS[11:5], rs2p, rs1p, 3'b010, immCS[4:0], 7'b0100111}; // c.fsw + 5'b00111: if (P.XLEN==32) + if (P.C_SUPPORTED & P.F_SUPPORTED | P.ZCF_SUPPORTED) + InstrD = {immCS[11:5], rs2p, rs1p, 3'b010, immCS[4:0], 7'b0100111}; // c.fsw + else begin + IllegalCompInstrD = 1; + InstrD = {16'b0, instr16}; // preserve instruction for mtval on trap + end else InstrD = {immCSD[11:5], rs2p, rs1p, 3'b011, immCSD[4:0], 7'b0100011}; //c.sd 5'b01000: InstrD = {immCI, rds1, 3'b000, rds1, 7'b0010011}; // c.addi - 5'b01001: if (XLEN==32) + 5'b01001: if (P.XLEN==32) InstrD = {immCJ, 5'b00001, 7'b1101111}; // c.jal else InstrD = {immCI, rds1, 3'b000, rds1, 7'b0011011}; // c.addiw @@ -125,33 +165,51 @@ module decompress #(parameter XLEN)( InstrD = {7'b0000000, rs2p, rds1p, 3'b110, rds1p, 7'b0110011}; // c.or else // if (instr16[6:5] == 2'b11) InstrD = {7'b0000000, rs2p, rds1p, 3'b111, rds1p, 7'b0110011}; // c.and - else if (XLEN > 32) //if (instr16[12:10] == 3'b111) full truth table no need to check [12:10] - if (instr16[6:5] == 2'b00) + else if (instr16[12:10] == 3'b111) begin + if (instr16[6:5] == 2'b00 & P.XLEN > 32) InstrD = {7'b0100000, rs2p, rds1p, 3'b000, rds1p, 7'b0111011}; // c.subw - else if (instr16[6:5] == 2'b01) + else if (instr16[6:5] == 2'b01 & P.XLEN > 32) InstrD = {7'b0000000, rs2p, rds1p, 3'b000, rds1p, 7'b0111011}; // c.addw + else if (instr16[6:2] == 5'b11000 & P.ZCB_SUPPORTED) + InstrD = {12'b000011111111, rds1p, 3'b111, rds1p, 7'b0010011}; // c.zext.b = andi rd, rs1, 255 + else if (instr16[6:2] == 5'b10101 & P.ZCB_SUPPORTED) + InstrD = {12'b011000000100, rds1p, 3'b001, rds1p, 7'b0010011}; // c.sext.b + else if (instr16[6:2] == 5'b11010 & P.ZCB_SUPPORTED) + InstrD = {7'b0000100, 5'b00000, rds1p, 3'b100, rds1p, 3'b011, P.XLEN > 32, 3'b011}; // c.zext.h + else if (instr16[6:2] == 5'b11011 & P.ZCB_SUPPORTED) + InstrD = {12'b011000000101, rds1p, 3'b001, rds1p, 7'b0010011}; // c.sext.h + else if (instr16[6:2] == 5'b11101 & P.ZCB_SUPPORTED) + InstrD = {12'b111111111111, rds1p, 3'b100, rds1p, 7'b0010011}; // c.not = xori + else if (instr16[6:2] == 5'b11100 & P.ZCB_SUPPORTED & P.XLEN > 32) + InstrD = {7'b0000100, 5'b00000, rds1p, 3'b000, rds1p, 7'b0111011}; // c.zext.w = add.uw rd, rs1, 0 + else if (instr16[6:5] == 2'b10 & P.ZCB_SUPPORTED) + InstrD = {7'b0000001, rs2p, rds1p, 3'b000, rds1p, 7'b0110011}; // c.mul else begin // reserved IllegalCompInstrD = 1; InstrD = {16'b0, instr16}; // preserve instruction for mtval on trap end - // coverage off - // are excluding this branch from coverage because in rv64gc XLEN is always 64 and thus greater than 32 bits - // This branch will only be taken if instr16[12:10] == 3'b111 and 'XLEN !> 32, because all other - // possible values for instr16[12:10] are covered by branches above. XLEN !> 32 - // will never occur in rv64gc so this branch can not be covered - else begin // illegal instruction + end else begin // illegal instruction IllegalCompInstrD = 1; InstrD = {16'b0, instr16}; // preserve instruction for mtval on trap end - // coverage on 5'b01101: InstrD = {immCJ, 5'b00000, 7'b1101111}; // c.j 5'b01110: InstrD = {immCB[11:5], 5'b00000, rs1p, 3'b000, immCB[4:0], 7'b1100011}; // c.beqz 5'b01111: InstrD = {immCB[11:5], 5'b00000, rs1p, 3'b001, immCB[4:0], 7'b1100011}; // c.bnez 5'b10000: InstrD = {6'b000000, immSH, rds1, 3'b001, rds1, 7'b0010011}; // c.slli - 5'b10001: InstrD = {immCILSPD, 5'b00010, 3'b011, rds1, 7'b0000111}; // c.fldsp + 5'b10001: if (P.C_SUPPORTED & P.D_SUPPORTED | P.ZCD_SUPPORTED) + InstrD = {immCILSPD, 5'b00010, 3'b011, rds1, 7'b0000111}; // c.fldsp + else begin // unsupported instruction + IllegalCompInstrD = 1; + InstrD = {16'b0, instr16}; // preserve instruction for mtval on trap + end 5'b10010: InstrD = {immCILSP, 5'b00010, 3'b010, rds1, 7'b0000011}; // c.lwsp - 5'b10011: if (XLEN == 32) - InstrD = {immCILSP, 5'b00010, 3'b010, rds1, 7'b0000111}; // c.flwsp + 5'b10011: if (P.XLEN == 32) + if (P.C_SUPPORTED & P.F_SUPPORTED | P.ZCF_SUPPORTED) + InstrD = {immCILSP, 5'b00010, 3'b010, rds1, 7'b0000111}; // c.flwsp + else begin + IllegalCompInstrD = 1; + InstrD = {16'b0, instr16}; // preserve instruction for mtval on trap + end else InstrD = {immCILSPD, 5'b00010, 3'b011, rds1, 7'b0000011}; // c.ldsp 5'b10100: if (instr16[12] == 0) @@ -167,10 +225,20 @@ module decompress #(parameter XLEN)( InstrD = {12'b0, rds1, 3'b000, 5'b00001, 7'b1100111}; // c.jalr else InstrD = {7'b0000000, rs2, rds1, 3'b000, rds1, 7'b0110011}; // c.add - 5'b10101: InstrD = {immCSSD[11:5], rs2, 5'b00010, 3'b011, immCSSD[4:0], 7'b0100111}; // c.fsdsp + 5'b10101: if (P.C_SUPPORTED & P.D_SUPPORTED | P.ZCD_SUPPORTED) + InstrD = {immCSSD[11:5], rs2, 5'b00010, 3'b011, immCSSD[4:0], 7'b0100111}; // c.fsdsp + else begin // unsupported instruction + IllegalCompInstrD = 1; + InstrD = {16'b0, instr16}; // preserve instruction for mtval on trap + end 5'b10110: InstrD = {immCSS[11:5], rs2, 5'b00010, 3'b010, immCSS[4:0], 7'b0100011}; // c.swsp - 5'b10111: if (XLEN==32) - InstrD = {immCSS[11:5], rs2, 5'b00010, 3'b010, immCSS[4:0], 7'b0100111}; // c.fswsp + 5'b10111: if (P.XLEN==32) + if (P.C_SUPPORTED & P.F_SUPPORTED | P.ZCF_SUPPORTED) + InstrD = {immCSS[11:5], rs2, 5'b00010, 3'b010, immCSS[4:0], 7'b0100111}; // c.fswsp + else begin + IllegalCompInstrD = 1; + InstrD = {16'b0, instr16}; // preserve instruction for mtval on trap + end else InstrD = {immCSSD[11:5], rs2, 5'b00010, 3'b011, immCSSD[4:0], 7'b0100011}; // c.sdsp default: begin // illegal instruction diff --git a/src/ifu/ifu.sv b/src/ifu/ifu.sv index d63a987b2..af6f70898 100644 --- a/src/ifu/ifu.sv +++ b/src/ifu/ifu.sv @@ -353,9 +353,9 @@ module ifu import cvw::*; #(parameter cvw_t P) ( flopenrc #(P.XLEN) PCDReg(clk, reset, FlushD, ~StallD, PCF, PCD); // expand 16-bit compressed instructions to 32 bits - if (P.C_SUPPORTED) begin + if (P.C_SUPPORTED | P.ZCA_SUPPORTED) begin logic IllegalCompInstrD; - decompress #(P.XLEN) decomp(.InstrRawD, .InstrD, .IllegalCompInstrD); + decompress #(P) decomp(.InstrRawD, .InstrD, .IllegalCompInstrD); assign IllegalIEUInstrD = IllegalBaseInstrD | IllegalCompInstrD; // illegal if bad 32 or 16-bit instr end else begin assign InstrD = InstrRawD; diff --git a/testbench/common/riscvassertions.sv b/testbench/common/riscvassertions.sv index a6cee910e..815478390 100644 --- a/testbench/common/riscvassertions.sv +++ b/testbench/common/riscvassertions.sv @@ -63,6 +63,11 @@ module riscvassertions import cvw::*; #(parameter cvw_t P); assert ((P.ZICBOP_SUPPORTED == 0) || (P.DCACHE_SUPPORTED == 1)) else $error("ZICBOP requires DCACHE_SUPPORTED"); assert ((P.SVPBMT_SUPPORTED == 0) || (P.VIRTMEM_SUPPORTED == 1 && P.XLEN==64)) else $error("SVPBMT requires VIRTMEM_SUPPORTED and RV64"); assert ((P.SVNAPOT_SUPPORTED == 0) || (P.VIRTMEM_SUPPORTED == 1 && P.XLEN==64)) else $error("SVNAPOT requires VIRTMEM_SUPPORTED and RV64"); + assert ((P.ZCB_SUPPORTED == 0) || (P.M_SUPPORTED == 1 && (P.ZBA_SUPPORTED == 1 || P.XLEN == 32) && P.ZBB_SUPPORTED == 1)) else $error("ZCB requires M and ZBB (and also ZBA for RV64)"); + assert ((P.C_SUPPORTED == 0) || (P.ZCA_SUPPORTED == 0 && P.ZCF_SUPPORTED == 0 && P.ZCD_SUPPORTED == 0)) else $error("C and ZCA/ZCD/ZCF cannot simultaneously be supported"); + assert ((P.ZCA_SUPPORTED == 1) || (P.ZCD_SUPPORTED == 0 && P.ZCF_SUPPORTED == 0)) else $error("ZCF or ZCD requires ZCA"); + assert ((P.ZCF_SUPPORTED == 0) || (P.F_SUPPORTED == 1)) else $error("ZCF requires F"); + assert ((P.ZCD_SUPPORTED == 0) || (P.D_SUPPORTED == 1)) else $error("ZCD requires D"); end endmodule