From 0bd533473cb369ad7a8e74fe38155b42dddbfd17 Mon Sep 17 00:00:00 2001 From: Ross Thompson Date: Thu, 17 Feb 2022 17:19:41 -0600 Subject: [PATCH] New config option to enable hptw writes to PTE in memory to update Access and Dirty bits. --- pipelined/config/buildroot/wally-config.vh | 1 + pipelined/config/fpga/wally-config.vh | 1 + pipelined/config/rv32e/wally-config.vh | 1 + pipelined/config/rv32gc/wally-config.vh | 1 + pipelined/config/rv32ic/wally-config.vh | 1 + pipelined/config/rv64BP/wally-config.vh | 1 + pipelined/config/rv64gc/wally-config.vh | 1 + pipelined/config/rv64ic/wally-config.vh | 1 + pipelined/src/lsu/lsuvirtmen.sv | 6 +- pipelined/src/mmu/hptw.sv | 88 +++++++++++++--------- pipelined/src/mmu/tlbcontrol.sv | 20 +++-- 11 files changed, 79 insertions(+), 43 deletions(-) diff --git a/pipelined/config/buildroot/wally-config.vh b/pipelined/config/buildroot/wally-config.vh index 1bdea74a..eaedcd72 100644 --- a/pipelined/config/buildroot/wally-config.vh +++ b/pipelined/config/buildroot/wally-config.vh @@ -126,3 +126,4 @@ `define TESTSBP 0 `define REPLAY 0 +`define HPTW_WRITES_SUPPORTED 1 diff --git a/pipelined/config/fpga/wally-config.vh b/pipelined/config/fpga/wally-config.vh index 223aa3d8..2e8063e2 100644 --- a/pipelined/config/fpga/wally-config.vh +++ b/pipelined/config/fpga/wally-config.vh @@ -132,3 +132,4 @@ `define TESTSBP 1 `define REPLAY 0 +`define HPTW_WRITES_SUPPORTED 1 diff --git a/pipelined/config/rv32e/wally-config.vh b/pipelined/config/rv32e/wally-config.vh index 9102cf63..aadc41cb 100644 --- a/pipelined/config/rv32e/wally-config.vh +++ b/pipelined/config/rv32e/wally-config.vh @@ -130,3 +130,4 @@ `define TESTSBP 0 `define REPLAY 0 +`define HPTW_WRITES_SUPPORTED 0 diff --git a/pipelined/config/rv32gc/wally-config.vh b/pipelined/config/rv32gc/wally-config.vh index af6ef40c..da45b57b 100644 --- a/pipelined/config/rv32gc/wally-config.vh +++ b/pipelined/config/rv32gc/wally-config.vh @@ -128,3 +128,4 @@ `define TESTSBP 0 `define REPLAY 0 +`define HPTW_WRITES_SUPPORTED 0 diff --git a/pipelined/config/rv32ic/wally-config.vh b/pipelined/config/rv32ic/wally-config.vh index 4d7b0418..bddc0233 100644 --- a/pipelined/config/rv32ic/wally-config.vh +++ b/pipelined/config/rv32ic/wally-config.vh @@ -128,3 +128,4 @@ `define TESTSBP 0 `define REPLAY 0 +`define HPTW_WRITES_SUPPORTED 0 diff --git a/pipelined/config/rv64BP/wally-config.vh b/pipelined/config/rv64BP/wally-config.vh index f8ee8903..dea04686 100644 --- a/pipelined/config/rv64BP/wally-config.vh +++ b/pipelined/config/rv64BP/wally-config.vh @@ -131,3 +131,4 @@ `define TESTSBP 1 `define REPLAY 0 +`define HPTW_WRITES_SUPPORTED 0 diff --git a/pipelined/config/rv64gc/wally-config.vh b/pipelined/config/rv64gc/wally-config.vh index ea17620c..a7dc7838 100644 --- a/pipelined/config/rv64gc/wally-config.vh +++ b/pipelined/config/rv64gc/wally-config.vh @@ -131,3 +131,4 @@ `define TESTSBP 0 `define REPLAY 0 +`define HPTW_WRITES_SUPPORTED 0 diff --git a/pipelined/config/rv64ic/wally-config.vh b/pipelined/config/rv64ic/wally-config.vh index ec497db2..92792472 100644 --- a/pipelined/config/rv64ic/wally-config.vh +++ b/pipelined/config/rv64ic/wally-config.vh @@ -131,3 +131,4 @@ `define TESTSBP 0 `define REPLAY 0 +`define HPTW_WRITES_SUPPORTED 0 diff --git a/pipelined/src/lsu/lsuvirtmen.sv b/pipelined/src/lsu/lsuvirtmen.sv index 18538d93..51ca4e51 100644 --- a/pipelined/src/lsu/lsuvirtmen.sv +++ b/pipelined/src/lsu/lsuvirtmen.sv @@ -79,8 +79,8 @@ module lsuvirtmem( logic HPTWWrite; assign AnyCPUReqM = (|MemRWM) | (|AtomicM); - assign ITLBMissOrDAFaultF = ITLBMissF | InstrDAPageFaultF; - assign DTLBMissOrDAFaultM = DTLBMissM | DataDAPageFaultM; + assign ITLBMissOrDAFaultF = ITLBMissF | (`HPTW_WRITES_SUPPORTED & InstrDAPageFaultF); + assign DTLBMissOrDAFaultM = DTLBMissM | (`HPTW_WRITES_SUPPORTED & DataDAPageFaultM); interlockfsm interlockfsm ( .clk, .reset, .AnyCPUReqM, .ITLBMissOrDAFaultF, .ITLBWriteF, .DTLBMissOrDAFaultM, .DTLBWriteM, .TrapM, .DCacheStallM, @@ -88,7 +88,7 @@ module lsuvirtmem( hptw hptw( // *** remove logic from (), mention this in style guide CH3 .clk, .reset, .SATP_REGW, .PCF, .IEUAdrM, .MemRWM, .AtomicM, .STATUS_MXR, .STATUS_SUM, .STATUS_MPRV, .STATUS_MPP, .PrivilegeModeW, - .ITLBMissF(ITLBMissOrDAFaultF & ~TrapM), .DTLBMissM(DTLBMissOrDAFaultM & ~TrapM), // *** Fix me. + .ITLBMissF(ITLBMissOrDAFaultF & ~TrapM), .DTLBMissM(DTLBMissOrDAFaultM & ~TrapM), // *** Fix me. *** I'm not sure ITLBMiss should be suppressed on TrapM. .PTE, .PageType, .ITLBWriteF, .DTLBWriteM, .HPTWReadPTE(ReadDataM), .DCacheStallM, .HPTWAdr, .HPTWRead, .HPTWWrite, .HPTWSize); diff --git a/pipelined/src/mmu/hptw.sv b/pipelined/src/mmu/hptw.sv index e0193eeb..226509c4 100644 --- a/pipelined/src/mmu/hptw.sv +++ b/pipelined/src/mmu/hptw.sv @@ -29,7 +29,7 @@ /////////////////////////////////////////// `include "wally-config.vh" -`define HTPW_DA_WRITES_SUPPORTED 1 + module hptw ( input logic clk, reset, @@ -71,21 +71,10 @@ module hptw logic [1:0] NextPageType; logic [`SVMODE_BITS-1:0] SvMode; logic [`XLEN-1:0] TranslationVAdr; - logic Dirty, Accessed; logic [`XLEN-1:0] NextPTE; logic UpdatePTE; - logic SetDirty; logic DAPageFault; - logic SaveHPTWAdr, SelHPTWWriteAdr; - logic [`PA_BITS-1:0] HPTWWriteAdr, HPTWReadAdr; - logic SV39Mode; - logic ReadAccess, WriteAccess; - logic InvalidRead, InvalidWrite; - logic UpperBitsUnequalPageFault; - logic ImproperPrivilege; - logic [1:0] EffectivePrivilegeMode; - logic OtherPageFault; - + logic [`PA_BITS-1:0] HPTWReadAdr; (* mark_debug = "true" *) statetype WalkerState, NextWalkerState, InitialWalkerState; @@ -101,59 +90,88 @@ module hptw // State flops flopenr #(1) TLBMissMReg(clk, reset, StartWalk, DTLBMissM, DTLBWalk); // when walk begins, record whether it was for DTLB (or record 0 for ITLB) assign PRegEn = HPTWRead & ~DCacheStallM; - assign NextPTE = UpdatePTE ? {PTE[`XLEN-1:8], (SetDirty | PTE[7]), 1'b1, PTE[5:0]} : HPTWReadPTE; flopenr #(`XLEN) PTEReg(clk, reset, PRegEn | UpdatePTE, NextPTE, PTE); // Capture page table entry from data cache - flopenr #(`PA_BITS) HPTWAdrWriteReg(clk, reset, SaveHPTWAdr, HPTWReadAdr, HPTWWriteAdr); - assign SaveHPTWAdr = WalkerState == L0_ADR; - - assign SelHPTWWriteAdr = UpdatePTE | HPTWWrite; - mux2 #(`PA_BITS) HPTWWriteAdrMux(HPTWReadAdr, HPTWWriteAdr, SelHPTWWriteAdr, HPTWAdr); // Assign PTE descriptors common across all XLEN values // For non-leaf PTEs, D, A, U bits are reserved and ignored. They do not cause faults while walking the page table assign {PTE_U, Executable, Writable, Readable, Valid} = PTE[4:0]; - assign {Dirty, Accessed} = PTE[7:6]; assign LeafPTE = Executable | Writable | Readable; assign ValidPTE = Valid & ~(Writable & ~Readable); assign ValidLeafPTE = ValidPTE & LeafPTE; assign ValidNonLeafPTE = ValidPTE & ~LeafPTE; - assign WriteAccess = (MemRWM[0] | |AtomicM); - assign SetDirty = ~Dirty & & DTLBWalk & WriteAccess; - assign ReadAccess = MemRWM[1]; - assign EffectivePrivilegeMode = (DTLBWalk == 0) ? PrivilegeModeW : (STATUS_MPRV ? STATUS_MPP : PrivilegeModeW); // DTLB uses MPP mode when MPRV is 1 - assign ImproperPrivilege = ((EffectivePrivilegeMode == `U_MODE) & ~PTE_U) | - ((EffectivePrivilegeMode == `S_MODE) & PTE_U & (~STATUS_SUM & DTLBWalk)); + if(`HPTW_WRITES_SUPPORTED) begin : hptwwrites + logic SV39Mode; + logic ReadAccess, WriteAccess; + logic InvalidRead, InvalidWrite; + logic UpperBitsUnequalPageFault; + logic OtherPageFault; + logic [1:0] EffectivePrivilegeMode; + logic ImproperPrivilege; + logic SaveHPTWAdr, SelHPTWWriteAdr; + logic [`PA_BITS-1:0] HPTWWriteAdr; + logic SetDirty; + logic Dirty, Accessed; - if (`XLEN==64) begin:rv64 + assign NextPTE = UpdatePTE ? {PTE[`XLEN-1:8], (SetDirty | PTE[7]), 1'b1, PTE[5:0]} : HPTWReadPTE; // This will be HPTWReadPTE if not handling DAPageFault. + flopenr #(`PA_BITS) HPTWAdrWriteReg(clk, reset, SaveHPTWAdr, HPTWReadAdr, HPTWWriteAdr); + assign SaveHPTWAdr = WalkerState == L0_ADR; + assign SelHPTWWriteAdr = UpdatePTE | HPTWWrite; + mux2 #(`PA_BITS) HPTWWriteAdrMux(HPTWReadAdr, HPTWWriteAdr, SelHPTWWriteAdr, HPTWAdr); // HPTWAdr = HPTWReadAdr if not handling DAPageFault. + + + assign {Dirty, Accessed} = PTE[7:6]; + assign WriteAccess = (MemRWM[0] | |AtomicM); + assign SetDirty = ~Dirty & & DTLBWalk & WriteAccess; + assign ReadAccess = MemRWM[1]; + + assign EffectivePrivilegeMode = (DTLBWalk == 0) ? PrivilegeModeW : (STATUS_MPRV ? STATUS_MPP : PrivilegeModeW); // DTLB uses MPP mode when MPRV is 1 + assign ImproperPrivilege = ((EffectivePrivilegeMode == `U_MODE) & ~PTE_U) | + ((EffectivePrivilegeMode == `S_MODE) & PTE_U & (~STATUS_SUM & DTLBWalk)); + + // *** turn into module + if (`XLEN==64) begin:rv64 assign SV39Mode = (SATP_REGW[`XLEN-1:`XLEN-`SVMODE_BITS] == `SV39); // page fault if upper bits aren't all the same logic UpperEqual39, UpperEqual48; assign UpperEqual39 = &(TranslationVAdr[63:38]) | ~|(TranslationVAdr[63:38]); assign UpperEqual48 = &(TranslationVAdr[63:47]) | ~|(TranslationVAdr[63:47]); assign UpperBitsUnequalPageFault = SV39Mode ? ~UpperEqual39 : ~UpperEqual48; - end else begin + end else begin assign SV39Mode = 0; assign UpperBitsUnequalPageFault = 0; - end + end assign InvalidRead = ReadAccess & ~Readable & (~STATUS_MXR | ~Executable); assign InvalidWrite = WriteAccess & ~Writable; assign OtherPageFault = DTLBWalk? ImproperPrivilege | InvalidRead | InvalidWrite | UpperBitsUnequalPageFault | Misaligned | ~Valid : ImproperPrivilege | ~Executable | UpperBitsUnequalPageFault | Misaligned | ~Valid; - - assign DAPageFault = ValidLeafPTE & (~Accessed | SetDirty) & ~OtherPageFault; - + + + // 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 DAPageFault = ValidLeafPTE & (~Accessed | SetDirty) & ~OtherPageFault; // set to 0 if not handling DAPageFault. + + assign HPTWWrite = (WalkerState == UPDATE_PTE); + assign UpdatePTE = WalkerState == LEAF & DAPageFault; + end else begin // block: hptwwrites + assign NextPTE = HPTWReadPTE; + assign HPTWAdr = HPTWReadAdr; + assign DAPageFault = '0; + assign UpdatePTE = '0; + assign HPTWWrite = '0; + end + // Enable and select signals based on states assign StartWalk = (WalkerState == IDLE) & TLBMiss; assign HPTWRead = (WalkerState == L3_RD) | (WalkerState == L2_RD) | (WalkerState == L1_RD) | (WalkerState == L0_RD); assign DTLBWriteM = (WalkerState == LEAF & ~DAPageFault) & DTLBWalk; assign ITLBWriteF = (WalkerState == LEAF & ~DAPageFault) & ~DTLBWalk; - assign HPTWWrite = (WalkerState == UPDATE_PTE); - assign UpdatePTE = WalkerState == LEAF & DAPageFault; // FSM to track PageType based on the levels of the page table traversed @@ -241,7 +259,7 @@ module hptw else NextWalkerState = IDLE; // *** TODO update PTE with dirty/access. write to TLB and update memory. // probably want to write the PTE in UPDATE_PTE then go to leaf and update TLB. - UPDATE_PTE: if(DCacheStallM) NextWalkerState = UPDATE_PTE; + UPDATE_PTE: if(`HPTW_WRITES_SUPPORTED & DCacheStallM) NextWalkerState = UPDATE_PTE; else NextWalkerState = LEAF; default: begin // synthesis translate_off diff --git a/pipelined/src/mmu/tlbcontrol.sv b/pipelined/src/mmu/tlbcontrol.sv index 4a3e3221..3ab7a5c2 100644 --- a/pipelined/src/mmu/tlbcontrol.sv +++ b/pipelined/src/mmu/tlbcontrol.sv @@ -97,9 +97,14 @@ module tlbcontrol #(parameter ITLB = 0) ( // only execute non-user mode pages. assign ImproperPrivilege = ((EffectivePrivilegeMode == `U_MODE) & ~PTE_U) | ((EffectivePrivilegeMode == `S_MODE) & PTE_U); + if(`HPTW_WRITES_SUPPORTED) begin : hptwwrites + assign DAPageFault = Translate & TLBHit & ~PTE_A & ~TLBPageFault; + assign TLBPageFault = (Translate & TLBHit & (ImproperPrivilege | ~PTE_X | UpperBitsUnequalPageFault | Misaligned | ~PTE_V)); + end else begin // fault for software handling if access bit is off - assign DAPageFault = Translate & TLBHit & ~PTE_A & ~TLBPageFault; - assign TLBPageFault = (Translate & TLBHit & (ImproperPrivilege | ~PTE_X | UpperBitsUnequalPageFault | Misaligned | ~PTE_V)); + assign DAPageFault = ~PTE_A; + assign TLBPageFault = (Translate & TLBHit & (ImproperPrivilege | ~PTE_X | DAPageFault | UpperBitsUnequalPageFault | Misaligned | ~PTE_V)); + end end else begin:dtlb // Data TLB fault checking logic InvalidRead, InvalidWrite; @@ -114,9 +119,14 @@ module tlbcontrol #(parameter ITLB = 0) ( // Check for write error. Writes are invalid when the page's write bit is // low. assign InvalidWrite = WriteAccess & ~PTE_W; - // Fault for software handling if access bit is off or writing a page with dirty bit off - assign DAPageFault = Translate & TLBHit & (~PTE_A | WriteAccess & ~PTE_D) & ~TLBPageFault; - assign TLBPageFault = (Translate & TLBHit & (ImproperPrivilege | InvalidRead | InvalidWrite | UpperBitsUnequalPageFault | Misaligned | ~PTE_V)); + if(`HPTW_WRITES_SUPPORTED) begin : hptwwrites + assign DAPageFault = Translate & TLBHit & (~PTE_A | WriteAccess & ~PTE_D) & ~TLBPageFault; + assign TLBPageFault = (Translate & TLBHit & (ImproperPrivilege | InvalidRead | InvalidWrite | UpperBitsUnequalPageFault | Misaligned | ~PTE_V)); + end else begin + // Fault for software handling if access bit is off or writing a page with dirty bit off + assign DAPageFault = ~PTE_A | WriteAccess & ~PTE_D; + assign TLBPageFault = (Translate & TLBHit & (ImproperPrivilege | InvalidRead | InvalidWrite | DAPageFault | UpperBitsUnequalPageFault | Misaligned | ~PTE_V)); + end end assign TLBHit = CAMHit & TLBAccess;