forked from Github_Repos/cvw
Updated the ptw, lsuarb and dcache to hopefully solve the interlock issues.
This commit is contained in:
parent
ca63f6bc48
commit
e0f719d513
67
wally-pipelined/src/cache/dcache.sv
vendored
67
wally-pipelined/src/cache/dcache.sv
vendored
@ -43,7 +43,7 @@ module dcache
|
||||
|
||||
input logic [`XLEN-1:0] WriteDataM,
|
||||
output logic [`XLEN-1:0] ReadDataW,
|
||||
output logic [`XLEN-1:0] ReadDataM,
|
||||
output logic [`XLEN-1:0] ReadDataM,
|
||||
output logic DCacheStall,
|
||||
output logic CommittedM,
|
||||
|
||||
@ -53,6 +53,7 @@ module dcache
|
||||
input logic DTLBMissM,
|
||||
input logic CacheableM,
|
||||
input logic DTLBWriteM,
|
||||
input logic SelPTW,
|
||||
// ahb side
|
||||
output logic [`PA_BITS-1:0] AHBPAdr, // to ahb
|
||||
output logic AHBRead,
|
||||
@ -443,7 +444,13 @@ module dcache
|
||||
// The page table walker asserts it's control 1 cycle
|
||||
// after the TLBs miss.
|
||||
DCacheStall = 1'b1;
|
||||
NextState = STATE_READY;
|
||||
end
|
||||
else if(SelPTW) begin
|
||||
// Now we have activated the ptw.
|
||||
// Do not assert Stall as we are now directing the stall the ptw.
|
||||
NextState = STATE_PTW_READY;
|
||||
CommittedM = 1'b1;
|
||||
end
|
||||
// amo hit
|
||||
else if(|AtomicM & CacheableM & ~(ExceptionM | PendingInterruptM) & CacheHit & ~DTLBMissM) begin
|
||||
@ -592,7 +599,7 @@ module dcache
|
||||
// now all output connect to PTW instead of CPU.
|
||||
CommittedM = 1'b1;
|
||||
// return to ready if page table walk completed.
|
||||
if (DTLBWriteM) begin
|
||||
if (~SelPTW) begin
|
||||
NextState = STATE_PTW_ACCESS_AFTER_WALK;
|
||||
|
||||
// read hit valid cached
|
||||
@ -650,61 +657,15 @@ module dcache
|
||||
|
||||
STATE_PTW_READ_MISS_READ_WORD_DELAY: begin
|
||||
SelAdrM = 1'b1;
|
||||
NextState = STATE_PTW_READY;
|
||||
NextState = STATE_PTW_READY;
|
||||
CommittedM = 1'b1;
|
||||
end
|
||||
|
||||
STATE_PTW_ACCESS_AFTER_WALK: begin
|
||||
SelAdrM = 1'b1;
|
||||
// amo hit
|
||||
if(|AtomicM & CacheableM & ~(ExceptionM | PendingInterruptM) & CacheHit & ~DTLBMissM) begin
|
||||
NextState = STATE_AMO_UPDATE;
|
||||
DCacheStall = 1'b1;
|
||||
|
||||
if(StallW) NextState = STATE_CPU_BUSY;
|
||||
else NextState = STATE_AMO_UPDATE;
|
||||
end
|
||||
// read hit valid cached
|
||||
else if(MemRWM[1] & CacheableM & ~(ExceptionM | PendingInterruptM) & CacheHit & ~DTLBMissM) begin
|
||||
DCacheStall = 1'b0;
|
||||
|
||||
if(StallW) NextState = STATE_CPU_BUSY;
|
||||
else NextState = STATE_READY;
|
||||
end
|
||||
// write hit valid cached
|
||||
else if (MemRWM[0] & CacheableM & ~(ExceptionM | PendingInterruptM) & CacheHit & ~DTLBMissM) begin
|
||||
DCacheStall = 1'b0;
|
||||
SRAMWordWriteEnableM = 1'b1;
|
||||
SetDirtyM = 1'b1;
|
||||
|
||||
if(StallW) NextState = STATE_CPU_BUSY;
|
||||
else NextState = STATE_READY;
|
||||
end
|
||||
// read or write miss valid cached
|
||||
else if((|MemRWM) & CacheableM & ~(ExceptionM | PendingInterruptM) & ~CacheHit & ~DTLBMissM) begin
|
||||
NextState = STATE_MISS_FETCH_WDV;
|
||||
CntReset = 1'b1;
|
||||
DCacheStall = 1'b1;
|
||||
end
|
||||
// uncached write
|
||||
else if(MemRWM[0] & ~CacheableM & ~ExceptionM & ~DTLBMissM) begin
|
||||
NextState = STATE_UNCACHED_WRITE;
|
||||
CntReset = 1'b1;
|
||||
DCacheStall = 1'b1;
|
||||
AHBWrite = 1'b1;
|
||||
end
|
||||
// uncached read
|
||||
else if(MemRWM[1] & ~CacheableM & ~ExceptionM & ~DTLBMissM) begin
|
||||
NextState = STATE_UNCACHED_READ;
|
||||
CntReset = 1'b1;
|
||||
DCacheStall = 1'b1;
|
||||
AHBRead = 1'b1;
|
||||
end
|
||||
// fault
|
||||
else if(AnyCPUReqM & (ExceptionM | PendingInterruptM) & ~DTLBMissM) begin
|
||||
NextState = STATE_READY;
|
||||
end
|
||||
else NextState = STATE_READY;
|
||||
DCacheStall = 1'b1;
|
||||
SelAdrM = 1'b1;
|
||||
CommittedM = 1'b1;
|
||||
NextState = STATE_READY;
|
||||
end
|
||||
|
||||
STATE_CPU_BUSY : begin
|
||||
|
@ -126,7 +126,6 @@ module lsu
|
||||
logic HPTWStall;
|
||||
logic [`XLEN-1:0] HPTWPAdrE;
|
||||
logic [`XLEN-1:0] HPTWPAdrM;
|
||||
logic HPTWTranslate;
|
||||
logic HPTWReadM;
|
||||
logic [1:0] MemRWMtoDCache;
|
||||
logic [2:0] Funct3MtoDCache;
|
||||
@ -170,8 +169,8 @@ module lsu
|
||||
.HPTWStall(HPTWStall),
|
||||
.HPTWPAdrE(HPTWPAdrE),
|
||||
.HPTWPAdrM(HPTWPAdrM),
|
||||
.HPTWTranslate(HPTWTranslate),
|
||||
.HPTWReadM(HPTWReadM),
|
||||
.SelPTW(SelPTW),
|
||||
.WalkerInstrPageFaultF(WalkerInstrPageFaultF),
|
||||
.WalkerLoadPageFaultM(WalkerLoadPageFaultM),
|
||||
.WalkerStorePageFaultM(WalkerStorePageFaultM));
|
||||
@ -182,7 +181,7 @@ module lsu
|
||||
lsuArb arbiter(.clk(clk),
|
||||
.reset(reset),
|
||||
// HPTW connection
|
||||
.HPTWTranslate(HPTWTranslate),
|
||||
.SelPTW(SelPTW),
|
||||
.HPTWReadM(HPTWReadM),
|
||||
.HPTWPAdrE(HPTWPAdrE),
|
||||
.HPTWPAdrM(HPTWPAdrM),
|
||||
@ -214,8 +213,9 @@ module lsu
|
||||
.ReadDataWfromDCache(ReadDataWfromDCache),
|
||||
.CommittedMfromDCache(CommittedMfromDCache),
|
||||
.PendingInterruptMtoDCache(PendingInterruptMtoDCache),
|
||||
.DCacheStall(DCacheStall),
|
||||
.SelPTW(SelPTW));
|
||||
.DCacheStall(DCacheStall));
|
||||
|
||||
|
||||
|
||||
|
||||
mmu #(.TLB_ENTRIES(`DTLB_ENTRIES), .IMMU(0))
|
||||
@ -243,7 +243,9 @@ module lsu
|
||||
// .SelRegions(DHSELRegionsM),
|
||||
.*); // *** the pma/pmp instruction acess faults don't really matter here. is it possible to parameterize which outputs exist?
|
||||
|
||||
// *** BUG, this is most likely wrong
|
||||
assign CacheableMtoDCache = SelPTW ? 1'b1 : CacheableM;
|
||||
|
||||
generate
|
||||
if (`XLEN == 32) assign DCtoAHBSizeM = CacheableMtoDCache ? 3'b010 : Funct3MtoDCache;
|
||||
else assign DCtoAHBSizeM = CacheableMtoDCache ? 3'b011 : Funct3MtoDCache;
|
||||
@ -335,6 +337,7 @@ module lsu
|
||||
.DTLBMissM(DTLBMissM),
|
||||
.CacheableM(CacheableMtoDCache),
|
||||
.DTLBWriteM(DTLBWriteM),
|
||||
.SelPTW(SelPTW),
|
||||
|
||||
// AHB connection
|
||||
.AHBPAdr(DCtoAHBPAdrM),
|
||||
|
@ -30,7 +30,7 @@ module lsuArb
|
||||
(input logic clk, reset,
|
||||
|
||||
// from page table walker
|
||||
input logic HPTWTranslate,
|
||||
input logic SelPTW,
|
||||
input logic HPTWReadM,
|
||||
input logic [`XLEN-1:0] HPTWPAdrE,
|
||||
input logic [`XLEN-1:0] HPTWPAdrM,
|
||||
@ -62,7 +62,6 @@ module lsuArb
|
||||
output logic [`XLEN-1:0] MemAdrEtoDCache,
|
||||
output logic StallWtoDCache,
|
||||
output logic PendingInterruptMtoDCache,
|
||||
output logic SelPTW,
|
||||
|
||||
|
||||
// from D Cache
|
||||
@ -73,73 +72,11 @@ module lsuArb
|
||||
input logic DCacheStall
|
||||
|
||||
);
|
||||
|
||||
// HPTWTranslate is the request for memory by the page table walker. When
|
||||
// this is high the page table walker gains priority over the CPU's data
|
||||
// input. Note the ptw only makes a request after an instruction or data
|
||||
// tlb miss. It is entirely possible the dcache is currently processing
|
||||
// a data cache miss when an instruction tlb miss occurs. If an instruction
|
||||
// in the E stage causes a d cache miss, the d cache will immediately start
|
||||
// processing the request. Simultaneously the ITLB misses. By the time
|
||||
// the TLB miss causes the page table walker to issue the first request
|
||||
// to data memory the d cache is already busy. We can interlock by
|
||||
// leveraging Stall as a d cache busy. We will need an FSM to handle this.
|
||||
|
||||
typedef enum{StateReady,
|
||||
StatePTWPending,
|
||||
StatePTWActive} statetype;
|
||||
|
||||
|
||||
statetype CurrState, NextState;
|
||||
logic [2:0] PTWSize;
|
||||
|
||||
|
||||
flopenl #(.TYPE(statetype)) StateReg(.clk(clk),
|
||||
.load(reset),
|
||||
.en(1'b1),
|
||||
.d(NextState),
|
||||
.val(StateReady),
|
||||
.q(CurrState));
|
||||
|
||||
always_comb begin
|
||||
case(CurrState)
|
||||
StateReady:
|
||||
if (HPTWTranslate) NextState = StatePTWActive;
|
||||
else NextState = StateReady;
|
||||
StatePTWActive:
|
||||
if (HPTWTranslate) NextState = StatePTWActive;
|
||||
else NextState = StateReady;
|
||||
default: NextState = StateReady;
|
||||
endcase
|
||||
end
|
||||
|
||||
/* -----\/----- EXCLUDED -----\/-----
|
||||
|
||||
always_comb begin
|
||||
case(CurrState)
|
||||
StateReady:
|
||||
/-* -----\/----- EXCLUDED -----\/-----
|
||||
if (HPTWTranslate & DataStall) NextState = StatePTWPending;
|
||||
else
|
||||
-----/\----- EXCLUDED -----/\----- *-/
|
||||
if (HPTWTranslate) NextState = StatePTWActive;
|
||||
else NextState = StateReady;
|
||||
StatePTWPending:
|
||||
if (HPTWTranslate & ~DataStall) NextState = StatePTWActive;
|
||||
else if (HPTWTranslate & DataStall) NextState = StatePTWPending;
|
||||
else NextState = StateReady;
|
||||
StatePTWActive:
|
||||
if (HPTWTranslate) NextState = StatePTWActive;
|
||||
else NextState = StateReady;
|
||||
default: NextState = StateReady;
|
||||
endcase
|
||||
end
|
||||
|
||||
-----/\----- EXCLUDED -----/\----- */
|
||||
|
||||
// multiplex the outputs to LSU
|
||||
assign DisableTranslation = SelPTW; // change names between SelPTW would be confusing in DTLB.
|
||||
assign SelPTW = (CurrState == StatePTWActive && HPTWTranslate) || (CurrState == StateReady && HPTWTranslate);
|
||||
assign MemRWMtoDCache = SelPTW ? {HPTWReadM, 1'b0} : MemRWM;
|
||||
|
||||
generate
|
||||
|
@ -9,21 +9,21 @@
|
||||
//
|
||||
// Purpose: Page Table Walker
|
||||
// Part of the Memory Management Unit (MMU)
|
||||
//
|
||||
//
|
||||
// A component of the Wally configurable RISC-V project.
|
||||
//
|
||||
//
|
||||
// Copyright (C) 2021 Harvey Mudd College & Oklahoma State University
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation
|
||||
// files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy,
|
||||
// modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software
|
||||
// files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy,
|
||||
// modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software
|
||||
// is furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||||
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||
// BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||||
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||
// BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT
|
||||
// OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
///////////////////////////////////////////
|
||||
|
||||
@ -37,107 +37,94 @@
|
||||
module pagetablewalker
|
||||
(
|
||||
// Control signals
|
||||
input logic clk, reset,
|
||||
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,
|
||||
input logic ITLBMissF, DTLBMissM,
|
||||
input logic [1:0] MemRWM,
|
||||
|
||||
// Outputs to the TLBs (PTEs to write)
|
||||
output logic [`XLEN-1:0] PageTableEntryF, PageTableEntryM,
|
||||
output logic [1:0] PageTypeF, PageTypeM,
|
||||
output logic ITLBWriteF, DTLBWriteM,
|
||||
|
||||
|
||||
output logic [1:0] PageTypeF, PageTypeM,
|
||||
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 MMUReady,
|
||||
input logic HPTWStall,
|
||||
input logic MMUReady,
|
||||
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 HPTWTranslate, // *** rename to HPTWReq
|
||||
output logic HPTWReadM,
|
||||
output logic [`XLEN-1:0] HPTWPAdrM, // this probalby should be `PA_BITS wide
|
||||
output logic HPTWReadM,
|
||||
|
||||
|
||||
// Faults
|
||||
output logic WalkerInstrPageFaultF,
|
||||
output logic WalkerLoadPageFaultM,
|
||||
output logic WalkerStorePageFaultM
|
||||
output logic WalkerInstrPageFaultF,
|
||||
output logic WalkerLoadPageFaultM,
|
||||
output logic WalkerStorePageFaultM
|
||||
);
|
||||
|
||||
logic HPTWReadE;
|
||||
logic HPTWReadE;
|
||||
|
||||
generate
|
||||
if (`MEM_VIRTMEM) begin
|
||||
// Internal signals
|
||||
// register TLBs translation miss requests
|
||||
logic ITLBMissFQ, DTLBMissMQ;
|
||||
|
||||
logic [`PPN_BITS-1:0] BasePageTablePPN;
|
||||
logic [`XLEN-1:0] TranslationVAdr;
|
||||
logic [`XLEN-1:0] SavedPTE, CurrentPTE;
|
||||
logic [`PA_BITS-1:0] TranslationPAdr;
|
||||
logic [`PPN_BITS-1:0] CurrentPPN;
|
||||
logic [`SVMODE_BITS-1:0] SvMode;
|
||||
logic MemStore;
|
||||
logic DTLBWriteM_d;
|
||||
logic ITLBMissFQ, DTLBMissMQ;
|
||||
|
||||
logic [`PPN_BITS-1:0] BasePageTablePPN;
|
||||
logic [`XLEN-1:0] TranslationVAdr;
|
||||
logic [`XLEN-1:0] SavedPTE, CurrentPTE;
|
||||
logic [`PA_BITS-1:0] TranslationPAdr;
|
||||
logic [`PPN_BITS-1:0] CurrentPPN;
|
||||
logic [`SVMODE_BITS-1:0] SvMode;
|
||||
logic MemStore;
|
||||
|
||||
// PTE Control Bits
|
||||
logic Dirty, Accessed, Global, User,
|
||||
logic Dirty, Accessed, Global, User,
|
||||
Executable, Writable, Readable, Valid;
|
||||
// PTE descriptions
|
||||
logic ValidPTE, AccessAlert, MegapageMisaligned, BadMegapage, LeafPTE;
|
||||
logic ValidPTE, AccessAlert, MegapageMisaligned, BadMegapage, LeafPTE;
|
||||
|
||||
// Outputs of walker
|
||||
logic [`XLEN-1:0] PageTableEntry;
|
||||
logic [1:0] PageType;
|
||||
logic StartWalk;
|
||||
logic EndWalk;
|
||||
|
||||
typedef enum {LEVEL0_WDV,
|
||||
logic [`XLEN-1:0] PageTableEntry;
|
||||
logic [1:0] PageType;
|
||||
logic StartWalk;
|
||||
logic EndWalk;
|
||||
|
||||
typedef enum {LEVEL0_SET_ADRE,
|
||||
LEVEL0_WDV,
|
||||
LEVEL0,
|
||||
LEVEL1_SET_ADRE,
|
||||
LEVEL1_WDV,
|
||||
LEVEL1,
|
||||
LEVEL2_SET_ADRE,
|
||||
LEVEL2_WDV,
|
||||
LEVEL2,
|
||||
LEVEL3_SET_ADRE,
|
||||
LEVEL3_WDV,
|
||||
LEVEL3,
|
||||
LEAF,
|
||||
IDLE,
|
||||
START,
|
||||
FAULT} statetype;
|
||||
|
||||
statetype WalkerState, NextWalkerState;
|
||||
statetype WalkerState, NextWalkerState, PreviousWalkerState;
|
||||
|
||||
logic PRegEn;
|
||||
logic SelDataTranslation;
|
||||
|
||||
|
||||
flop #(`XLEN) HPTWPAdrMReg(.clk(clk),
|
||||
.d(HPTWPAdrE),
|
||||
.q(HPTWPAdrM));
|
||||
logic PRegEn;
|
||||
logic SelDataTranslation;
|
||||
logic AnyTLBMissM;
|
||||
|
||||
flop #(2) PageTypeReg(.clk(clk),
|
||||
.d(PageType),
|
||||
.q(PageTypeM));
|
||||
|
||||
flop #(`XLEN) PageTableEntryReg(.clk(clk),
|
||||
.d(PageTableEntry),
|
||||
.q(PageTableEntryM));
|
||||
|
||||
flop #(1) DTLBWriteReg(.clk(clk),
|
||||
.d(DTLBWriteM_d),
|
||||
.q(DTLBWriteM));
|
||||
|
||||
flop #(1) HPTWReadMReg(.clk(clk),
|
||||
.d(HPTWReadE),
|
||||
.q(HPTWReadM));
|
||||
flop #(`XLEN) HPTWPAdrMReg(.clk(clk),
|
||||
.d(HPTWPAdrE),
|
||||
.q(HPTWPAdrM));
|
||||
|
||||
|
||||
|
||||
assign SvMode = SATP_REGW[`XLEN-1:`XLEN-`SVMODE_BITS];
|
||||
@ -147,7 +134,7 @@ module pagetablewalker
|
||||
assign MemStore = MemRWM[0];
|
||||
|
||||
// Prefer data address translations over instruction address translations
|
||||
assign TranslationVAdr = (SelDataTranslation) ? MemAdrM : PCF; // *** need to register TranslationVAdr
|
||||
assign TranslationVAdr = (SelDataTranslation) ? MemAdrM : PCF;
|
||||
assign SelDataTranslation = DTLBMissMQ | DTLBMissM;
|
||||
|
||||
flopenrc #(1)
|
||||
@ -157,7 +144,7 @@ module pagetablewalker
|
||||
.clear(EndWalk),
|
||||
.d(DTLBMissM),
|
||||
.q(DTLBMissMQ));
|
||||
|
||||
|
||||
flopenrc #(1)
|
||||
ITLBMissMReg(.clk(clk),
|
||||
.reset(reset),
|
||||
@ -165,22 +152,16 @@ module pagetablewalker
|
||||
.clear(EndWalk),
|
||||
.d(ITLBMissF),
|
||||
.q(ITLBMissFQ));
|
||||
|
||||
|
||||
assign StartWalk = WalkerState == IDLE && (DTLBMissM | ITLBMissF);
|
||||
assign EndWalk = WalkerState == LEAF ||
|
||||
//(WalkerState == LEVEL0 && ValidPTE && LeafPTE && ~AccessAlert) ||
|
||||
//(WalkerState == LEVEL1 && ValidPTE && LeafPTE && ~AccessAlert) ||
|
||||
//(WalkerState == LEVEL2 && ValidPTE && LeafPTE && ~AccessAlert) ||
|
||||
//(WalkerState == LEVEL3 && ValidPTE && LeafPTE && ~AccessAlert) ||
|
||||
(WalkerState == FAULT);
|
||||
|
||||
assign HPTWTranslate = (DTLBMissMQ | ITLBMissFQ);
|
||||
//assign HPTWTranslate = DTLBMissM | ITLBMissF;
|
||||
|
||||
assign AnyTLBMissM = DTLBMissM | ITLBMissF;
|
||||
|
||||
assign StartWalk = WalkerState == IDLE & AnyTLBMissM;
|
||||
assign EndWalk = WalkerState == LEAF || WalkerState == FAULT;
|
||||
|
||||
// unswizzle PTE bits
|
||||
assign {Dirty, Accessed, Global, User,
|
||||
Executable, Writable, Readable, Valid} = CurrentPTE[7:0];
|
||||
Executable, Writable, Readable, Valid} = CurrentPTE[7:0];
|
||||
|
||||
// Assign PTE descriptors common across all XLEN values
|
||||
assign LeafPTE = Executable | Writable | Readable;
|
||||
@ -189,398 +170,391 @@ module pagetablewalker
|
||||
|
||||
// Assign specific outputs to general outputs
|
||||
assign PageTableEntryF = PageTableEntry;
|
||||
//assign PageTableEntryM = PageTableEntry;
|
||||
assign PageTableEntryM = PageTableEntry;
|
||||
assign PageTypeF = PageType;
|
||||
//assign PageTypeM = PageType;
|
||||
assign PageTypeM = PageType;
|
||||
|
||||
|
||||
// generate
|
||||
if (`XLEN == 32) begin
|
||||
logic [9:0] VPN1, VPN0;
|
||||
logic [9:0] VPN1, VPN0;
|
||||
|
||||
flopenl #(.TYPE(statetype)) mmureg(clk, reset, 1'b1, NextWalkerState, IDLE, WalkerState);
|
||||
flopenl #(.TYPE(statetype)) mmureg(clk, reset, 1'b1, NextWalkerState, IDLE, WalkerState);
|
||||
|
||||
/* -----\/----- EXCLUDED -----\/-----
|
||||
assign PRegEn = (WalkerState == LEVEL1_WDV || WalkerState == LEVEL0_WDV) && ~HPTWStall;
|
||||
assign PRegEn = (WalkerState == LEVEL1_WDV || WalkerState == LEVEL0_WDV) && ~HPTWStall;
|
||||
-----/\----- EXCLUDED -----/\----- */
|
||||
|
||||
// State transition logic
|
||||
always_comb begin
|
||||
// State transition logic
|
||||
always_comb begin
|
||||
PRegEn = 1'b0;
|
||||
TranslationPAdr = '0;
|
||||
HPTWReadE = 1'b0;
|
||||
PageTableEntry = '0;
|
||||
PageType = '0;
|
||||
DTLBWriteM_d = '0;
|
||||
ITLBWriteF = '0;
|
||||
|
||||
WalkerInstrPageFaultF = 1'b0;
|
||||
WalkerLoadPageFaultM = 1'b0;
|
||||
WalkerStorePageFaultM = 1'b0;
|
||||
PageTableEntry = '0;
|
||||
PageType = '0;
|
||||
DTLBWriteM = '0;
|
||||
ITLBWriteF = '0;
|
||||
|
||||
case (WalkerState)
|
||||
IDLE: begin
|
||||
if (HPTWTranslate && SvMode == `SV32) begin // *** Added SvMode
|
||||
NextWalkerState = START;
|
||||
end else begin
|
||||
NextWalkerState = IDLE;
|
||||
end
|
||||
end
|
||||
WalkerInstrPageFaultF = 1'b0;
|
||||
WalkerLoadPageFaultM = 1'b0;
|
||||
WalkerStorePageFaultM = 1'b0;
|
||||
|
||||
START: begin
|
||||
NextWalkerState = LEVEL1_WDV;
|
||||
TranslationPAdr = {BasePageTablePPN, VPN1, 2'b00};
|
||||
HPTWReadE = 1'b1;
|
||||
end
|
||||
|
||||
LEVEL1_WDV: begin
|
||||
TranslationPAdr = {BasePageTablePPN, VPN1, 2'b00};
|
||||
HPTWReadE = 1'b1;
|
||||
if (HPTWStall) begin
|
||||
NextWalkerState = LEVEL1_WDV;
|
||||
end else begin
|
||||
NextWalkerState = LEVEL1;
|
||||
SelPTW = 1'b1;
|
||||
|
||||
case (WalkerState)
|
||||
IDLE: begin
|
||||
SelPTW = 1'b0;
|
||||
if (AnyTLBMissM & SvMode == `SV32) begin
|
||||
NextWalkerState = LEVEL1_SET_ADRE;
|
||||
end else begin
|
||||
NextWalkerState = IDLE;
|
||||
end
|
||||
end
|
||||
|
||||
LEVEL1_SET_ADRE: begin
|
||||
NextWalkerState = LEVEL1_WDV;
|
||||
TranslationPAdr = {BasePageTablePPN, VPN1, 2'b00};
|
||||
end
|
||||
|
||||
LEVEL1_WDV: begin
|
||||
TranslationPAdr = {BasePageTablePPN, VPN1, 2'b00};
|
||||
HPTWReadE = 1'b1;
|
||||
if (HPTWStall) begin
|
||||
NextWalkerState = LEVEL1_WDV;
|
||||
end else begin
|
||||
NextWalkerState = LEVEL1;
|
||||
PRegEn = 1'b1;
|
||||
end
|
||||
end
|
||||
|
||||
LEVEL1: begin
|
||||
// *** <FUTURE WORK> According to the architecture, we should
|
||||
// fault upon finding a superpage that is misaligned or has 0
|
||||
// access bit. The following commented line of code is
|
||||
// supposed to perform that check. However, it is untested.
|
||||
if (ValidPTE && LeafPTE && ~BadMegapage) begin
|
||||
end
|
||||
end
|
||||
|
||||
LEVEL1: begin
|
||||
// *** <FUTURE WORK> According to the architecture, we should
|
||||
// fault upon finding a superpage that is misaligned or has 0
|
||||
// access bit. The following commented line of code is
|
||||
// supposed to perform that check. However, it is untested.
|
||||
if (ValidPTE && LeafPTE && ~BadMegapage) begin
|
||||
NextWalkerState = LEAF;
|
||||
PageTableEntry = CurrentPTE;
|
||||
PageType = (WalkerState == LEVEL1) ? 2'b01 : 2'b00; // *** not sure about this mux?
|
||||
DTLBWriteM_d = DTLBMissMQ;
|
||||
ITLBWriteF = ~DTLBMissMQ; // Prefer data over instructions
|
||||
TranslationPAdr = {2'b00, TranslationVAdr[31:0]};
|
||||
end
|
||||
// else if (ValidPTE && LeafPTE) NextWalkerState = LEAF; // *** Once the above line is properly tested, delete this line.
|
||||
else if (ValidPTE && ~LeafPTE) begin
|
||||
NextWalkerState = LEVEL0_WDV;
|
||||
TranslationPAdr = {CurrentPPN, VPN0, 2'b00};
|
||||
TranslationPAdr = {2'b00, TranslationVAdr[31:0]};
|
||||
end
|
||||
// else if (ValidPTE && LeafPTE) NextWalkerState = LEAF; // *** Once the above line is properly tested, delete this line.
|
||||
else if (ValidPTE && ~LeafPTE) begin
|
||||
NextWalkerState = LEVEL0_SET_ADRE;
|
||||
TranslationPAdr = {CurrentPPN, VPN0, 2'b00};
|
||||
HPTWReadE = 1'b1;
|
||||
end else begin
|
||||
NextWalkerState = FAULT;
|
||||
end
|
||||
end
|
||||
|
||||
LEVEL0_WDV: begin
|
||||
TranslationPAdr = {CurrentPPN, VPN0, 2'b00};
|
||||
HPTWReadE = 1'b1;
|
||||
if (HPTWStall) begin
|
||||
end else begin
|
||||
NextWalkerState = FAULT;
|
||||
end
|
||||
end
|
||||
|
||||
LEVEL0_SET_ADRE: begin
|
||||
NextWalkerState = LEVEL0_WDV;
|
||||
TranslationPAdr = {CurrentPPN, VPN0, 2'b00};
|
||||
end
|
||||
|
||||
LEVEL0_WDV: begin
|
||||
TranslationPAdr = {CurrentPPN, VPN0, 2'b00};
|
||||
HPTWReadE = 1'b1;
|
||||
if (HPTWStall) begin
|
||||
NextWalkerState = LEVEL0_WDV;
|
||||
end else begin
|
||||
end else begin
|
||||
NextWalkerState = LEVEL0;
|
||||
PRegEn = 1'b1;
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
LEVEL0: begin
|
||||
if (ValidPTE & LeafPTE & ~AccessAlert) begin
|
||||
NextWalkerState = LEAF;
|
||||
PageTableEntry = CurrentPTE;
|
||||
PageType = (WalkerState == LEVEL1) ? 2'b01 : 2'b00;
|
||||
DTLBWriteM_d = DTLBMissMQ;
|
||||
ITLBWriteF = ~DTLBMissMQ; // Prefer data over instructions
|
||||
TranslationPAdr = {2'b00, TranslationVAdr[31:0]};
|
||||
end else begin
|
||||
NextWalkerState = FAULT;
|
||||
end
|
||||
end
|
||||
|
||||
LEAF: begin
|
||||
NextWalkerState = IDLE;
|
||||
end
|
||||
LEVEL0: begin
|
||||
if (ValidPTE & LeafPTE & ~AccessAlert) begin
|
||||
NextWalkerState = LEAF;
|
||||
TranslationPAdr = {2'b00, TranslationVAdr[31:0]};
|
||||
end else begin
|
||||
NextWalkerState = FAULT;
|
||||
end
|
||||
end
|
||||
|
||||
FAULT: begin
|
||||
NextWalkerState = IDLE;
|
||||
WalkerInstrPageFaultF = ~DTLBMissMQ;
|
||||
WalkerLoadPageFaultM = DTLBMissMQ && ~MemStore;
|
||||
WalkerStorePageFaultM = DTLBMissMQ && MemStore;
|
||||
end
|
||||
|
||||
// Default case should never happen, but is included for linter.
|
||||
default: NextWalkerState = IDLE;
|
||||
endcase
|
||||
end
|
||||
LEAF: begin
|
||||
NextWalkerState = IDLE;
|
||||
PageTableEntry = CurrentPTE;
|
||||
PageType = (PreviousWalkerState == LEVEL1) ? 2'b01 : 2'b00; // *** not sure about this mux?
|
||||
DTLBWriteM = DTLBMissMQ;
|
||||
ITLBWriteF = ~DTLBMissMQ; // Prefer data over instructions
|
||||
TranslationPAdr = {2'b00, TranslationVAdr[31:0]};
|
||||
end
|
||||
|
||||
// A megapage is a Level 1 leaf page. This page must have zero PPN[0].
|
||||
assign MegapageMisaligned = |(CurrentPPN[9:0]);
|
||||
assign BadMegapage = MegapageMisaligned || AccessAlert; // *** Implement better access/dirty scheme
|
||||
FAULT: begin
|
||||
NextWalkerState = IDLE;
|
||||
WalkerInstrPageFaultF = ~DTLBMissMQ;
|
||||
WalkerLoadPageFaultM = DTLBMissMQ && ~MemStore;
|
||||
WalkerStorePageFaultM = DTLBMissMQ && MemStore;
|
||||
end
|
||||
|
||||
assign VPN1 = TranslationVAdr[31:22];
|
||||
assign VPN0 = TranslationVAdr[21:12];
|
||||
// Default case should never happen, but is included for linter.
|
||||
default: NextWalkerState = IDLE;
|
||||
endcase
|
||||
end
|
||||
|
||||
|
||||
// A megapage is a Level 1 leaf page. This page must have zero PPN[0].
|
||||
assign MegapageMisaligned = |(CurrentPPN[9:0]);
|
||||
assign BadMegapage = MegapageMisaligned || AccessAlert; // *** Implement better access/dirty scheme
|
||||
|
||||
// Capture page table entry from data cache
|
||||
// *** may need to delay reading this value until the next clock cycle.
|
||||
// The clk to q latency of the SRAM in the data cache will be long.
|
||||
// I cannot see directly using this value. This is no different than
|
||||
// a load delay hazard. This will require rewriting the walker fsm.
|
||||
// also need a new signal to save. Should be a mealy output of the fsm
|
||||
// request followed by ~stall.
|
||||
flopenr #(32) ptereg(clk, reset, PRegEn, HPTWReadPTE, SavedPTE);
|
||||
//mux2 #(32) ptemux(SavedPTE, HPTWReadPTE, PRegEn, CurrentPTE);
|
||||
assign CurrentPTE = SavedPTE;
|
||||
assign CurrentPPN = CurrentPTE[`PPN_BITS+9:10];
|
||||
assign VPN1 = TranslationVAdr[31:22];
|
||||
assign VPN0 = TranslationVAdr[21:12];
|
||||
|
||||
// Assign outputs to ahblite
|
||||
// *** Currently truncate address to 32 bits. This must be changed if
|
||||
// we support larger physical address spaces
|
||||
assign HPTWPAdrE = TranslationPAdr[31:0];
|
||||
|
||||
|
||||
// Capture page table entry from data cache
|
||||
// *** may need to delay reading this value until the next clock cycle.
|
||||
// The clk to q latency of the SRAM in the data cache will be long.
|
||||
// I cannot see directly using this value. This is no different than
|
||||
// a load delay hazard. This will require rewriting the walker fsm.
|
||||
// also need a new signal to save. Should be a mealy output of the fsm
|
||||
// request followed by ~stall.
|
||||
flopenr #(32) ptereg(clk, reset, PRegEn, HPTWReadPTE, SavedPTE);
|
||||
//mux2 #(32) ptemux(SavedPTE, HPTWReadPTE, PRegEn, CurrentPTE);
|
||||
assign CurrentPTE = SavedPTE;
|
||||
assign CurrentPPN = CurrentPTE[`PPN_BITS+9:10];
|
||||
|
||||
// Assign outputs to ahblite
|
||||
// *** Currently truncate address to 32 bits. This must be changed if
|
||||
// we support larger physical address spaces
|
||||
assign HPTWPAdrE = TranslationPAdr[31:0];
|
||||
|
||||
end else begin
|
||||
|
||||
logic [8:0] VPN3, VPN2, VPN1, VPN0;
|
||||
|
||||
logic TerapageMisaligned, GigapageMisaligned, BadTerapage, BadGigapage;
|
||||
logic [8:0] VPN3, VPN2, VPN1, VPN0;
|
||||
|
||||
flopenl #(.TYPE(statetype)) mmureg(clk, reset, 1'b1, NextWalkerState, IDLE, WalkerState);
|
||||
logic TerapageMisaligned, GigapageMisaligned, BadTerapage, BadGigapage;
|
||||
|
||||
/* -----\/----- EXCLUDED -----\/-----
|
||||
assign PRegEn = (WalkerState == LEVEL1_WDV || WalkerState == LEVEL0_WDV ||
|
||||
WalkerState == LEVEL2_WDV || WalkerState == LEVEL3_WDV) && ~HPTWStall;
|
||||
-----/\----- EXCLUDED -----/\----- */
|
||||
flopenl #(.TYPE(statetype)) mmureg(clk, reset, 1'b1, NextWalkerState, IDLE, WalkerState);
|
||||
|
||||
//assign HPTWRead = (WalkerState == IDLE && HPTWTranslate) || WalkerState == LEVEL3 ||
|
||||
// WalkerState == LEVEL2 || WalkerState == LEVEL1;
|
||||
|
||||
/* -----\/----- EXCLUDED -----\/-----
|
||||
assign PRegEn = (WalkerState == LEVEL1_WDV || WalkerState == LEVEL0_WDV ||
|
||||
WalkerState == LEVEL2_WDV || WalkerState == LEVEL3_WDV) && ~HPTWStall;
|
||||
-----/\----- EXCLUDED -----/\----- */
|
||||
|
||||
always_comb begin
|
||||
//assign HPTWRead = (WalkerState == IDLE && HPTWTranslate) || WalkerState == LEVEL3 ||
|
||||
// WalkerState == LEVEL2 || WalkerState == LEVEL1;
|
||||
|
||||
|
||||
always_comb begin
|
||||
PRegEn = 1'b0;
|
||||
TranslationPAdr = '0;
|
||||
HPTWReadE = 1'b0;
|
||||
PageTableEntry = '0;
|
||||
PageType = '0;
|
||||
DTLBWriteM_d = '0;
|
||||
ITLBWriteF = '0;
|
||||
|
||||
WalkerInstrPageFaultF = 1'b0;
|
||||
WalkerLoadPageFaultM = 1'b0;
|
||||
WalkerStorePageFaultM = 1'b0;
|
||||
PageTableEntry = '0;
|
||||
PageType = '0;
|
||||
DTLBWriteM = '0;
|
||||
ITLBWriteF = '0;
|
||||
|
||||
case (WalkerState)
|
||||
IDLE: begin
|
||||
if (HPTWTranslate && (SvMode == `SV48 || SvMode == `SV39)) begin
|
||||
NextWalkerState = START;
|
||||
end else begin
|
||||
NextWalkerState = IDLE;
|
||||
end
|
||||
end
|
||||
WalkerInstrPageFaultF = 1'b0;
|
||||
WalkerLoadPageFaultM = 1'b0;
|
||||
WalkerStorePageFaultM = 1'b0;
|
||||
|
||||
START: begin
|
||||
if (HPTWTranslate && SvMode == `SV48) begin
|
||||
SelPTW = 1'b1;
|
||||
|
||||
case (WalkerState)
|
||||
IDLE: begin
|
||||
SelPTW = 1'b0;
|
||||
if (AnyTLBMissM & SvMode == `SV48) begin
|
||||
NextWalkerState = LEVEL3_SET_ADRE;
|
||||
end else if (AnyTLBMissM & SvMode == `SV39) begin
|
||||
NextWalkerState = LEVEL2_SET_ADRE;
|
||||
end else begin
|
||||
NextWalkerState = IDLE;
|
||||
end
|
||||
end
|
||||
|
||||
LEVEL3_SET_ADRE: begin
|
||||
NextWalkerState = LEVEL3_WDV;
|
||||
TranslationPAdr = {BasePageTablePPN, VPN3, 3'b000};
|
||||
end
|
||||
|
||||
LEVEL3_WDV: begin
|
||||
TranslationPAdr = {BasePageTablePPN, VPN3, 3'b000};
|
||||
HPTWReadE = 1'b1;
|
||||
if (HPTWStall) begin
|
||||
NextWalkerState = LEVEL3_WDV;
|
||||
TranslationPAdr = {BasePageTablePPN, VPN3, 3'b000};
|
||||
HPTWReadE = 1'b1;
|
||||
end else if (HPTWTranslate && SvMode == `SV39) begin
|
||||
NextWalkerState = LEVEL2_WDV;
|
||||
TranslationPAdr = {BasePageTablePPN, VPN2, 3'b000};
|
||||
HPTWReadE = 1'b1;
|
||||
end else begin // *** should not get here
|
||||
NextWalkerState = IDLE;
|
||||
TranslationPAdr = '0;
|
||||
end
|
||||
end
|
||||
|
||||
LEVEL3_WDV: begin
|
||||
TranslationPAdr = {BasePageTablePPN, VPN3, 3'b000};
|
||||
HPTWReadE = 1'b1;
|
||||
if (HPTWStall) begin
|
||||
NextWalkerState = LEVEL3_WDV;
|
||||
end else begin
|
||||
end else begin
|
||||
NextWalkerState = LEVEL3;
|
||||
PRegEn = 1'b1;
|
||||
end
|
||||
end
|
||||
|
||||
LEVEL3: begin
|
||||
// *** <FUTURE WORK> According to the architecture, we should
|
||||
// fault upon finding a superpage that is misaligned or has 0
|
||||
// access bit. The following commented line of code is
|
||||
// supposed to perform that check. However, it is untested.
|
||||
if (ValidPTE && LeafPTE && ~BadTerapage) begin
|
||||
NextWalkerState = LEAF;
|
||||
PageTableEntry = CurrentPTE;
|
||||
PageType = (WalkerState == LEVEL3) ? 2'b11 : // *** not sure about this mux?
|
||||
((WalkerState == LEVEL2) ? 2'b10 :
|
||||
((WalkerState == LEVEL1) ? 2'b01 : 2'b00));
|
||||
DTLBWriteM_d = DTLBMissMQ;
|
||||
ITLBWriteF = ~DTLBMissMQ; // Prefer data over instructions
|
||||
TranslationPAdr = TranslationVAdr[`PA_BITS-1:0];
|
||||
end
|
||||
// else if (ValidPTE && LeafPTE) NextWalkerState = LEAF; // *** Once the above line is properly tested, delete this line.
|
||||
else if (ValidPTE && ~LeafPTE) begin
|
||||
NextWalkerState = LEVEL2_WDV;
|
||||
TranslationPAdr = {(SvMode == `SV48) ? CurrentPPN : BasePageTablePPN, VPN2, 3'b000};
|
||||
HPTWReadE = 1'b1;
|
||||
end else begin
|
||||
NextWalkerState = FAULT;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
LEVEL3: begin
|
||||
// *** <FUTURE WORK> According to the architecture, we should
|
||||
// fault upon finding a superpage that is misaligned or has 0
|
||||
// access bit. The following commented line of code is
|
||||
// supposed to perform that check. However, it is untested.
|
||||
if (ValidPTE && LeafPTE && ~BadTerapage) begin
|
||||
NextWalkerState = LEAF;
|
||||
TranslationPAdr = TranslationVAdr[`PA_BITS-1:0];
|
||||
end
|
||||
// else if (ValidPTE && LeafPTE) NextWalkerState = LEAF; // *** Once the above line is properly tested, delete this line.
|
||||
else if (ValidPTE && ~LeafPTE) begin
|
||||
NextWalkerState = LEVEL2_SET_ADRE;
|
||||
TranslationPAdr = {(SvMode == `SV48) ? CurrentPPN : BasePageTablePPN, VPN2, 3'b000};
|
||||
end else begin
|
||||
NextWalkerState = FAULT;
|
||||
end
|
||||
end
|
||||
|
||||
LEVEL2_WDV: begin
|
||||
TranslationPAdr = {(SvMode == `SV48) ? CurrentPPN : BasePageTablePPN, VPN2, 3'b000};
|
||||
HPTWReadE = 1'b1;
|
||||
if (HPTWStall) begin
|
||||
NextWalkerState = LEVEL2_WDV;
|
||||
end else begin
|
||||
NextWalkerState = LEVEL2;
|
||||
PRegEn = 1'b1;
|
||||
end
|
||||
end
|
||||
|
||||
LEVEL2: begin
|
||||
// *** <FUTURE WORK> According to the architecture, we should
|
||||
// fault upon finding a superpage that is misaligned or has 0
|
||||
// access bit. The following commented line of code is
|
||||
// supposed to perform that check. However, it is untested.
|
||||
if (ValidPTE && LeafPTE && ~BadGigapage) begin
|
||||
NextWalkerState = LEAF;
|
||||
PageTableEntry = CurrentPTE;
|
||||
PageType = (WalkerState == LEVEL3) ? 2'b11 :
|
||||
((WalkerState == LEVEL2) ? 2'b10 :
|
||||
((WalkerState == LEVEL1) ? 2'b01 : 2'b00));
|
||||
DTLBWriteM_d = DTLBMissMQ;
|
||||
ITLBWriteF = ~DTLBMissMQ; // Prefer data over instructions
|
||||
TranslationPAdr = TranslationVAdr[`PA_BITS-1:0];
|
||||
end
|
||||
// else if (ValidPTE && LeafPTE) NextWalkerState = LEAF; // *** Once the above line is properly tested, delete this line.
|
||||
else if (ValidPTE && ~LeafPTE) begin
|
||||
NextWalkerState = LEVEL1_WDV;
|
||||
TranslationPAdr = {CurrentPPN, VPN1, 3'b000};
|
||||
HPTWReadE = 1'b1;
|
||||
end else begin
|
||||
NextWalkerState = FAULT;
|
||||
end
|
||||
LEVEL2_SET_ADRE: begin
|
||||
NextWalkerState = LEVEL2_WDV;
|
||||
TranslationPAdr = {(SvMode == `SV48) ? CurrentPPN : BasePageTablePPN, VPN2, 3'b000};
|
||||
end
|
||||
|
||||
end
|
||||
LEVEL2_WDV: begin
|
||||
TranslationPAdr = {(SvMode == `SV48) ? CurrentPPN : BasePageTablePPN, VPN2, 3'b000};
|
||||
HPTWReadE = 1'b1;
|
||||
if (HPTWStall) begin
|
||||
NextWalkerState = LEVEL2_WDV;
|
||||
end else begin
|
||||
NextWalkerState = LEVEL2;
|
||||
PRegEn = 1'b1;
|
||||
end
|
||||
end
|
||||
|
||||
LEVEL1_WDV: begin
|
||||
TranslationPAdr = {CurrentPPN, VPN1, 3'b000};
|
||||
HPTWReadE = 1'b1;
|
||||
if (HPTWStall) begin
|
||||
NextWalkerState = LEVEL1_WDV;
|
||||
end else begin
|
||||
NextWalkerState = LEVEL1;
|
||||
PRegEn = 1'b1;
|
||||
end
|
||||
end
|
||||
LEVEL2: begin
|
||||
// *** <FUTURE WORK> According to the architecture, we should
|
||||
// fault upon finding a superpage that is misaligned or has 0
|
||||
// access bit. The following commented line of code is
|
||||
// supposed to perform that check. However, it is untested.
|
||||
if (ValidPTE && LeafPTE && ~BadGigapage) begin
|
||||
NextWalkerState = LEAF;
|
||||
TranslationPAdr = TranslationVAdr[`PA_BITS-1:0];
|
||||
end
|
||||
// else if (ValidPTE && LeafPTE) NextWalkerState = LEAF; // *** Once the above line is properly tested, delete this line.
|
||||
else if (ValidPTE && ~LeafPTE) begin
|
||||
NextWalkerState = LEVEL1_SET_ADRE;
|
||||
TranslationPAdr = {CurrentPPN, VPN1, 3'b000};
|
||||
end else begin
|
||||
NextWalkerState = FAULT;
|
||||
end
|
||||
end
|
||||
|
||||
LEVEL1: begin
|
||||
// *** <FUTURE WORK> According to the architecture, we should
|
||||
// fault upon finding a superpage that is misaligned or has 0
|
||||
// access bit. The following commented line of code is
|
||||
// supposed to perform that check. However, it is untested.
|
||||
if (ValidPTE && LeafPTE && ~BadMegapage) begin
|
||||
NextWalkerState = LEAF;
|
||||
PageTableEntry = CurrentPTE;
|
||||
PageType = (WalkerState == LEVEL3) ? 2'b11 :
|
||||
((WalkerState == LEVEL2) ? 2'b10 :
|
||||
((WalkerState == LEVEL1) ? 2'b01 : 2'b00));
|
||||
DTLBWriteM_d = DTLBMissMQ;
|
||||
ITLBWriteF = ~DTLBMissMQ; // Prefer data over instructions
|
||||
TranslationPAdr = TranslationVAdr[`PA_BITS-1:0];
|
||||
|
||||
end
|
||||
// else if (ValidPTE && LeafPTE) NextWalkerState = LEAF; // *** Once the above line is properly tested, delete this line.
|
||||
else if (ValidPTE && ~LeafPTE) begin
|
||||
NextWalkerState = LEVEL0_WDV;
|
||||
TranslationPAdr = {CurrentPPN, VPN0, 3'b000};
|
||||
HPTWReadE = 1'b1;
|
||||
end else begin
|
||||
NextWalkerState = FAULT;
|
||||
end
|
||||
end
|
||||
LEVEL1_SET_ADRE: begin
|
||||
NextWalkerState = LEVEL1_WDV;
|
||||
TranslationPAdr = {CurrentPPN, VPN1, 3'b000};
|
||||
end
|
||||
|
||||
LEVEL0_WDV: begin
|
||||
TranslationPAdr = {CurrentPPN, VPN0, 3'b000};
|
||||
HPTWReadE = 1'b1;
|
||||
if (HPTWStall) begin
|
||||
NextWalkerState = LEVEL0_WDV;
|
||||
end else begin
|
||||
NextWalkerState = LEVEL0;
|
||||
PRegEn = 1'b1;
|
||||
end
|
||||
end
|
||||
LEVEL1_WDV: begin
|
||||
TranslationPAdr = {CurrentPPN, VPN1, 3'b000};
|
||||
HPTWReadE = 1'b1;
|
||||
if (HPTWStall) begin
|
||||
NextWalkerState = LEVEL1_WDV;
|
||||
end else begin
|
||||
NextWalkerState = LEVEL1;
|
||||
PRegEn = 1'b1;
|
||||
end
|
||||
end
|
||||
|
||||
LEVEL0: begin
|
||||
if (ValidPTE && LeafPTE && ~AccessAlert) begin
|
||||
NextWalkerState = LEAF;
|
||||
PageTableEntry = CurrentPTE;
|
||||
PageType = (WalkerState == LEVEL3) ? 2'b11 :
|
||||
((WalkerState == LEVEL2) ? 2'b10 :
|
||||
((WalkerState == LEVEL1) ? 2'b01 : 2'b00));
|
||||
DTLBWriteM_d = DTLBMissMQ;
|
||||
ITLBWriteF = ~DTLBMissMQ; // Prefer data over instructions
|
||||
TranslationPAdr = TranslationVAdr[`PA_BITS-1:0];
|
||||
end else begin
|
||||
NextWalkerState = FAULT;
|
||||
end
|
||||
end
|
||||
|
||||
LEAF: begin
|
||||
NextWalkerState = IDLE;
|
||||
end
|
||||
LEVEL1: begin
|
||||
// *** <FUTURE WORK> According to the architecture, we should
|
||||
// fault upon finding a superpage that is misaligned or has 0
|
||||
// access bit. The following commented line of code is
|
||||
// supposed to perform that check. However, it is untested.
|
||||
if (ValidPTE && LeafPTE && ~BadMegapage) begin
|
||||
NextWalkerState = LEAF;
|
||||
TranslationPAdr = TranslationVAdr[`PA_BITS-1:0];
|
||||
|
||||
FAULT: begin
|
||||
NextWalkerState = IDLE;
|
||||
WalkerInstrPageFaultF = ~DTLBMissMQ;
|
||||
WalkerLoadPageFaultM = DTLBMissMQ && ~MemStore;
|
||||
WalkerStorePageFaultM = DTLBMissMQ && MemStore;
|
||||
end
|
||||
end
|
||||
// else if (ValidPTE && LeafPTE) NextWalkerState = LEAF; // *** Once the above line is properly tested, delete this line.
|
||||
else if (ValidPTE && ~LeafPTE) begin
|
||||
NextWalkerState = LEVEL0_SET_ADRE;
|
||||
TranslationPAdr = {CurrentPPN, VPN0, 3'b000};
|
||||
end else begin
|
||||
NextWalkerState = FAULT;
|
||||
end
|
||||
end
|
||||
|
||||
// Default case should never happen
|
||||
default: begin
|
||||
NextWalkerState = IDLE;
|
||||
end
|
||||
LEVEL0_SET_ADRE: begin
|
||||
NextWalkerState = LEVEL0_WDV;
|
||||
TranslationPAdr = {CurrentPPN, VPN0, 3'b000};
|
||||
end
|
||||
|
||||
endcase
|
||||
end
|
||||
LEVEL0_WDV: begin
|
||||
TranslationPAdr = {CurrentPPN, VPN0, 3'b000};
|
||||
HPTWReadE = 1'b1;
|
||||
if (HPTWStall) begin
|
||||
NextWalkerState = LEVEL0_WDV;
|
||||
end else begin
|
||||
NextWalkerState = LEVEL0;
|
||||
PRegEn = 1'b1;
|
||||
end
|
||||
end
|
||||
|
||||
// A terapage is a level 3 leaf page. This page must have zero PPN[2],
|
||||
// zero PPN[1], and zero PPN[0]
|
||||
assign TerapageMisaligned = |(CurrentPPN[26:0]);
|
||||
// A gigapage is a Level 2 leaf page. This page must have zero PPN[1] and
|
||||
// zero PPN[0]
|
||||
assign GigapageMisaligned = |(CurrentPPN[17:0]);
|
||||
// A megapage is a Level 1 leaf page. This page must have zero PPN[0].
|
||||
assign MegapageMisaligned = |(CurrentPPN[8:0]);
|
||||
LEVEL0: begin
|
||||
if (ValidPTE && LeafPTE && ~AccessAlert) begin
|
||||
NextWalkerState = LEAF;
|
||||
TranslationPAdr = TranslationVAdr[`PA_BITS-1:0];
|
||||
end else begin
|
||||
NextWalkerState = FAULT;
|
||||
end
|
||||
end
|
||||
|
||||
assign BadTerapage = TerapageMisaligned || AccessAlert; // *** Implement better access/dirty scheme
|
||||
assign BadGigapage = GigapageMisaligned || AccessAlert; // *** Implement better access/dirty scheme
|
||||
assign BadMegapage = MegapageMisaligned || AccessAlert; // *** Implement better access/dirty scheme
|
||||
LEAF: begin
|
||||
PageTableEntry = CurrentPTE;
|
||||
PageType = (PreviousWalkerState == LEVEL3) ? 2'b11 : // *** not sure about this mux?
|
||||
((PreviousWalkerState == LEVEL2) ? 2'b10 :
|
||||
((PreviousWalkerState == LEVEL1) ? 2'b01 : 2'b00));
|
||||
DTLBWriteM = DTLBMissMQ;
|
||||
ITLBWriteF = ~DTLBMissMQ; // Prefer data over instructions
|
||||
TranslationPAdr = TranslationVAdr[`PA_BITS-1:0];
|
||||
NextWalkerState = IDLE;
|
||||
end
|
||||
|
||||
assign VPN3 = TranslationVAdr[47:39];
|
||||
assign VPN2 = TranslationVAdr[38:30];
|
||||
assign VPN1 = TranslationVAdr[29:21];
|
||||
assign VPN0 = TranslationVAdr[20:12];
|
||||
FAULT: begin
|
||||
NextWalkerState = IDLE;
|
||||
WalkerInstrPageFaultF = ~DTLBMissMQ;
|
||||
WalkerLoadPageFaultM = DTLBMissMQ && ~MemStore;
|
||||
WalkerStorePageFaultM = DTLBMissMQ && MemStore;
|
||||
end
|
||||
|
||||
// Default case should never happen
|
||||
default: begin
|
||||
NextWalkerState = IDLE;
|
||||
end
|
||||
|
||||
endcase
|
||||
end
|
||||
|
||||
// A terapage is a level 3 leaf page. This page must have zero PPN[2],
|
||||
// zero PPN[1], and zero PPN[0]
|
||||
assign TerapageMisaligned = |(CurrentPPN[26:0]);
|
||||
// A gigapage is a Level 2 leaf page. This page must have zero PPN[1] and
|
||||
// zero PPN[0]
|
||||
assign GigapageMisaligned = |(CurrentPPN[17:0]);
|
||||
// A megapage is a Level 1 leaf page. This page must have zero PPN[0].
|
||||
assign MegapageMisaligned = |(CurrentPPN[8:0]);
|
||||
|
||||
assign BadTerapage = TerapageMisaligned || AccessAlert; // *** Implement better access/dirty scheme
|
||||
assign BadGigapage = GigapageMisaligned || AccessAlert; // *** Implement better access/dirty scheme
|
||||
assign BadMegapage = MegapageMisaligned || AccessAlert; // *** Implement better access/dirty scheme
|
||||
|
||||
assign VPN3 = TranslationVAdr[47:39];
|
||||
assign VPN2 = TranslationVAdr[38:30];
|
||||
assign VPN1 = TranslationVAdr[29:21];
|
||||
assign VPN0 = TranslationVAdr[20:12];
|
||||
|
||||
|
||||
// Capture page table entry from ahblite
|
||||
flopenr #(`XLEN) ptereg(clk, reset, PRegEn, HPTWReadPTE, SavedPTE);
|
||||
//mux2 #(`XLEN) ptemux(SavedPTE, HPTWReadPTE, PRegEn, CurrentPTE);
|
||||
assign CurrentPTE = SavedPTE;
|
||||
assign CurrentPPN = CurrentPTE[`PPN_BITS+9:10];
|
||||
// Capture page table entry from ahblite
|
||||
flopenr #(`XLEN) ptereg(clk, reset, PRegEn, HPTWReadPTE, SavedPTE);
|
||||
//mux2 #(`XLEN) ptemux(SavedPTE, HPTWReadPTE, PRegEn, CurrentPTE);
|
||||
assign CurrentPTE = SavedPTE;
|
||||
assign CurrentPPN = CurrentPTE[`PPN_BITS+9:10];
|
||||
|
||||
// Assign outputs to ahblite
|
||||
// *** Currently truncate address to 32 bits. This must be changed if
|
||||
// we support larger physical address spaces
|
||||
assign HPTWPAdrE = {{(`XLEN-`PA_BITS){1'b0}}, TranslationPAdr[`PA_BITS-1:0]};
|
||||
// *** Major issue. We need the full virtual address here.
|
||||
// When the TLB's are update it use use the orignal address
|
||||
// *** Currently truncate address to 32 bits. This must be changed if
|
||||
// we support larger physical address spaces
|
||||
assign HPTWPAdrE = {{(`XLEN-`PA_BITS){1'b0}}, TranslationPAdr[`PA_BITS-1:0]};
|
||||
end
|
||||
//endgenerate
|
||||
end else begin
|
||||
assign HPTWPAdrE = 0;
|
||||
assign HPTWTranslate = 0;
|
||||
assign HPTWReadE = 0;
|
||||
assign WalkerInstrPageFaultF = 0;
|
||||
assign WalkerLoadPageFaultM = 0;
|
||||
assign WalkerStorePageFaultM = 0;
|
||||
assign SelPTW = 0;
|
||||
end
|
||||
endgenerate
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user