mirror of
https://github.com/openhwgroup/cvw
synced 2025-02-11 06:05:49 +00:00
Complete basic page table walker
This commit is contained in:
parent
0994d03b28
commit
7126ab7864
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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;
|
||||||
|
@ -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
|
||||||
|
@ -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),
|
||||||
|
@ -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
|
||||||
|
@ -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;
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user