diff --git a/wally-pipelined/src/dmem/dmem.sv b/wally-pipelined/src/dmem/dmem.sv index 75559c3f..1eb6fa82 100644 --- a/wally-pipelined/src/dmem/dmem.sv +++ b/wally-pipelined/src/dmem/dmem.sv @@ -47,6 +47,7 @@ module dmem ( output logic SquashSCW, // faults input logic DataAccessFaultM, + output logic DTLBLoadPageFaultM, DTLBStorePageFaultM, output logic LoadMisalignedFaultM, LoadAccessFaultM, output logic StoreMisalignedFaultM, StoreAccessFaultM, // TLB management @@ -54,22 +55,25 @@ module dmem ( input logic [`XLEN-1:0] PageTableEntryM, input logic [1:0] PageTypeM, input logic [`XLEN-1:0] SATP_REGW, + input logic STATUS_MXR, STATUS_SUM, input logic DTLBWriteM, DTLBFlushM, output logic DTLBMissM, DTLBHitM ); - logic MemAccessM; // Whether memory needs to be accessed logic SquashSCM; - // *** needs to be sent to trap unit logic DTLBPageFaultM; - tlb #(3) dtlb(.TLBAccess(MemAccessM), .VirtualAddress(MemAdrM), + tlb #(.ENTRY_BITS(3), .ITLB(0)) dtlb(.TLBAccessType(MemRWM), .VirtualAddress(MemAdrM), .PageTableEntryWrite(PageTableEntryM), .PageTypeWrite(PageTypeM), .TLBWrite(DTLBWriteM), .TLBFlush(DTLBFlushM), .PhysicalAddress(MemPAdrM), .TLBMiss(DTLBMissM), .TLBHit(DTLBHitM), .TLBPageFault(DTLBPageFaultM), .*); + // Specify which type of page fault is occurring + assign DTLBLoadPageFaultM = DTLBPageFaultM & MemRWM[1]; + assign DTLBStorePageFaultM = DTLBPageFaultM & MemRWM[0]; + // Determine if an Unaligned access is taking place always_comb case(Funct3M[1:0]) @@ -83,7 +87,6 @@ module dmem ( // *** this is also the place to squash if the cache is hit assign MemReadM = MemRWM[1] & ~DataMisalignedM; assign MemWriteM = MemRWM[0] & ~DataMisalignedM && ~SquashSCM; - assign MemAccessM = |MemRWM; // Determine if address is valid assign LoadMisalignedFaultM = DataMisalignedM & MemRWM[1]; diff --git a/wally-pipelined/src/ebu/ahblite.sv b/wally-pipelined/src/ebu/ahblite.sv index 25d1a226..73b03599 100644 --- a/wally-pipelined/src/ebu/ahblite.sv +++ b/wally-pipelined/src/ebu/ahblite.sv @@ -85,6 +85,9 @@ module ahblite ( logic IReady, DReady; logic CaptureDataM; + // Describes type of access + logic Atomic, Execute, Write, Read; + assign HCLK = clk; assign HRESETn = ~reset; @@ -109,15 +112,6 @@ module ahblite ( else NextBusState = IDLE; MMUTRANSLATE: if (~HREADY) NextBusState = MMUTRANSLATE; else NextBusState = IDLE; - // *** Could the MMUIDLE state just be the normal idle state? - // Do we trust MMUTranslate to be high exactly when we need translation? - // MMUIDLE: if (MMUTranslate) - // NextBusState = MMUTRANSLATE; - // else if (AtomicM[1]) NextBusState = ATOMICREAD; - // else if (MemReadM) NextBusState = MEMREAD; // Memory has priority over instructions - // else if (MemWriteM) NextBusState = MEMWRITE; - // else if (InstrReadF) NextBusState = INSTRREAD; - // else NextBusState = IDLE; ATOMICREAD: if (~HREADY) NextBusState = ATOMICREAD; else NextBusState = ATOMICWRITE; ATOMICWRITE: if (~HREADY) NextBusState = ATOMICWRITE; @@ -148,6 +142,13 @@ module ahblite ( assign #1 InstrStall = ((NextBusState == INSTRREAD) || (NextBusState == INSTRREADC) || (NextBusState == MMUTRANSLATE) || (MMUTranslate && ~MMUTranslationComplete)); + // Determine access type (important for determining whether to fault) + assign Atomic = ((NextBusState == ATOMICREAD) || (NextBusState == ATOMICWRITE)); + assign Execute = ((NextBusState == INSTRREAD) || (NextBusState == INSTRREADC)); + assign Write = ((NextBusState == MEMWRITE) || (NextBusState == ATOMICWRITE)); + assign Read = ((NextBusState == MEMREAD) || (NextBusState == ATOMICREAD) || + (NextBusState == MMUTRANSLATE)); + // bus outputs assign #1 GrantData = (NextBusState == MEMREAD) || (NextBusState == MEMWRITE) || (NextBusState == ATOMICREAD) || (NextBusState == ATOMICWRITE); diff --git a/wally-pipelined/src/ebu/pagetablewalker.sv b/wally-pipelined/src/ebu/pagetablewalker.sv index 8b3723f4..a1f10cd3 100644 --- a/wally-pipelined/src/ebu/pagetablewalker.sv +++ b/wally-pipelined/src/ebu/pagetablewalker.sv @@ -61,7 +61,9 @@ module pagetablewalker ( output logic MMUTranslationComplete, // Faults - output logic InstrPageFaultF, LoadPageFaultM, StorePageFaultM + output logic WalkerInstrPageFaultF, + output logic WalkerLoadPageFaultM, + output logic WalkerStorePageFaultM ); // Internal signals @@ -147,7 +149,6 @@ module pagetablewalker ( assign SvMode = SATP_REGW[31]; - // *** Do we need a synchronizer here for walker to talk to ahblite? flopenl #(3) mmureg(HCLK, ~HRESETn, 1'b1, NextWalkerState, IDLE, WalkerState); // State transition logic @@ -193,9 +194,9 @@ module pagetablewalker ( MMUTranslationComplete = '0; DTLBWriteM = '0; ITLBWriteF = '0; - InstrPageFaultF = '0; - LoadPageFaultM = '0; - StorePageFaultM = '0; + WalkerInstrPageFaultF = '0; + WalkerLoadPageFaultM = '0; + WalkerStorePageFaultM = '0; case (NextWalkerState) LEVEL1: begin @@ -216,9 +217,9 @@ module pagetablewalker ( FAULT: begin TranslationPAdr = {CurrentPPN, VPN0, 2'b00}; MMUTranslationComplete = '1; - InstrPageFaultF = ~DTLBMissM; - LoadPageFaultM = DTLBMissM && ~MemStore; - StorePageFaultM = DTLBMissM && MemStore; + WalkerInstrPageFaultF = ~DTLBMissM; + WalkerLoadPageFaultM = DTLBMissM && ~MemStore; + WalkerStorePageFaultM = DTLBMissM && MemStore; end default: begin // nothing @@ -298,9 +299,9 @@ module pagetablewalker ( MMUTranslationComplete = '0; DTLBWriteM = '0; ITLBWriteF = '0; - InstrPageFaultF = '0; - LoadPageFaultM = '0; - StorePageFaultM = '0; + WalkerInstrPageFaultF = '0; + WalkerLoadPageFaultM = '0; + WalkerStorePageFaultM = '0; case (NextWalkerState) LEVEL2: begin @@ -325,9 +326,9 @@ module pagetablewalker ( FAULT: begin TranslationPAdr = {CurrentPPN, VPN0, 3'b000}; MMUTranslationComplete = '1; - InstrPageFaultF = ~DTLBMissM; - LoadPageFaultM = DTLBMissM && ~MemStore; - StorePageFaultM = DTLBMissM && MemStore; + WalkerInstrPageFaultF = ~DTLBMissM; + WalkerLoadPageFaultM = DTLBMissM && ~MemStore; + WalkerStorePageFaultM = DTLBMissM && MemStore; end default: begin // nothing diff --git a/wally-pipelined/src/ifu/ifu.sv b/wally-pipelined/src/ifu/ifu.sv index d5ecf470..ad913434 100644 --- a/wally-pipelined/src/ifu/ifu.sv +++ b/wally-pipelined/src/ifu/ifu.sv @@ -54,6 +54,7 @@ module ifu ( // output logic [`XLEN-1:0] PCLinkW, // Faults input logic IllegalBaseInstrFaultD, + output logic ITLBInstrPageFaultF, output logic IllegalIEUInstrFaultD, output logic InstrMisalignedFaultM, output logic [`XLEN-1:0] InstrMisalignedAdrM, @@ -62,6 +63,7 @@ module ifu ( input logic [`XLEN-1:0] PageTableEntryF, input logic [1:0] PageTypeF, input logic [`XLEN-1:0] SATP_REGW, + input logic STATUS_MXR, STATUS_SUM, input logic ITLBWriteF, ITLBFlushF, output logic ITLBMissF, ITLBHitF ); @@ -74,14 +76,12 @@ module ifu ( logic CompressedF; logic [31:0] InstrRawD, InstrE, InstrW; logic [31:0] nop = 32'h00000013; // instruction for NOP - // *** send this to the trap unit - logic ITLBPageFaultF; - tlb #(3) itlb(.TLBAccess(1'b1), .VirtualAddress(PCF), + tlb #(.ENTRY_BITS(3), .ITLB(1)) itlb(.TLBAccessType(2'b10), .VirtualAddress(PCF), .PageTableEntryWrite(PageTableEntryF), .PageTypeWrite(PageTypeF), .TLBWrite(ITLBWriteF), .TLBFlush(ITLBFlushF), .PhysicalAddress(PCPF), .TLBMiss(ITLBMissF), - .TLBHit(ITLBHitF), .TLBPageFault(ITLBPageFaultF), + .TLBHit(ITLBHitF), .TLBPageFault(ITLBInstrPageFaultF), .*); // branch predictor signals diff --git a/wally-pipelined/src/mmu/tlb.sv b/wally-pipelined/src/mmu/tlb.sv index 760e9b97..24a04940 100644 --- a/wally-pipelined/src/mmu/tlb.sv +++ b/wally-pipelined/src/mmu/tlb.sv @@ -44,26 +44,26 @@ * RSW(2) -- for OS */ -/* *** TODO: - * - add LRU algorithm (select the write index based on which entry was used - * least recently) - */ - `include "wally-config.vh" `include "wally-constants.vh" // The TLB will have 2**ENTRY_BITS total entries -module tlb #(parameter ENTRY_BITS = 3) ( +module tlb #(parameter ENTRY_BITS = 3, + parameter ITLB = 0) ( input clk, reset, // Current value of satp CSR (from privileged unit) input [`XLEN-1:0] SATP_REGW, + input STATUS_MXR, STATUS_SUM, // Current privilege level of the processeor input [1:0] PrivilegeModeW, - // High if the TLB is currently being accessed - input TLBAccess, + // 00 - TLB is not being accessed + // 1x - TLB is accessed for a read (or an instruction) + // x1 - TLB is accessed for a write + // 11 - TLB is accessed for both read and write + input [1:0] TLBAccessType, // Virtual address input input [`XLEN-1:0] VirtualAddress, @@ -87,17 +87,7 @@ module tlb #(parameter ENTRY_BITS = 3) ( logic SvMode; logic Translate; - - generate - if (`XLEN == 32) begin - assign SvMode = SATP_REGW[31]; // *** change to an enum somehow? - end else begin - assign SvMode = SATP_REGW[63]; // currently just a boolean whether translation enabled - end - endgenerate - - // Whether translation should occur - assign Translate = SvMode & (PrivilegeModeW != `M_MODE); + logic TLBAccess, ReadAccess, WriteAccess; // *** If we want to support multiple virtual memory modes (ie sv39 AND sv48), // we could have some muxes that control which parameters are current. @@ -116,6 +106,9 @@ module tlb #(parameter ENTRY_BITS = 3) ( logic [7:0] PTEAccessBits; logic [11:0] PageOffset; + // Useful PTE Control Bits + logic PTE_U, PTE_X, PTE_W, PTE_R; + // Pattern location in the CAM and type of page hit logic [ENTRY_BITS-1:0] VPNIndex; logic [1:0] HitPageType; @@ -123,18 +116,68 @@ module tlb #(parameter ENTRY_BITS = 3) ( // Whether the virtual address has a match in the CAM logic CAMHit; + // Grab the sv bit from SATP + generate + if (`XLEN == 32) begin + assign SvMode = SATP_REGW[31]; // *** change to an enum somehow? + end else begin + assign SvMode = SATP_REGW[63]; // currently just a boolean whether translation enabled + end + endgenerate + + // Whether translation should occur + assign Translate = SvMode & (PrivilegeModeW != `M_MODE); + + // Determine how the TLB is currently being used + assign ReadAccess = TLBAccessType[1]; + assign WriteAccess = TLBAccessType[0]; + assign TLBAccess = ReadAccess || WriteAccess; + assign VirtualPageNumber = VirtualAddress[`VPN_BITS+11:12]; assign PageOffset = VirtualAddress[11:0]; - // Currently use random replacement algorithm - // tlb_rand rdm(.*); + // TLB entries are evicted according to the LRU algorithm tlb_lru lru(.*); - tlb_ram #(ENTRY_BITS) ram(.*); - tlb_cam #(ENTRY_BITS, `VPN_BITS, `VPN_SEGMENT_BITS) cam(.*); + tlb_ram #(ENTRY_BITS) tlb_ram(.*); + tlb_cam #(ENTRY_BITS, `VPN_BITS, `VPN_SEGMENT_BITS) tlb_cam(.*); - // *** check whether access is allowed, otherwise fault - assign TLBPageFault = 0; // *** temporary + // unswizzle useful PTE bits + assign PTE_U = PTEAccessBits[4]; + assign PTE_X = PTEAccessBits[3]; + assign PTE_W = PTEAccessBits[2]; + assign PTE_R = PTEAccessBits[1]; + + // Check whether the access is allowed, page faulting if not. + // *** We might not have S mode. + generate + if (ITLB == 1) begin + logic ImproperPrivilege; + + // User mode may only execute user mode pages, and supervisor mode may + // only execute non-user mode pages. + assign ImproperPrivilege = ((PrivilegeModeW == `U_MODE) && ~PTE_U) || + ((PrivilegeModeW == `S_MODE) && PTE_U); + assign TLBPageFault = Translate && TLBHit && (ImproperPrivilege || ~PTE_X); + end else begin + logic ImproperPrivilege, 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 = ((PrivilegeModeW == `U_MODE) && ~PTE_U) || + ((PrivilegeModeW == `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 && + ((~STATUS_MXR && ~PTE_R) || (STATUS_MXR && ~PTE_R && PTE_X)); + // Check for write error. Writes are invalid when the page's write bit is + // low. + assign InvalidWrite = WriteAccess && ~PTE_W; + assign TLBPageFault = Translate && TLBHit && + (ImproperPrivilege || InvalidRead || InvalidWrite); + end + endgenerate // *** Not the cleanest solution. // The highest segment of the physical page number has some extra bits @@ -158,6 +201,8 @@ module tlb #(parameter ENTRY_BITS = 3) ( // Output the hit physical address if translation is currently on. generate if (`XLEN == 32) begin + // *** If we want rv32 to use the full 34 bit physical address space, this + // must be changed mux2 #(`XLEN) addressmux(VirtualAddress, PhysicalAddressFull[31:0], Translate, PhysicalAddress); end else begin mux2 #(`XLEN) addressmux(VirtualAddress, {8'b0, PhysicalAddressFull}, Translate, PhysicalAddress); diff --git a/wally-pipelined/src/privileged/csr.sv b/wally-pipelined/src/privileged/csr.sv index b3572c7f..741f26bd 100644 --- a/wally-pipelined/src/privileged/csr.sv +++ b/wally-pipelined/src/privileged/csr.sv @@ -49,6 +49,7 @@ module csr #(parameter output logic [`XLEN-1:0] SATP_REGW, output logic [11:0] MIP_REGW, MIE_REGW, output logic STATUS_MIE, STATUS_SIE, + output logic STATUS_MXR, STATUS_SUM, input logic [4:0] SetFflagsM, output logic [2:0] FRM_REGW, // output logic [11:0] MIP_REGW, SIP_REGW, UIP_REGW, MIE_REGW, SIE_REGW, UIE_REGW, diff --git a/wally-pipelined/src/privileged/csrsr.sv b/wally-pipelined/src/privileged/csrsr.sv index 40f77a12..ecfcf4e8 100644 --- a/wally-pipelined/src/privileged/csrsr.sv +++ b/wally-pipelined/src/privileged/csrsr.sv @@ -36,10 +36,11 @@ module csrsr ( output logic [`XLEN-1:0] MSTATUS_REGW, SSTATUS_REGW, USTATUS_REGW, output logic [1:0] STATUS_MPP, output logic STATUS_SPP, STATUS_TSR, - output logic STATUS_MIE, STATUS_SIE + output logic STATUS_MIE, STATUS_SIE, + output logic STATUS_MXR, STATUS_SUM ); - logic STATUS_SD, STATUS_TW, STATUS_TVM, STATUS_MXR, STATUS_SUM, STATUS_SUM_INT, STATUS_MPRV, STATUS_MPRV_INT; + logic STATUS_SD, STATUS_TW, STATUS_TVM, STATUS_SUM_INT, STATUS_MPRV, STATUS_MPRV_INT; logic [1:0] STATUS_SXL, STATUS_UXL, STATUS_XS, STATUS_FS, STATUS_FS_INT, STATUS_MPP_NEXT; logic STATUS_MPIE, STATUS_SPIE, STATUS_UPIE, STATUS_UIE; diff --git a/wally-pipelined/src/privileged/privileged.sv b/wally-pipelined/src/privileged/privileged.sv index d0cf2ea1..94767592 100644 --- a/wally-pipelined/src/privileged/privileged.sv +++ b/wally-pipelined/src/privileged/privileged.sv @@ -40,7 +40,8 @@ module privileged ( input logic InstrValidW, FloatRegWriteW, LoadStallD, BPPredWrongM, input logic [3:0] InstrClassM, input logic PrivilegedM, - input logic InstrPageFaultF, LoadPageFaultM, StorePageFaultM, + input logic ITLBInstrPageFaultF, DTLBLoadPageFaultM, DTLBStorePageFaultM, + input logic WalkerInstrPageFaultF, WalkerLoadPageFaultM, WalkerStorePageFaultM, input logic InstrMisalignedFaultM, InstrAccessFaultF, IllegalIEUInstrFaultD, input logic LoadMisalignedFaultM, LoadAccessFaultM, input logic StoreMisalignedFaultM, StoreAccessFaultM, @@ -49,6 +50,7 @@ module privileged ( input logic [4:0] SetFflagsM, output logic [1:0] PrivilegeModeW, output logic [`XLEN-1:0] SATP_REGW, + output logic STATUS_MXR, STATUS_SUM, output logic [2:0] FRM_REGW, input logic FlushD, FlushE, FlushM, StallD, StallW, StallE, StallM ); @@ -63,7 +65,8 @@ module privileged ( logic uretM, sretM, mretM, ecallM, ebreakM, wfiM, sfencevmaM; logic IllegalCSRAccessM; logic IllegalIEUInstrFaultE, IllegalIEUInstrFaultM; - logic InstrPageFaultD, InstrPageFaultE, InstrPageFaultM; + logic LoadPageFaultM, StorePageFaultM; + logic InstrPageFaultF, InstrPageFaultD, InstrPageFaultE, InstrPageFaultM; logic InstrAccessFaultD, InstrAccessFaultE, InstrAccessFaultM; logic IllegalInstrFaultM; @@ -123,11 +126,12 @@ module privileged ( assign EcallFaultM = ecallM; assign ITLBFlushF = sfencevmaM; assign DTLBFlushM = sfencevmaM; - // *** Page faults now driven by page table walker. Might need to make the - // below signals ORs of a walker fault and a tlb fault if both of those come in - // assign InstrPageFaultM = 0; - // assign LoadPageFaultM = 0; - // assign StorePageFaultM = 0; + + // A page fault might occur because of insufficient privilege during a TLB + // lookup or a improperly formatted page table during walking + assign InstrPageFaultF = ITLBInstrPageFaultF || WalkerInstrPageFaultF; + assign LoadPageFaultM = DTLBLoadPageFaultM || WalkerLoadPageFaultM; + assign StorePageFaultM = DTLBStorePageFaultM || WalkerStorePageFaultM; // pipeline fault signals flopenrc #(2) faultregD(clk, reset, FlushD, ~StallD, diff --git a/wally-pipelined/src/wally/wallypipelinedhart.sv b/wally-pipelined/src/wally/wallypipelinedhart.sv index f255c965..ca474a75 100644 --- a/wally-pipelined/src/wally/wallypipelinedhart.sv +++ b/wally-pipelined/src/wally/wallypipelinedhart.sv @@ -77,7 +77,8 @@ module wallypipelinedhart ( logic InstrMisalignedFaultM; logic DataMisalignedM; logic IllegalBaseInstrFaultD, IllegalIEUInstrFaultD; - logic InstrPageFaultF, LoadPageFaultM, StorePageFaultM; + logic ITLBInstrPageFaultF, DTLBLoadPageFaultM, DTLBStorePageFaultM; + logic WalkerInstrPageFaultF, WalkerLoadPageFaultM, WalkerStorePageFaultM; logic LoadMisalignedFaultM, LoadAccessFaultM; logic StoreMisalignedFaultM, StoreAccessFaultM; logic [`XLEN-1:0] InstrMisalignedAdrM; @@ -103,6 +104,7 @@ module wallypipelinedhart ( logic ITLBMissF, ITLBHitF; logic DTLBMissM, DTLBHitM; logic [`XLEN-1:0] SATP_REGW; + logic STATUS_MXR, STATUS_SUM; logic [1:0] PrivilegeModeW; logic [`XLEN-1:0] PageTableEntryF, PageTableEntryM;