2021-03-18 18:35:46 +00:00
///////////////////////////////////////////
// pagetablewalker.sv
//
// Written: tfleming@hmc.edu 2 March 2021
2021-06-01 21:50:37 +00:00
// Modified: kmacsaigoren@hmc.edu 1 June 2021
// implemented SV48 on top of SV39. This included, adding a level of the FSM for the extra page number segment
// adding support for terapage encoding, and for setting the TranslationPAdr using the new level,
// adding the internal SvMode signal
2021-03-18 18:35:46 +00:00
//
// 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
// 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
// OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
///////////////////////////////////////////
`include " wally-config.vh "
2021-03-31 02:19:27 +00:00
/ * * * *
TO - DO:
2021-06-07 13:46:52 +00:00
- Implement faults on accessed / dirty behavior
2021-03-31 02:19:27 +00:00
*/
2021-03-18 18:35:46 +00:00
2021-03-31 02:19:27 +00:00
module pagetablewalker (
// Control signals
input logic HCLK , HRESETn ,
2021-03-18 18:35:46 +00:00
input logic [ `XLEN - 1 : 0 ] SATP_REGW ,
2021-03-31 02:19:27 +00:00
// Signals from TLBs (addresses to translate)
2021-03-18 18:35:46 +00:00
input logic [ `XLEN - 1 : 0 ] PCF , MemAdrM ,
2021-03-31 02:19:27 +00:00
input logic ITLBMissF , DTLBMissM ,
input logic [ 1 : 0 ] MemRWM ,
2021-03-18 18:35:46 +00:00
2021-03-31 02:19:27 +00:00
// Outputs to the TLBs (PTEs to write)
2021-03-18 18:35:46 +00:00
output logic [ `XLEN - 1 : 0 ] PageTableEntryF , PageTableEntryM ,
2021-04-08 06:44:59 +00:00
output logic [ 1 : 0 ] PageTypeF , PageTypeM ,
2021-03-18 18:35:46 +00:00
output logic ITLBWriteF , DTLBWriteM ,
2021-06-23 21:43:22 +00:00
2021-06-23 23:59:06 +00:00
// *** 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
2021-03-18 18:35:46 +00:00
input logic [ `XLEN - 1 : 0 ] MMUReadPTE ,
input logic MMUReady ,
2021-06-23 21:43:22 +00:00
// *** modify to send to LSU
2021-03-18 18:35:46 +00:00
output logic [ `XLEN - 1 : 0 ] MMUPAdr ,
2021-06-23 21:43:22 +00:00
output logic MMUTranslate , // *** rename to HPTWReq
2021-03-25 06:48:40 +00:00
2021-04-22 05:51:38 +00:00
// Stall signal
output logic MMUStall ,
2021-03-25 06:48:40 +00:00
// Faults
2021-04-21 23:58:36 +00:00
output logic WalkerInstrPageFaultF ,
output logic WalkerLoadPageFaultM ,
output logic WalkerStorePageFaultM
2021-03-18 18:35:46 +00:00
) ;
2021-03-31 02:19:27 +00:00
// Internal signals
2021-03-18 18:35:46 +00:00
logic [ `PPN_BITS - 1 : 0 ] BasePageTablePPN ;
2021-03-31 02:19:27 +00:00
logic [ `XLEN - 1 : 0 ] TranslationVAdr ;
logic [ `XLEN - 1 : 0 ] SavedPTE , CurrentPTE ;
logic [ `PA_BITS - 1 : 0 ] TranslationPAdr ;
logic [ `PPN_BITS - 1 : 0 ] CurrentPPN ;
2021-06-01 21:50:37 +00:00
logic [ `SVMODE_BITS - 1 : 0 ] SvMode ;
2021-03-31 02:19:27 +00:00
logic MemStore ;
2021-03-18 18:35:46 +00:00
2021-03-31 02:19:27 +00:00
// PTE Control Bits
logic Dirty , Accessed , Global , User ,
Executable , Writable , Readable , Valid ;
// PTE descriptions
logic ValidPTE , AccessAlert , MegapageMisaligned , BadMegapage , LeafPTE ;
2021-03-18 18:35:46 +00:00
2021-04-08 06:44:59 +00:00
// Outputs of walker
logic [ `XLEN - 1 : 0 ] PageTableEntry ;
logic [ 1 : 0 ] PageType ;
2021-06-01 21:50:37 +00:00
assign SvMode = SATP_REGW [ `XLEN - 1 : `XLEN - `SVMODE_BITS ] ;
2021-03-18 18:35:46 +00:00
assign BasePageTablePPN = SATP_REGW [ `PPN_BITS - 1 : 0 ] ;
2021-03-31 02:19:27 +00:00
assign MemStore = MemRWM [ 0 ] ;
2021-03-25 06:48:40 +00:00
// Prefer data address translations over instruction address translations
assign TranslationVAdr = ( DTLBMissM ) ? MemAdrM : PCF ;
assign MMUTranslate = DTLBMissM | | ITLBMissF ;
2021-03-18 18:35:46 +00:00
2021-03-31 02:19:27 +00:00
// unswizzle PTE bits
assign { Dirty , Accessed , Global , User ,
Executable , Writable , Readable , Valid } = CurrentPTE [ 7 : 0 ] ;
2021-04-04 01:28:24 +00:00
2021-03-31 02:19:27 +00:00
// Assign PTE descriptors common across all XLEN values
assign LeafPTE = Executable | Writable | Readable ;
assign ValidPTE = Valid & & ~ ( Writable & & ~ Readable ) ;
assign AccessAlert = ~ Accessed | | ( MemStore & & ~ Dirty ) ;
2021-04-08 06:44:59 +00:00
// Assign specific outputs to general outputs
assign PageTableEntryF = PageTableEntry ;
assign PageTableEntryM = PageTableEntry ;
assign PageTypeF = PageType ;
assign PageTypeM = PageType ;
2021-06-22 17:29:49 +00:00
localparam LEVEL0 = 3 'h0 ;
2021-04-13 16:27:12 +00:00
localparam LEVEL1 = 3 'h1 ;
2021-06-01 21:50:37 +00:00
// space left for more levels
localparam LEAF = 3 'h5 ;
localparam IDLE = 3 'h6 ;
localparam FAULT = 3 'h7 ;
2021-04-13 16:27:12 +00:00
logic [ 2 : 0 ] WalkerState , NextWalkerState ;
2021-03-18 18:35:46 +00:00
generate
if ( `XLEN = = 32 ) begin
2021-03-31 02:19:27 +00:00
logic [ 9 : 0 ] VPN1 , VPN0 ;
2021-03-18 18:35:46 +00:00
2021-04-13 16:27:12 +00:00
flopenl # ( 3 ) mmureg ( HCLK , ~ HRESETn , 1 'b1 , NextWalkerState , IDLE , WalkerState ) ;
2021-03-18 18:35:46 +00:00
2021-03-31 02:19:27 +00:00
// State transition logic
2021-03-18 18:35:46 +00:00
always_comb begin
case ( WalkerState )
2021-03-25 06:48:40 +00:00
IDLE: if ( MMUTranslate ) NextWalkerState = LEVEL1 ;
else NextWalkerState = IDLE ;
LEVEL1: if ( ~ MMUReady ) NextWalkerState = LEVEL1 ;
2021-05-14 11:12:32 +00:00
// *** <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.
else if ( ValidPTE & & LeafPTE & & ~ BadMegapage ) NextWalkerState = LEAF ;
2021-05-14 12:06:07 +00:00
// else if (ValidPTE && LeafPTE) NextWalkerState = LEAF; // *** Once the above line is properly tested, delete this line.
2021-03-25 06:48:40 +00:00
else if ( ValidPTE & & ~ LeafPTE ) NextWalkerState = LEVEL0 ;
else NextWalkerState = FAULT ;
LEVEL0: if ( ~ MMUReady ) NextWalkerState = LEVEL0 ;
else if ( ValidPTE & & LeafPTE & & ~ AccessAlert )
NextWalkerState = LEAF ;
else NextWalkerState = FAULT ;
LEAF: if ( MMUTranslate ) NextWalkerState = LEVEL1 ;
else NextWalkerState = IDLE ;
FAULT: if ( MMUTranslate ) NextWalkerState = LEVEL1 ;
else NextWalkerState = IDLE ;
2021-04-13 23:19:58 +00:00
// Default case should never happen, but is included for linter.
default : NextWalkerState = IDLE ;
2021-03-18 18:35:46 +00:00
endcase
end
2021-03-25 06:48:40 +00:00
// 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
2021-03-31 02:19:27 +00:00
assign VPN1 = TranslationVAdr [ 31 : 22 ] ;
2021-05-14 11:12:32 +00:00
assign VPN0 = TranslationVAdr [ 21 : 12 ] ;
2021-03-31 02:19:27 +00:00
// Assign combinational outputs
always_comb begin
// default values
2021-04-13 16:27:12 +00:00
TranslationPAdr = '0 ;
PageTableEntry = '0 ;
PageType = '0 ;
DTLBWriteM = '0 ;
ITLBWriteF = '0 ;
2021-04-21 23:58:36 +00:00
WalkerInstrPageFaultF = '0 ;
WalkerLoadPageFaultM = '0 ;
WalkerStorePageFaultM = '0 ;
2021-04-22 05:51:38 +00:00
MMUStall = '1 ;
2021-03-31 02:19:27 +00:00
case ( NextWalkerState )
2021-04-22 05:51:38 +00:00
IDLE: begin
MMUStall = '0 ;
end
2021-03-31 02:19:27 +00:00
LEVEL1: begin
2021-04-13 16:27:12 +00:00
TranslationPAdr = { BasePageTablePPN , VPN1 , 2 'b00 } ;
2021-03-31 02:19:27 +00:00
end
LEVEL0: begin
2021-04-13 16:27:12 +00:00
TranslationPAdr = { CurrentPPN , VPN0 , 2 'b00 } ;
2021-03-31 02:19:27 +00:00
end
LEAF: begin
// Keep physical address alive to prevent HADDR dropping to 0
2021-04-13 16:27:12 +00:00
TranslationPAdr = { CurrentPPN , VPN0 , 2 'b00 } ;
PageTableEntry = CurrentPTE ;
PageType = ( WalkerState = = LEVEL1 ) ? 2 'b01 : 2 'b00 ;
DTLBWriteM = DTLBMissM ;
ITLBWriteF = ~ DTLBMissM ; // Prefer data over instructions
2021-03-31 02:19:27 +00:00
end
FAULT: begin
2021-04-13 16:27:12 +00:00
TranslationPAdr = { CurrentPPN , VPN0 , 2 'b00 } ;
2021-04-21 23:58:36 +00:00
WalkerInstrPageFaultF = ~ DTLBMissM ;
WalkerLoadPageFaultM = DTLBMissM & & ~ MemStore ;
WalkerStorePageFaultM = DTLBMissM & & MemStore ;
2021-04-22 05:51:38 +00:00
MMUStall = '0 ; // Drop the stall early to enter trap handling code
2021-03-31 02:19:27 +00:00
end
2021-04-13 23:19:58 +00:00
default : begin
// nothing
end
2021-03-31 02:19:27 +00:00
endcase
end
// Capture page table entry from ahblite
flopenr # ( 32 ) ptereg ( HCLK , ~ HRESETn , MMUReady , MMUReadPTE , SavedPTE ) ;
mux2 # ( 32 ) ptemux ( SavedPTE , MMUReadPTE , MMUReady , CurrentPTE ) ;
assign CurrentPPN = CurrentPTE [ `PPN_BITS + 9 : 10 ] ;
2021-03-25 06:48:40 +00:00
// Assign outputs to ahblite
// *** Currently truncate address to 32 bits. This must be changed if
// we support larger physical address spaces
assign MMUPAdr = TranslationPAdr [ 31 : 0 ] ;
2021-03-18 18:35:46 +00:00
end else begin
2021-06-01 21:50:37 +00:00
localparam LEVEL2 = 3 'h2 ;
localparam LEVEL3 = 3 'h3 ;
2021-06-22 17:29:49 +00:00
2021-06-01 21:50:37 +00:00
logic [ 8 : 0 ] VPN3 , VPN2 , VPN1 , VPN0 ;
2021-03-25 06:48:40 +00:00
2021-06-01 21:50:37 +00:00
logic TerapageMisaligned , GigapageMisaligned , BadTerapage , BadGigapage ;
2021-03-25 06:48:40 +00:00
2021-04-13 16:27:12 +00:00
flopenl # ( 3 ) mmureg ( HCLK , ~ HRESETn , 1 'b1 , NextWalkerState , IDLE , WalkerState ) ;
2021-03-25 06:48:40 +00:00
always_comb begin
case ( WalkerState )
2021-06-22 15:21:11 +00:00
IDLE: if ( MMUTranslate & & SvMode = = `SV48 ) NextWalkerState = LEVEL3 ;
else if ( MMUTranslate & & SvMode = = `SV39 ) NextWalkerState = LEVEL2 ;
else NextWalkerState = IDLE ;
LEVEL3: if ( ~ MMUReady ) NextWalkerState = LEVEL3 ;
// *** <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.
else if ( ValidPTE & & LeafPTE & & ~ BadTerapage ) NextWalkerState = LEAF ;
// else if (ValidPTE && LeafPTE) NextWalkerState = LEAF; // *** Once the above line is properly tested, delete this line.
else if ( ValidPTE & & ~ LeafPTE ) NextWalkerState = LEVEL2 ;
else NextWalkerState = FAULT ;
LEVEL2: if ( ~ MMUReady ) NextWalkerState = LEVEL2 ;
2021-05-14 11:12:32 +00:00
// *** <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.
else if ( ValidPTE & & LeafPTE & & ~ BadGigapage ) NextWalkerState = LEAF ;
2021-05-14 12:06:07 +00:00
// else if (ValidPTE && LeafPTE) NextWalkerState = LEAF; // *** Once the above line is properly tested, delete this line.
2021-06-22 15:21:11 +00:00
else if ( ValidPTE & & ~ LeafPTE ) NextWalkerState = LEVEL1 ;
else NextWalkerState = FAULT ;
LEVEL1: if ( ~ MMUReady ) NextWalkerState = LEVEL1 ;
2021-05-14 11:12:32 +00:00
// *** <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.
else if ( ValidPTE & & LeafPTE & & ~ BadMegapage ) NextWalkerState = LEAF ;
2021-05-14 12:06:07 +00:00
// else if (ValidPTE && LeafPTE) NextWalkerState = LEAF; // *** Once the above line is properly tested, delete this line.
2021-06-22 15:21:11 +00:00
else if ( ValidPTE & & ~ LeafPTE ) NextWalkerState = LEVEL0 ;
else NextWalkerState = FAULT ;
LEVEL0: if ( ~ MMUReady ) NextWalkerState = LEVEL0 ;
else if ( ValidPTE & & LeafPTE & & ~ AccessAlert ) NextWalkerState = LEAF ;
else NextWalkerState = FAULT ;
2021-06-22 17:29:49 +00:00
LEAF: if ( MMUTranslate & & SvMode = = `SV48 ) NextWalkerState = LEVEL3 ;
else if ( MMUTranslate & & SvMode = = `SV39 ) NextWalkerState = LEVEL2 ;
2021-06-22 15:21:11 +00:00
else NextWalkerState = IDLE ;
2021-06-22 17:29:49 +00:00
FAULT: if ( MMUTranslate & & SvMode = = `SV48 ) NextWalkerState = LEVEL3 ;
else if ( MMUTranslate & & SvMode = = `SV39 ) NextWalkerState = LEVEL2 ;
2021-06-22 15:21:11 +00:00
else NextWalkerState = IDLE ;
2021-04-13 23:19:58 +00:00
// Default case should never happen, but is included for linter.
2021-06-22 15:21:11 +00:00
default : NextWalkerState = IDLE ;
2021-03-25 06:48:40 +00:00
endcase
end
2021-06-01 21:50:37 +00:00
// 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 ] ) ;
2021-03-31 02:19:27 +00:00
// A gigapage is a Level 2 leaf page. This page must have zero PPN[1] and
// zero PPN[0]
2021-03-25 06:48:40 +00:00
assign GigapageMisaligned = | ( CurrentPPN [ 17 : 0 ] ) ;
2021-03-31 02:19:27 +00:00
// A megapage is a Level 1 leaf page. This page must have zero PPN[0].
2021-03-25 06:48:40 +00:00
assign MegapageMisaligned = | ( CurrentPPN [ 8 : 0 ] ) ;
2021-03-31 02:19:27 +00:00
2021-06-01 21:50:37 +00:00
assign BadTerapage = TerapageMisaligned | | AccessAlert ; // *** Implement better access/dirty scheme
2021-03-25 06:48:40 +00:00
assign BadGigapage = GigapageMisaligned | | AccessAlert ; // *** Implement better access/dirty scheme
assign BadMegapage = MegapageMisaligned | | AccessAlert ; // *** Implement better access/dirty scheme
2021-06-01 21:50:37 +00:00
assign VPN3 = TranslationVAdr [ 47 : 39 ] ;
2021-03-31 02:19:27 +00:00
assign VPN2 = TranslationVAdr [ 38 : 30 ] ;
assign VPN1 = TranslationVAdr [ 29 : 21 ] ;
2021-05-14 11:12:32 +00:00
assign VPN0 = TranslationVAdr [ 20 : 12 ] ;
2021-03-31 02:19:27 +00:00
always_comb begin
// default values
2021-04-13 16:27:12 +00:00
TranslationPAdr = '0 ;
PageTableEntry = '0 ;
PageType = '0 ;
DTLBWriteM = '0 ;
ITLBWriteF = '0 ;
2021-04-21 23:58:36 +00:00
WalkerInstrPageFaultF = '0 ;
WalkerLoadPageFaultM = '0 ;
WalkerStorePageFaultM = '0 ;
2021-05-14 11:12:32 +00:00
// The MMU defaults to stalling the processor
2021-04-22 05:51:38 +00:00
MMUStall = '1 ;
2021-03-31 02:19:27 +00:00
case ( NextWalkerState )
2021-04-22 05:51:38 +00:00
IDLE: begin
MMUStall = '0 ;
end
2021-06-01 21:50:37 +00:00
LEVEL3: begin
TranslationPAdr = { BasePageTablePPN , VPN3 , 3 'b000 } ;
// *** this is a huge breaking point. if we're going through level3 every time, even when sv48 is off,
// what should translationPAdr be when level3 is just off?
end
2021-03-31 02:19:27 +00:00
LEVEL2: begin
2021-06-01 21:50:37 +00:00
TranslationPAdr = { ( SvMode = = `SV48 ) ? CurrentPPN : BasePageTablePPN , VPN2 , 3 'b000 } ;
2021-03-31 02:19:27 +00:00
end
LEVEL1: begin
2021-04-13 16:27:12 +00:00
TranslationPAdr = { CurrentPPN , VPN1 , 3 'b000 } ;
2021-03-31 02:19:27 +00:00
end
LEVEL0: begin
2021-04-13 16:27:12 +00:00
TranslationPAdr = { CurrentPPN , VPN0 , 3 'b000 } ;
2021-03-31 02:19:27 +00:00
end
LEAF: begin
// Keep physical address alive to prevent HADDR dropping to 0
2021-04-13 16:27:12 +00:00
TranslationPAdr = { CurrentPPN , VPN0 , 3 'b000 } ;
PageTableEntry = CurrentPTE ;
2021-06-01 21:50:37 +00:00
PageType = ( WalkerState = = LEVEL3 ) ? 2 'b11 :
( ( WalkerState = = LEVEL2 ) ? 2 'b10 :
( ( WalkerState = = LEVEL1 ) ? 2 'b01 : 2 'b00 ) ) ;
2021-04-13 16:27:12 +00:00
DTLBWriteM = DTLBMissM ;
ITLBWriteF = ~ DTLBMissM ; // Prefer data over instructions
2021-03-31 02:19:27 +00:00
end
FAULT: begin
2021-05-14 11:12:32 +00:00
// Keep physical address alive to prevent HADDR dropping to 0
2021-04-13 16:27:12 +00:00
TranslationPAdr = { CurrentPPN , VPN0 , 3 'b000 } ;
2021-04-21 23:58:36 +00:00
WalkerInstrPageFaultF = ~ DTLBMissM ;
WalkerLoadPageFaultM = DTLBMissM & & ~ MemStore ;
WalkerStorePageFaultM = DTLBMissM & & MemStore ;
2021-04-22 05:51:38 +00:00
MMUStall = '0 ; // Drop the stall early to enter trap handling code
2021-03-31 02:19:27 +00:00
end
2021-04-13 23:19:58 +00:00
default : begin
// nothing
end
2021-03-31 02:19:27 +00:00
endcase
end
// Capture page table entry from ahblite
flopenr # ( `XLEN ) ptereg ( HCLK , ~ HRESETn , MMUReady , MMUReadPTE , SavedPTE ) ;
mux2 # ( `XLEN ) ptemux ( SavedPTE , MMUReadPTE , MMUReady , CurrentPTE ) ;
assign CurrentPPN = CurrentPTE [ `PPN_BITS + 9 : 10 ] ;
2021-03-25 06:48:40 +00:00
// Assign outputs to ahblite
// *** Currently truncate address to 32 bits. This must be changed if
// we support larger physical address spaces
2021-06-10 00:58:20 +00:00
assign MMUPAdr = { { ( `XLEN - 32 ) { 1 'b0 } } , TranslationPAdr [ 31 : 0 ] } ;
2021-03-25 06:48:40 +00:00
end
endgenerate
2021-03-18 18:35:46 +00:00
2021-04-13 16:27:12 +00:00
endmodule