Complete basic page table walker

This commit is contained in:
Thomas Fleming 2021-03-30 22:19:27 -04:00
parent 0994d03b28
commit 7126ab7864
10 changed files with 208 additions and 181 deletions

View File

@ -27,7 +27,7 @@
// RV32 or RV64: XLEN = 32 or 64 // RV32 or RV64: XLEN = 32 or 64
`define XLEN 32 `define XLEN 32
`define MISA (32'h00000104 | 1 << 12) `define MISA (32'h00000104 | 1 << 20 | 1 << 18 | 1 << 12)
`define A_SUPPORTED ((`MISA >> 0) % 2 == 1) `define A_SUPPORTED ((`MISA >> 0) % 2 == 1)
`define C_SUPPORTED ((`MISA >> 2) % 2 == 1) `define C_SUPPORTED ((`MISA >> 2) % 2 == 1)
`define D_SUPPORTED ((`MISA >> 3) % 2 == 1) `define D_SUPPORTED ((`MISA >> 3) % 2 == 1)
@ -53,7 +53,7 @@
`define MEM_DCACHE 0 `define MEM_DCACHE 0
`define MEM_DTIM 1 `define MEM_DTIM 1
`define MEM_ICACHE 0 `define MEM_ICACHE 0
`define MEM_VIRTMEM 0 `define MEM_VIRTMEM 1
// Address space // Address space
`define RESET_VECTOR 32'h80000000 `define RESET_VECTOR 32'h80000000

View File

@ -54,7 +54,7 @@
`define MEM_DCACHE 0 `define MEM_DCACHE 0
`define MEM_DTIM 1 `define MEM_DTIM 1
`define MEM_ICACHE 0 `define MEM_ICACHE 0
`define MEM_VIRTMEM 0 `define MEM_VIRTMEM 1
// Address space // Address space
`define RESET_VECTOR 64'h0000000080000000 `define RESET_VECTOR 64'h0000000080000000

View File

@ -54,7 +54,7 @@
`define MEM_DCACHE 0 `define MEM_DCACHE 0
`define MEM_DTIM 1 `define MEM_DTIM 1
`define MEM_ICACHE 0 `define MEM_ICACHE 0
`define MEM_VIRTMEM 0 `define MEM_VIRTMEM 1
// Address space // Address space
`define RESET_VECTOR 64'h0000000080000000 `define RESET_VECTOR 64'h0000000080000000

View File

