diff --git a/wally-pipelined/src/lsu/lsu.sv b/wally-pipelined/src/lsu/lsu.sv index d138a933a..df3d32f28 100644 --- a/wally-pipelined/src/lsu/lsu.sv +++ b/wally-pipelined/src/lsu/lsu.sv @@ -123,6 +123,9 @@ module lsu logic HPTWStall; logic [`XLEN-1:0] HPTWPAdrE; logic [`XLEN-1:0] HPTWPAdrM; + logic [`XLEN-1:0] TranslationVAdr; + logic [`PA_BITS-1:0] TranslationPAdr; + logic UseTranslationVAdr; logic HPTWRead; logic [1:0] MemRWMtoDCache; logic [2:0] Funct3MtoDCache; @@ -162,15 +165,22 @@ module lsu .DTLBWriteM(DTLBWriteM), .HPTWReadPTE(HPTWReadPTE), .HPTWStall(HPTWStall), - .HPTWPAdrE(HPTWPAdrE), - .HPTWPAdrM(HPTWPAdrM), + .TranslationVAdr, + .TranslationPAdr, + .UseTranslationVAdr, .HPTWRead(HPTWRead), .SelPTW(SelPTW), .WalkerInstrPageFaultF(WalkerInstrPageFaultF), .WalkerLoadPageFaultM(WalkerLoadPageFaultM), .WalkerStorePageFaultM(WalkerStorePageFaultM)); -// assign PageTableEntryF = PTE; + logic [`XLEN-1:0] TranslationPAdrXLEN; + generate // *** needs fixing about truncation dh 7/17/21 + if (`XLEN == 32) assign TranslationPAdrXLEN = TranslationPAdr[31:0]; + else assign TranslationPAdrXLEN = {{(`XLEN-`PA_BITS){1'b0}}, TranslationPAdr[`PA_BITS-1:0]}; + endgenerate + mux2 #(`XLEN) HPTWPAdrMux(TranslationPAdrXLEN, TranslationVAdr, UseTranslationVAdr, HPTWPAdrE); // *** misleading to call it PAdr, bad because some bits have been truncated + flop #(`XLEN) HPTWPAdrMReg(clk, HPTWPAdrE, HPTWPAdrM); assign WalkerPageFaultM = WalkerStorePageFaultM | WalkerLoadPageFaultM; diff --git a/wally-pipelined/src/mmu/pagetablewalker.sv b/wally-pipelined/src/mmu/pagetablewalker.sv index 8c524fbd1..fe8aaf5b1 100644 --- a/wally-pipelined/src/mmu/pagetablewalker.sv +++ b/wally-pipelined/src/mmu/pagetablewalker.sv @@ -31,46 +31,29 @@ module pagetablewalker ( - // Control signals input logic clk, reset, - input logic [`XLEN-1:0] SATP_REGW, - - // Signals from TLBs (addresses to translate) - input logic [`XLEN-1:0] PCF, MemAdrM, - input logic ITLBMissF, DTLBMissM, - input logic [1:0] MemRWM, - - // Outputs to the TLBs (PTEs to write) - output logic [`XLEN-1:0] PTE, //PageTableEntryM, - output logic [1:0] PageType, - output logic ITLBWriteF, DTLBWriteM, - output logic SelPTW, - - - // *** modify to send to LSU // *** KMG: These are inputs/results from the ahblite whose addresses should have already been checked, so I don't think they need to be sent through the LSU - input logic [`XLEN-1:0] HPTWReadPTE, - input logic HPTWStall, - - // *** modify to send to LSU - output logic [`XLEN-1:0] HPTWPAdrE, // this probalby should be `PA_BITS wide - output logic [`XLEN-1:0] HPTWPAdrM, // this probalby should be `PA_BITS wide - output logic HPTWRead, - - - // Faults - output logic WalkerInstrPageFaultF, - output logic WalkerLoadPageFaultM, - output logic WalkerStorePageFaultM - ); - + input logic [`XLEN-1:0] SATP_REGW, // includes SATP.MODE to determine number of levels in page table + input logic [`XLEN-1:0] PCF, MemAdrM, // addresses to translate + input logic ITLBMissF, DTLBMissM, // TLB Miss + input logic [1:0] MemRWM, // 10 = read, 01 = write + input logic [`XLEN-1:0] HPTWReadPTE, // page table entry from LSU + input logic HPTWStall, // stall from LSU + output logic [`XLEN-1:0] PTE, // page table entry to TLBs + output logic [1:0] PageType, // page type to TLBs + output logic ITLBWriteF, DTLBWriteM, // write TLB with new entry + output logic SelPTW, // LSU Arbiter should select signals from the PTW rather than from the IEU + output logic [`XLEN-1:0] TranslationVAdr, + output logic [`PA_BITS-1:0] TranslationPAdr, + output logic UseTranslationVAdr, + output logic HPTWRead, // HPTW requesting to read memory + output logic WalkerInstrPageFaultF, WalkerLoadPageFaultM,WalkerStorePageFaultM // faults +); generate if (`MEM_VIRTMEM) begin // Internal signals logic DTLBWalk; // register TLBs translation miss requests logic [`PPN_BITS-1:0] BasePageTablePPN; - logic [`XLEN-1:0] TranslationVAdr; - logic [`PA_BITS-1:0] TranslationPAdr; logic [`PPN_BITS-1:0] CurrentPPN; logic MemWrite; logic Executable, Writable, Readable, Valid; @@ -96,13 +79,12 @@ module pagetablewalker // Determine which address to translate assign TranslationVAdr = DTLBWalk ? MemAdrM : PCF; - - flop #(`XLEN) HPTWPAdrMReg(clk, HPTWPAdrE, HPTWPAdrM); - flopenrc #(1) TLBMissMReg(clk, reset, EndWalk, StartWalk | EndWalk, DTLBMissM, DTLBWalk); - flopenl #(.TYPE(statetype)) WalkerStateReg(clk, reset, 1'b1, NextWalkerState, IDLE, WalkerState); - flopenr #(`XLEN) PTEReg(clk, reset, PRegEn, HPTWReadPTE, PTE); // Capture page table entry from data cache - assign CurrentPPN = PTE[`PPN_BITS+9:10]; + assign CurrentPPN = PTE[`PPN_BITS+9:10]; + // State flops + flopenrc #(1) TLBMissMReg(clk, reset, EndWalk, StartWalk | EndWalk, DTLBMissM, DTLBWalk); // track whether walk is for DTLB or ITLB + flopenr #(`XLEN) PTEReg(clk, reset, PRegEn, HPTWReadPTE, PTE); // Capture page table entry from data cache + // 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 {Executable, Writable, Readable, Valid} = PTE[3:0]; @@ -119,6 +101,7 @@ module pagetablewalker assign SelPTW = (WalkerState != IDLE) & (WalkerState != FAULT); assign DTLBWriteM = (WalkerState == LEAF) & DTLBWalk; assign ITLBWriteF = (WalkerState == LEAF) & ~DTLBWalk; + assign UseTranslationVAdr = (NextWalkerState == LEAF) || (WalkerState == LEAF); // Raise faults. DTLBMiss assign WalkerInstrPageFaultF = (WalkerState == FAULT) & ~DTLBWalk; @@ -136,49 +119,31 @@ module pagetablewalker default: NextPageType = PageType; endcase - // TranslationPAdr mux - if (`XLEN==32) begin - logic [9:0] VPN1, VPN0; - assign VPN1 = TranslationVAdr[31:22]; - assign VPN0 = TranslationVAdr[21:12]; + // TranslationPAdr muxing + if (`XLEN==32) begin // RV32 + logic [9:0] VPN; + logic [`PPN_BITS-1:0] PPN; + assign VPN = ((WalkerState == LEVEL1_SET_ADR) | (WalkerState == LEVEL1_READ)) ? TranslationVAdr[31:22] : TranslationVAdr[21:12]; // select VPN field based on HPTW state + assign PPN = ((WalkerState == LEVEL1_SET_ADR) | (WalkerState == LEVEL1_READ)) ? BasePageTablePPN : CurrentPPN; + assign TranslationPAdr = {PPN, VPN, 2'b00}; + end else begin // RV64 + logic [8:0] VPN; + logic [`PPN_BITS-1:0] PPN; always_comb - case (WalkerState) - LEVEL1_SET_ADR: TranslationPAdr = {BasePageTablePPN, VPN1, 2'b00}; - LEVEL1_READ: TranslationPAdr = {BasePageTablePPN, VPN1, 2'b00}; - LEVEL1: if (NextWalkerState == LEAF) TranslationPAdr = {2'b00, TranslationVAdr[31:0]}; // ***check this and similar in LEVEL0 and LEAF - else TranslationPAdr = {CurrentPPN, VPN0, 2'b00}; - LEVEL0_SET_ADR: TranslationPAdr = {CurrentPPN, VPN0, 2'b00}; - LEVEL0_READ: TranslationPAdr = {CurrentPPN, VPN0, 2'b00}; - LEVEL0: TranslationPAdr = {2'b00, TranslationVAdr[31:0]}; - LEAF: TranslationPAdr = {2'b00, TranslationVAdr[31:0]}; - default: TranslationPAdr = 0; // cause seg fault if this is improperly used - endcase - end else begin - logic [8:0] VPN3, VPN2, VPN1, VPN0; - assign VPN3 = TranslationVAdr[47:39]; - assign VPN2 = TranslationVAdr[38:30]; - assign VPN1 = TranslationVAdr[29:21]; - assign VPN0 = TranslationVAdr[20:12]; - always_comb - case (WalkerState) - LEVEL3_SET_ADR: TranslationPAdr = {BasePageTablePPN, VPN3, 3'b000}; - LEVEL3_READ: TranslationPAdr = {BasePageTablePPN, VPN3, 3'b000}; - LEVEL3: if (NextWalkerState == LEAF) TranslationPAdr = TranslationVAdr[`PA_BITS-1:0]; - else TranslationPAdr = {(SvMode == `SV48) ? CurrentPPN : BasePageTablePPN, VPN2, 3'b000}; - LEVEL2_SET_ADR: TranslationPAdr = {(SvMode == `SV48) ? CurrentPPN : BasePageTablePPN, VPN2, 3'b000}; - LEVEL2_READ: TranslationPAdr = {(SvMode == `SV48) ? CurrentPPN : BasePageTablePPN, VPN2, 3'b000}; - LEVEL2: if (NextWalkerState == LEAF) TranslationPAdr = TranslationVAdr[`PA_BITS-1:0]; - else TranslationPAdr = {CurrentPPN, VPN1, 3'b000}; - LEVEL1_SET_ADR: TranslationPAdr = {CurrentPPN, VPN1, 3'b000}; - LEVEL1_READ: TranslationPAdr = {CurrentPPN, VPN1, 3'b000}; - LEVEL1: if (NextWalkerState == LEAF) TranslationPAdr = TranslationVAdr[`PA_BITS-1:0]; - else TranslationPAdr = {CurrentPPN, VPN0, 3'b000}; - LEVEL0_SET_ADR: TranslationPAdr = {CurrentPPN, VPN0, 3'b000}; - LEVEL0_READ: TranslationPAdr = {CurrentPPN, VPN0, 3'b000}; - LEVEL0: TranslationPAdr = TranslationVAdr[`PA_BITS-1:0]; - LEAF: TranslationPAdr = TranslationVAdr[`PA_BITS-1:0]; - default: TranslationPAdr = 0; // cause seg fault if this is improperly used - endcase + case (WalkerState) // select VPN field based on HPTW state + LEVEL3_SET_ADR: VPN = TranslationVAdr[47:39]; + LEVEL3_READ: VPN = TranslationVAdr[47:39]; + LEVEL3: VPN = TranslationVAdr[38:30]; + LEVEL2_SET_ADR: VPN = TranslationVAdr[38:30]; + LEVEL2_READ: VPN = TranslationVAdr[38:30]; + LEVEL2: VPN = TranslationVAdr[29:21]; + LEVEL1_SET_ADR: VPN = TranslationVAdr[29:21]; + LEVEL1_READ: VPN = TranslationVAdr[29:21]; + default: VPN = TranslationVAdr[20:12]; + endcase + assign PPN = ((WalkerState == LEVEL3_SET_ADR) | (WalkerState == LEVEL3_READ) | + (SvMode != `SV48 & ((WalkerState == LEVEL2_SET_ADR) | (WalkerState == LEVEL2_READ)))) ? BasePageTablePPN : CurrentPPN; + assign TranslationPAdr = {PPN, VPN, 3'b000}; end if (`XLEN == 32) begin @@ -186,17 +151,18 @@ module pagetablewalker assign TerapageMisaligned = 0; // not applicable assign GigapageMisaligned = 0; // not applicable assign MegapageMisaligned = |(CurrentPPN[9:0]); // must have zero PPN0 - assign HPTWPAdrE = TranslationPAdr[31:0]; // ***not right? end else begin assign InitialWalkerState = (SvMode == `SV48) ? LEVEL3_SET_ADR : LEVEL2_SET_ADR; assign TerapageMisaligned = |(CurrentPPN[26:0]); // must have zero PPN2, PPN1, PPN0 assign GigapageMisaligned = |(CurrentPPN[17:0]); // must have zero PPN1 and PPN0 assign MegapageMisaligned = |(CurrentPPN[8:0]); // must have zero PPN0 - assign HPTWPAdrE = {{(`XLEN-`PA_BITS){1'b0}}, TranslationPAdr[`PA_BITS-1:0]}; end // Page Table Walker FSM - // ***Is there a w ay to reduce the number of cycles needed to do the walk? + // If the setup time on the D$ RAM is short, it should be possible to merge the LEVELx_READ and LEVELx states + // to decrease the latency of the HPTW. However, if the D$ is a cycle limiter, it's better to leave the + // HPTW as shown below to keep the D$ setup time out of the critical path. + flopenl #(.TYPE(statetype)) WalkerStateReg(clk, reset, 1'b1, NextWalkerState, IDLE, WalkerState); always_comb case (WalkerState) IDLE: if (StartWalk) NextWalkerState = InitialWalkerState; @@ -231,14 +197,10 @@ module pagetablewalker NextWalkerState = IDLE; // should never be reached end endcase - end else begin - assign HPTWPAdrE = 0; - assign HPTWRead = 0; - assign WalkerInstrPageFaultF = 0; - assign WalkerLoadPageFaultM = 0; - assign WalkerStorePageFaultM = 0; - assign SelPTW = 0; + end else begin // No Virtual memory supported; tie HPTW outputs to 0 + assign HPTWRead = 0; assign SelPTW = 0; + assign WalkerInstrPageFaultF = 0; assign WalkerLoadPageFaultM = 0; assign WalkerStorePageFaultM = 0; + assign TranslationVAdr = 0; assign TranslationPAdr = 0; assign UseTranslationVAdr = 0; end endgenerate - endmodule