@ -57,13 +57,14 @@ module dmem (
output logic DTLBMissM, DTLBHitM output logic DTLBMissM, DTLBHitM
); );
logic MemAccessM; // Whether memory needs to be accessed
logic SquashSCM; logic SquashSCM;
// *** temporary hack until walker is hooked up -- Thomas F // *** temporary hack until walker is hooked up -- Thomas F
// logic [`XLEN-1:0] PageTableEntryM = '0; // logic [`XLEN-1:0] PageTableEntryM = '0;
logic DTLBFlushM = '0; logic DTLBFlushM = '0;
// logic DTLBWriteM = '0; // logic DTLBWriteM = '0;
tlb #(3) dtlb(clk, reset, SATP_REGW, PrivilegeModeW, MemAdrM, PageTableEntryM, DTLBWriteM, tlb #(3) dtlb(clk, reset, SATP_REGW, PrivilegeModeW, MemAccessM, MemAdrM, PageTableEntryM, DTLBWriteM,
DTLBFlushM, MemPAdrM, DTLBMissM, DTLBHitM); DTLBFlushM, MemPAdrM, DTLBMissM, DTLBHitM);
// Determine if an Unaligned access is taking place // Determine if an Unaligned access is taking place
@ -79,10 +80,11 @@ module dmem (
// *** this is also the place to squash if the cache is hit // *** this is also the place to squash if the cache is hit
assign MemReadM = MemRWM[1] & ~DataMisalignedM; assign MemReadM = MemRWM[1] & ~DataMisalignedM;
assign MemWriteM = MemRWM[0] & ~DataMisalignedM && ~SquashSCM; assign MemWriteM = MemRWM[0] & ~DataMisalignedM && ~SquashSCM;
assign MemAccessM = |MemRWM;
// Determine if address is valid // Determine if address is valid
assign LoadMisalignedFaultM = DataMisalignedM & MemRWM[1]; assign LoadMisalignedFaultM = DataMisalignedM & MemRWM[1];
assign LoadAccessFaultM = DataAccessFaultM & MemRWM[0]; assign LoadAccessFaultM = DataAccessFaultM & MemRWM[1];
assign StoreMisalignedFaultM = DataMisalignedM & MemRWM[0]; assign StoreMisalignedFaultM = DataMisalignedM & MemRWM[0];
assign StoreAccessFaultM = DataAccessFaultM & MemRWM[0]; assign StoreAccessFaultM = DataAccessFaultM & MemRWM[0];
@ -97,7 +99,7 @@ module dmem (
assign scM = MemRWM[0] && AtomicM[0]; assign scM = MemRWM[0] && AtomicM[0];
assign WriteAdrMatchM = MemRWM[0] && (MemPAdrM[`XLEN-1:2] == ReservationPAdrW) && ReservationValidW; assign WriteAdrMatchM = MemRWM[0] && (MemPAdrM[`XLEN-1:2] == ReservationPAdrW) && ReservationValidW;
assign SquashSCM = scM && ~WriteAdrMatchM; assign SquashSCM = scM && ~WriteAdrMatchM;
always_comb begin // ReservationValidM (next valiue of valid reservation) always_comb begin // ReservationValidM (next value of valid reservation)
if (lrM) ReservationValidM = 1; // set valid on load reserve if (lrM) ReservationValidM = 1; // set valid on load reserve
else if (scM || WriteAdrMatchM) ReservationValidM = 0; // clear valid on store to same address or any sc else if (scM || WriteAdrMatchM) ReservationValidM = 0; // clear valid on store to same address or any sc
else ReservationValidM = ReservationValidW; // otherwise don't change valid else ReservationValidM = ReservationValidW; // otherwise don't change valid

View File

@ -49,6 +49,7 @@ module ahblite (
// Signals from MMU // Signals from MMU
input logic [`XLEN-1:0] MMUPAdr, input logic [`XLEN-1:0] MMUPAdr,
input logic MMUTranslate, MMUTranslationComplete, input logic MMUTranslate, MMUTranslationComplete,
input logic TrapM,
output logic [`XLEN-1:0] MMUReadPTE, output logic [`XLEN-1:0] MMUReadPTE,
output logic MMUReady, output logic MMUReady,
// Return from bus // Return from bus
@ -104,16 +105,16 @@ module ahblite (
else if (InstrReadF) NextBusState = INSTRREAD; else if (InstrReadF) NextBusState = INSTRREAD;
else NextBusState = IDLE; else NextBusState = IDLE;
MMUTRANSLATE: if (~HREADY) NextBusState = MMUTRANSLATE; MMUTRANSLATE: if (~HREADY) NextBusState = MMUTRANSLATE;
else NextBusState = MMUIDLE; else NextBusState = IDLE;
// *** Could the MMUIDLE state just be the normal idle state? // *** Could the MMUIDLE state just be the normal idle state?
// Do we trust MMUTranslate to be high exactly when we need translation? // Do we trust MMUTranslate to be high exactly when we need translation?
MMUIDLE: if (~MMUTranslationComplete) // MMUIDLE: if (MMUTranslate)
NextBusState = MMUTRANSLATE; // NextBusState = MMUTRANSLATE;
else if (AtomicM[1]) NextBusState = ATOMICREAD; // else if (AtomicM[1]) NextBusState = ATOMICREAD;
else if (MemReadM) NextBusState = MEMREAD; // Memory has priority over instructions // else if (MemReadM) NextBusState = MEMREAD; // Memory has priority over instructions
else if (MemWriteM) NextBusState = MEMWRITE; // else if (MemWriteM) NextBusState = MEMWRITE;
else if (InstrReadF) NextBusState = INSTRREAD; // else if (InstrReadF) NextBusState = INSTRREAD;
else NextBusState = IDLE; // else NextBusState = IDLE;
ATOMICREAD: if (~HREADY) NextBusState = ATOMICREAD; ATOMICREAD: if (~HREADY) NextBusState = ATOMICREAD;
else NextBusState = ATOMICWRITE; else NextBusState = ATOMICWRITE;
ATOMICWRITE: if (~HREADY) NextBusState = ATOMICWRITE; ATOMICWRITE: if (~HREADY) NextBusState = ATOMICWRITE;
@ -133,13 +134,15 @@ module ahblite (
endcase endcase
// stall signals // stall signals
assign #2 DataStall = (NextBusState == MEMREAD) || (NextBusState == MEMWRITE) || // Note that we need to extend both stalls when MMUTRANSLATE goes to idle,
// since translation might not be complete.
assign #2 DataStall = ~TrapM && ((NextBusState == MEMREAD) || (NextBusState == MEMWRITE) ||
(NextBusState == ATOMICREAD) || (NextBusState == ATOMICWRITE) || (NextBusState == ATOMICREAD) || (NextBusState == ATOMICWRITE) ||
(NextBusState == MMUTRANSLATE) || (NextBusState == MMUIDLE); (NextBusState == MMUTRANSLATE) || (BusState == MMUTRANSLATE));
// *** Could get finer grained stalling if we distinguish between MMU // *** Could get finer grained stalling if we distinguish between MMU
// instruction address translation and data address translation // instruction address translation and data address translation
assign #1 InstrStall = (NextBusState == INSTRREAD) || (NextBusState == INSTRREADC) || assign #1 InstrStall = ~TrapM && ((NextBusState == INSTRREAD) || (NextBusState == INSTRREADC) ||
(NextBusState == MMUTRANSLATE) || (NextBusState == MMUIDLE); (NextBusState == MMUTRANSLATE) || (BusState == MMUTRANSLATE));
// bus outputs // bus outputs
assign #1 GrantData = (NextBusState == MEMREAD) || (NextBusState == MEMWRITE) || assign #1 GrantData = (NextBusState == MEMREAD) || (NextBusState == MEMWRITE) ||
@ -168,7 +171,7 @@ module ahblite (
// Route signals to Instruction and Data Caches // Route signals to Instruction and Data Caches
// *** assumes AHBW = XLEN // *** assumes AHBW = XLEN
assign #1 MMUReady = (NextBusState == MMUIDLE); assign MMUReady = (BusState == MMUTRANSLATE && NextBusState == IDLE);
assign InstrRData = HRDATA; assign InstrRData = HRDATA;
assign MMUReadPTE = HRDATA; assign MMUReadPTE = HRDATA;

View File

@ -27,46 +27,71 @@
`include "wally-config.vh" `include "wally-config.vh"
`include "wally-constants.vh" `include "wally-constants.vh"
module pagetablewalker ( /* ***
input logic clk, reset, TO-DO:
- Faults have a timing issue and currently do not work.
- Leaf state brings HADDR down to zeros (maybe fixed?)
- Complete rv64ic case
- Implement better accessed/dirty behavior
- Implement read/write/execute checking (either here or in TLB)
*/
module pagetablewalker (
// Control signals
input logic HCLK, HRESETn,
input logic [`XLEN-1:0] SATP_REGW, input logic [`XLEN-1:0] SATP_REGW,
input logic MemWriteM, // Signals from TLBs (addresses to translate)
input logic ITLBMissF, DTLBMissM,
input logic [`XLEN-1:0] PCF, MemAdrM, 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] PageTableEntryF, PageTableEntryM, output logic [`XLEN-1:0] PageTableEntryF, PageTableEntryM,
output logic ITLBWriteF, DTLBWriteM, output logic ITLBWriteF, DTLBWriteM,
// *** handshake to tlbs probably not needed, since stalls take effect
output logic MMUTranslationComplete,
// Signals from and to ahblite // Signals from ahblite (PTEs from memory)
input logic [`XLEN-1:0] MMUReadPTE, input logic [`XLEN-1:0] MMUReadPTE,
input logic MMUReady, input logic MMUReady,
// Signals to ahblite (memory addresses to access)
output logic [`XLEN-1:0] MMUPAdr, output logic [`XLEN-1:0] MMUPAdr,
output logic MMUTranslate, output logic MMUTranslate,
output logic MMUTranslationComplete,
// Faults // Faults
output logic InstrPageFaultM, LoadPageFaultM, StorePageFaultM output logic InstrPageFaultM, LoadPageFaultM, StorePageFaultM
); );
logic SvMode; // Internal signals
logic SvMode, TLBMiss;
logic [`PPN_BITS-1:0] BasePageTablePPN; logic [`PPN_BITS-1:0] BasePageTablePPN;
logic [`XLEN-1:0] DirectInstrPTE, DirectMemPTE, TranslationVAdr; logic [`XLEN-1:0] TranslationVAdr;
logic [`XLEN-1:0] SavedPTE, CurrentPTE;
logic [`PA_BITS-1:0] TranslationPAdr;
logic [`PPN_BITS-1:0] CurrentPPN;
logic MemStore;
// PTE Control Bits
logic Dirty, Accessed, Global, User,
Executable, Writable, Readable, Valid;
// PTE descriptions
logic ValidPTE, AccessAlert, MegapageMisaligned, BadMegapage, LeafPTE;
// Signals for direct, fake translations. Not part of the final Wally version.
logic [`XLEN-1:0] DirectInstrPTE, DirectMemPTE;
logic [9:0] DirectPTEFlags = {2'b0, 8'b00001111}; logic [9:0] DirectPTEFlags = {2'b0, 8'b00001111};
// rv32 temp case logic [`VPN_BITS-1:0] PCPageNumber, MemAdrPageNumber;
logic [`VPN_BITS-1:0] PCPageNumber;
logic [`VPN_BITS-1:0] MemAdrPageNumber;
assign BasePageTablePPN = SATP_REGW[`PPN_BITS-1:0]; assign BasePageTablePPN = SATP_REGW[`PPN_BITS-1:0];
assign MemStore = MemRWM[0];
assign PCPageNumber = PCF[`VPN_BITS+11:12]; assign PCPageNumber = PCF[`VPN_BITS+11:12];
assign MemAdrPageNumber = MemAdrM[`VPN_BITS+11:12]; assign MemAdrPageNumber = MemAdrM[`VPN_BITS+11:12];
// Create fake page table entries for direct virtual to physical translation
generate generate
if (`XLEN == 32) begin if (`XLEN == 32) begin
assign DirectInstrPTE = {PCPageNumber, DirectPTEFlags}; assign DirectInstrPTE = {PCPageNumber, DirectPTEFlags};
@ -77,36 +102,39 @@ module pagetablewalker (
end end
endgenerate endgenerate
//flopenr #(`XLEN) instrpte(clk, reset, ITLBMissF, DirectInstrPTE, PageTableEntryF); // Direct translation flops
//flopenr #(`XLEN) datapte(clk, reset, DTLBMissM, DirectMemPTE, PageTableEntryM); //flopenr #(`XLEN) instrpte(HCLK, ~HRESETn, ITLBMissF, DirectInstrPTE, PageTableEntryF);
//flopenr #(`XLEN) datapte(HCLK, ~HRESETn, DTLBMissM, DirectMemPTE, PageTableEntryM);
//flopr #(1) iwritesignal(clk, reset, ITLBMissF, ITLBWriteF); //flopr #(1) iwritesignal(HCLK, ~HRESETn, ITLBMissF, ITLBWriteF);
//flopr #(1) dwritesignal(clk, reset, DTLBMissM, DTLBWriteM); //flopr #(1) dwritesignal(HCLK, ~HRESETn, DTLBMissM, DTLBWriteM);
// Prefer data address translations over instruction address translations // Prefer data address translations over instruction address translations
assign TranslationVAdr = (DTLBMissM) ? MemAdrM : PCF; assign TranslationVAdr = (DTLBMissM) ? MemAdrM : PCF;
assign MMUTranslate = DTLBMissM || ITLBMissF; assign MMUTranslate = DTLBMissM || ITLBMissF;
// unswizzle PTE bits
assign {Dirty, Accessed, Global, User,
Executable, Writable, Readable, Valid} = CurrentPTE[7:0];
// Assign PTE descriptors common across all XLEN values
assign LeafPTE = Executable | Writable | Readable;
assign ValidPTE = Valid && ~(Writable && ~Readable);
assign AccessAlert = ~Accessed || (MemStore && ~Dirty);
generate generate
if (`XLEN == 32) begin if (`XLEN == 32) begin
logic [9:0] VPN1, VPN0;
assign SvMode = SATP_REGW[31]; assign SvMode = SATP_REGW[31];
logic [9:0] VPN1 = TranslationVAdr[31:22]; typedef enum {IDLE, LEVEL1, LEVEL0, LEAF, FAULT} walker_statetype;
logic [9:0] VPN0 = TranslationVAdr[21:12]; // *** could optimize by not passing offset? walker_statetype WalkerState, NextWalkerState;
logic [33:0] TranslationPAdr;
logic [21:0] CurrentPPN;
logic Dirty, Accessed, Global, User,
Executable, Writable, Readable, Valid;
logic ValidPTE, AccessAlert, MegapageMisaligned, BadMegapage, LeafPTE;
typedef enum {IDLE, LEVEL1, LEVEL0, LEAF, FAULT} statetype;
statetype WalkerState, NextWalkerState;
// *** Do we need a synchronizer here for walker to talk to ahblite? // *** Do we need a synchronizer here for walker to talk to ahblite?
flopenl #(.TYPE(statetype)) mmureg(clk, reset, 1'b1, NextWalkerState, IDLE, WalkerState); flopenl #(.TYPE(walker_statetype)) mmureg(HCLK, ~HRESETn, 1'b1, NextWalkerState, IDLE, WalkerState);
// State transition logic
always_comb begin always_comb begin
case (WalkerState) case (WalkerState)
IDLE: if (MMUTranslate) NextWalkerState = LEVEL1; IDLE: if (MMUTranslate) NextWalkerState = LEVEL1;
@ -129,62 +157,59 @@ module pagetablewalker (
endcase endcase
end end
// unswizzle PTE bits
assign {Dirty, Accessed, Global, User,
Executable, Writable, Readable, Valid} = MMUReadPTE[7:0];
// A megapage is a Level 1 leaf page. This page must have zero PPN[0]. // A megapage is a Level 1 leaf page. This page must have zero PPN[0].
assign MegapageMisaligned = |(CurrentPPN[9:0]); assign MegapageMisaligned = |(CurrentPPN[9:0]);
assign LeafPTE = Executable | Writable | Readable;
assign ValidPTE = Valid && ~(Writable && ~Readable);
assign AccessAlert = ~Accessed || (MemWriteM && ~Dirty);
assign BadMegapage = MegapageMisaligned || AccessAlert; // *** Implement better access/dirty scheme assign BadMegapage = MegapageMisaligned || AccessAlert; // *** Implement better access/dirty scheme
// *** Should translate this flop block into our flop module notation assign VPN1 = TranslationVAdr[31:22];
always_ff @(posedge clk, negedge reset) assign VPN0 = TranslationVAdr[21:12]; // *** could optimize by not passing offset?
if (reset) begin
TranslationPAdr <= '0; // Assign combinational outputs
PageTableEntryF <= '0; always_comb begin
MMUTranslationComplete <= '0;
DTLBWriteM <= '0;
ITLBWriteF <= '0;
InstrPageFaultM <= '0;
LoadPageFaultM <= '0;
StorePageFaultM <= '0;
end else begin
// default values // default values
TranslationPAdr <= '0; assign TranslationPAdr = '0;
PageTableEntryF <= '0; assign PageTableEntryF = '0;
MMUTranslationComplete <= '0; assign PageTableEntryM = '0;
DTLBWriteM <= '0; assign MMUTranslationComplete = '0;
ITLBWriteF <= '0; assign DTLBWriteM = '0;
InstrPageFaultM <= '0; assign ITLBWriteF = '0;
LoadPageFaultM <= '0; assign InstrPageFaultM = '0;
StorePageFaultM <= '0; assign LoadPageFaultM = '0;
assign StorePageFaultM = '0;
case (NextWalkerState) case (NextWalkerState)
LEVEL1: begin LEVEL1: begin
TranslationPAdr <= {BasePageTablePPN, VPN1, 2'b00}; assign TranslationPAdr = {BasePageTablePPN, VPN1, 2'b00};
end end
LEVEL0: begin LEVEL0: begin
TranslationPAdr <= {CurrentPPN, VPN0, 2'b00}; assign TranslationPAdr = {CurrentPPN, VPN0, 2'b00};
end end
LEAF: begin LEAF: begin
PageTableEntryF <= MMUReadPTE; // Keep physical address alive to prevent HADDR dropping to 0
PageTableEntryM <= MMUReadPTE; assign TranslationPAdr = {CurrentPPN, VPN0, 2'b00};
MMUTranslationComplete <= '1; assign PageTableEntryF = CurrentPTE;
DTLBWriteM <= DTLBMissM; assign PageTableEntryM = CurrentPTE;
ITLBWriteF <= ~DTLBMissM; // Prefer data over instructions assign MMUTranslationComplete = '1;
assign DTLBWriteM = DTLBMissM;
assign ITLBWriteF = ~DTLBMissM; // Prefer data over instructions
end end
FAULT: begin FAULT: begin
InstrPageFaultM <= ~DTLBMissM; assign InstrPageFaultM = ~DTLBMissM;
LoadPageFaultM <= DTLBMissM && ~MemWriteM; assign LoadPageFaultM = DTLBMissM && ~MemStore;
StorePageFaultM <= DTLBMissM && MemWriteM; assign StorePageFaultM = DTLBMissM && MemStore;
end end
endcase endcase
end end
// Interpret inputs from ahblite
assign CurrentPPN = MMUReadPTE[31:10];
// Capture page table entry from ahblite
flopenr #(32) ptereg(HCLK, ~HRESETn, MMUReady, MMUReadPTE, SavedPTE);
// *** Evil hack to get CurrentPTE a cycle early before it is saved.
// Todo: Is it evil?
mux2 #(32) ptemux(SavedPTE, MMUReadPTE, MMUReady, CurrentPTE);
assign CurrentPPN = CurrentPTE[`PPN_BITS+9:10];
// Assign outputs to ahblite // Assign outputs to ahblite
// *** Currently truncate address to 32 bits. This must be changed if // *** Currently truncate address to 32 bits. This must be changed if
@ -194,27 +219,19 @@ module pagetablewalker (
end else begin end else begin
assign SvMode = SATP_REGW[63]; assign SvMode = SATP_REGW[63];
logic [8:0] VPN2 = TranslationVAdr[38:30]; logic [8:0] VPN2, VPN1, VPN0;
logic [8:0] VPN1 = TranslationVAdr[29:21];
logic [8:0] VPN0 = TranslationVAdr[20:12]; // *** could optimize by not passing offset?
logic [55:0] TranslationPAdr; logic GigapageMisaligned, BadGigapage;
logic [43:0] CurrentPPN;
logic Dirty, Accessed, Global, User, typedef enum {IDLE, LEVEL2, LEVEL1, LEVEL0, LEAF, FAULT} walker_statetype;
Executable, Writable, Readable, Valid; walker_statetype WalkerState, NextWalkerState;
logic ValidPTE, AccessAlert, GigapageMisaligned, MegapageMisaligned,
BadGigapage, BadMegapage, LeafPTE;
typedef enum {IDLE, LEVEL2, LEVEL1, LEVEL0, LEAF, FAULT} statetype;
statetype WalkerState, NextWalkerState;
// *** Do we need a synchronizer here for walker to talk to ahblite? // *** Do we need a synchronizer here for walker to talk to ahblite?
flopenl #(.TYPE(statetype)) mmureg(clk, reset, 1'b1, NextWalkerState, IDLE, WalkerState); flopenl #(.TYPE(walker_statetype)) mmureg(HCLK, ~HRESETn, 1'b1, NextWalkerState, IDLE, WalkerState);
always_comb begin always_comb begin
case (WalkerState) case (WalkerState)
IDLE: if (MMUTranslate) NextWalkerState = LEVEL1; IDLE: if (MMUTranslate) NextWalkerState = LEVEL2;
else NextWalkerState = IDLE; else NextWalkerState = IDLE;
LEVEL2: if (~MMUReady) NextWalkerState = LEVEL2; LEVEL2: if (~MMUReady) NextWalkerState = LEVEL2;
else if (ValidPTE && ~LeafPTE) NextWalkerState = LEVEL1; else if (ValidPTE && ~LeafPTE) NextWalkerState = LEVEL1;
@ -237,67 +254,65 @@ module pagetablewalker (
endcase endcase
end end
// unswizzle PTE bits // A gigapage is a Level 2 leaf page. This page must have zero PPN[1] and
assign {Dirty, Accessed, Global, User, // zero PPN[0]
Executable, Writable, Readable, Valid} = MMUReadPTE[7:0];
// A megapage is a Level 1 leaf page. This page must have zero PPN[0].
assign GigapageMisaligned = |(CurrentPPN[17: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 MegapageMisaligned = |(CurrentPPN[8:0]);
assign LeafPTE = Executable | Writable | Readable;
assign ValidPTE = Valid && ~(Writable && ~Readable);
assign AccessAlert = ~Accessed || (MemWriteM && ~Dirty);
assign BadGigapage = GigapageMisaligned || 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 BadMegapage = MegapageMisaligned || AccessAlert; // *** Implement better access/dirty scheme
assign VPN2 = TranslationVAdr[38:30];
assign VPN1 = TranslationVAdr[29:21];
assign VPN0 = TranslationVAdr[20:12]; // *** could optimize by not passing offset?
// *** Should translate this flop block into our flop module notation // *** Should translate this flop block into our flop module notation
always_ff @(posedge clk, negedge reset) always_comb begin
if (reset) begin
TranslationPAdr <= '0;
PageTableEntryF <= '0;
MMUTranslationComplete <= '0;
DTLBWriteM <= '0;
ITLBWriteF <= '0;
InstrPageFaultM <= '0;
LoadPageFaultM <= '0;
StorePageFaultM <= '0;
end else begin
// default values // default values
TranslationPAdr <= '0; assign TranslationPAdr = '0;
PageTableEntryF <= '0; assign PageTableEntryF = '0;
MMUTranslationComplete <= '0; assign PageTableEntryM = '0;
DTLBWriteM <= '0; assign MMUTranslationComplete = '0;
ITLBWriteF <= '0; assign DTLBWriteM = '0;
InstrPageFaultM <= '0; assign ITLBWriteF = '0;
LoadPageFaultM <= '0; assign InstrPageFaultM = '0;
StorePageFaultM <= '0; assign LoadPageFaultM = '0;
assign StorePageFaultM = '0;
case (NextWalkerState) case (NextWalkerState)
LEVEL2: begin LEVEL2: begin
TranslationPAdr <= {BasePageTablePPN, VPN2, 3'b00}; assign TranslationPAdr = {BasePageTablePPN, VPN2, 3'b000};
end end
LEVEL1: begin LEVEL1: begin
TranslationPAdr <= {CurrentPPN, VPN1, 3'b00}; assign TranslationPAdr = {CurrentPPN, VPN1, 3'b000};
end end
LEVEL0: begin LEVEL0: begin
TranslationPAdr <= {CurrentPPN, VPN0, 3'b00}; assign TranslationPAdr = {CurrentPPN, VPN0, 3'b000};
end end
LEAF: begin LEAF: begin
PageTableEntryF <= MMUReadPTE; // Keep physical address alive to prevent HADDR dropping to 0
PageTableEntryM <= MMUReadPTE; assign TranslationPAdr = {CurrentPPN, VPN0, 3'b000};
MMUTranslationComplete <= '1; assign PageTableEntryF = CurrentPTE;
DTLBWriteM <= DTLBMissM; assign PageTableEntryM = CurrentPTE;
ITLBWriteF <= ~DTLBMissM; // Prefer data over instructions assign MMUTranslationComplete = '1;
assign DTLBWriteM = DTLBMissM;
assign ITLBWriteF = ~DTLBMissM; // Prefer data over instructions
end end
FAULT: begin FAULT: begin
InstrPageFaultM <= ~DTLBMissM; assign InstrPageFaultM = ~DTLBMissM;
LoadPageFaultM <= DTLBMissM && ~MemWriteM; assign LoadPageFaultM = DTLBMissM && ~MemStore;
StorePageFaultM <= DTLBMissM && MemWriteM; assign StorePageFaultM = DTLBMissM && MemStore;
end end
endcase endcase
end end
// Interpret inputs from ahblite // Capture page table entry from ahblite
assign CurrentPPN = MMUReadPTE[53:10]; flopenr #(`XLEN) ptereg(HCLK, ~HRESETn, MMUReady, MMUReadPTE, SavedPTE);
// *** Evil hack to get CurrentPTE a cycle early before it is saved.
// Todo: Is it evil?
mux2 #(`XLEN) ptemux(SavedPTE, MMUReadPTE, MMUReady, CurrentPTE);
assign CurrentPPN = CurrentPTE[`PPN_BITS+9:10];
// Assign outputs to ahblite // Assign outputs to ahblite
// *** Currently truncate address to 32 bits. This must be changed if // *** Currently truncate address to 32 bits. This must be changed if

View File

@ -80,7 +80,7 @@ module ifu (
// logic [`XLEN-1:0] PageTableEntryF = '0; // logic [`XLEN-1:0] PageTableEntryF = '0;
logic ITLBFlushF = '0; logic ITLBFlushF = '0;
// logic ITLBWriteF = '0; // logic ITLBWriteF = '0;
tlb #(3) itlb(clk, reset, SATP_REGW, PrivilegeModeW, PCF, PageTableEntryF, ITLBWriteF, ITLBFlushF, tlb #(3) itlb(clk, reset, SATP_REGW, PrivilegeModeW, 1'b1, PCF, PageTableEntryF, ITLBWriteF, ITLBFlushF,
InstrPAdrF, ITLBMissF, ITLBHitF); InstrPAdrF, ITLBMissF, ITLBHitF);
// branch predictor signals // branch predictor signals
@ -96,7 +96,6 @@ module ifu (
assign PrivilegedChangePCM = RetM | TrapM; assign PrivilegedChangePCM = RetM | TrapM;
//mux3 #(`XLEN) pcmux(PCPlus2or4F, PCCorrectE, PrivilegedNextPCM, {PrivilegedChangePCM, BPPredWrongE}, UnalignedPCNextF); //mux3 #(`XLEN) pcmux(PCPlus2or4F, PCCorrectE, PrivilegedNextPCM, {PrivilegedChangePCM, BPPredWrongE}, UnalignedPCNextF);
mux2 #(`XLEN) pcmux0(.d0(PCPlus2or4F), mux2 #(`XLEN) pcmux0(.d0(PCPlus2or4F),
.d1(BPPredPCF), .d1(BPPredPCF),

View File

@ -63,6 +63,9 @@ module tlb #(parameter ENTRY_BITS = 3) (
// Current privilege level of the processeor // Current privilege level of the processeor
input [1:0] PrivilegeModeW, input [1:0] PrivilegeModeW,
// High if the TLB is currently being accessed
input TLBAccess,
// Virtual address input // Virtual address input
input [`XLEN-1:0] VirtualAddress, input [`XLEN-1:0] VirtualAddress,
@ -82,6 +85,7 @@ module tlb #(parameter ENTRY_BITS = 3) (
logic SvMode; logic SvMode;
logic Translate; logic Translate;
/*
generate generate
if (`XLEN == 32) begin if (`XLEN == 32) begin
assign SvMode = SATP_REGW[31]; // *** change to an enum somehow? assign SvMode = SATP_REGW[31]; // *** change to an enum somehow?
@ -89,9 +93,10 @@ module tlb #(parameter ENTRY_BITS = 3) (
assign SvMode = SATP_REGW[63]; // currently just a boolean whether translation enabled assign SvMode = SATP_REGW[63]; // currently just a boolean whether translation enabled
end end
endgenerate endgenerate
*/
// *** Currently fake virtual memory being on for testing purposes // *** Currently fake virtual memory being on for testing purposes
// *** DO NOT ENABLE UNLESS TESTING // *** DO NOT ENABLE UNLESS TESTING
// assign SvMode = 1; assign SvMode = 1;
assign Translate = SvMode & (PrivilegeModeW != `M_MODE); assign Translate = SvMode & (PrivilegeModeW != `M_MODE);
@ -118,6 +123,8 @@ module tlb #(parameter ENTRY_BITS = 3) (
// Page table entry matching the virtual address // Page table entry matching the virtual address
logic [`XLEN-1:0] PageTableEntry; logic [`XLEN-1:0] PageTableEntry;
logic CAMHit;
assign VirtualPageNumber = VirtualAddress[`VPN_BITS+11:12]; assign VirtualPageNumber = VirtualAddress[`VPN_BITS+11:12];
assign PageOffset = VirtualAddress[11:0]; assign PageOffset = VirtualAddress[11:0];
@ -149,7 +156,8 @@ module tlb #(parameter ENTRY_BITS = 3) (
end end
endgenerate endgenerate
assign TLBMiss = ~TLBHit & ~(TLBWrite | TLBFlush) & Translate; assign TLBHit = CAMHit & TLBAccess;
assign TLBMiss = ~TLBHit & ~TLBFlush & Translate & TLBAccess;
endmodule endmodule
module tlb_ram #(parameter ENTRY_BITS = 3) ( module tlb_ram #(parameter ENTRY_BITS = 3) (
@ -185,7 +193,7 @@ module tlb_cam #(parameter ENTRY_BITS = 3,
input TLBWrite, input TLBWrite,
input TLBFlush, input TLBFlush,
output [ENTRY_BITS-1:0] VPNIndex, output [ENTRY_BITS-1:0] VPNIndex,
output TLBHit output CAMHit
); );
localparam NENTRIES = 2**ENTRY_BITS; localparam NENTRIES = 2**ENTRY_BITS;
@ -220,7 +228,7 @@ module tlb_cam #(parameter ENTRY_BITS = 3,
end end
assign VPNIndex = matched_address_comb; assign VPNIndex = matched_address_comb;
assign TLBHit = match_found_comb & ~(TLBWrite | TLBFlush); assign CAMHit = match_found_comb & ~TLBFlush;
initial begin initial begin
for (int i = 0; i < NENTRIES; i++) for (int i = 0; i < NENTRIES; i++)
@ -236,6 +244,6 @@ module tlb_rand #(parameter ENTRY_BITS = 3) (
logic [31:0] data; logic [31:0] data;
assign data = $urandom; assign data = $urandom;
assign WriteIndex = data[ENTRY_BITS:0]; assign WriteIndex = data[ENTRY_BITS-1:0];
endmodule endmodule

View File

@ -354,7 +354,7 @@ string tests32i[] = {
else tests = {tests, tests64iNOc}; else tests = {tests, tests64iNOc};
if (`M_SUPPORTED) tests = {tests, tests64m}; if (`M_SUPPORTED) tests = {tests, tests64m};
if (`A_SUPPORTED) tests = {tests, tests64a}; if (`A_SUPPORTED) tests = {tests, tests64a};
//if (`MEM_VIRTMEM) tests = {tests, tests64mmu}; if (`MEM_VIRTMEM) tests = {tests, tests64mmu};
end end
// tests = {tests64a, tests}; // tests = {tests64a, tests};
end else begin // RV32 end else begin // RV32
@ -364,7 +364,7 @@ string tests32i[] = {
else tests = {tests, tests32iNOc}; else tests = {tests, tests32iNOc};
if (`M_SUPPORTED % 2 == 1) tests = {tests, tests32m}; if (`M_SUPPORTED % 2 == 1) tests = {tests, tests32m};
if (`A_SUPPORTED) tests = {tests, tests32a}; if (`A_SUPPORTED) tests = {tests, tests32a};
//if (`MEM_VIRTMEM) tests = {tests32mmu, tests}; if (`MEM_VIRTMEM) tests = {tests32mmu, tests};
end end
string signame, memfilename; string signame, memfilename;