Implement support for superpages

This commit is contained in:
Thomas Fleming 2021-04-08 02:44:59 -04:00
parent 7888eacc3f
commit e807f5d771
18 changed files with 360 additions and 67 deletions

View File

@ -26,6 +26,8 @@
///////////////////////////////////////////
// Virtual Memory Constants (sv39)
`define VPN_SEGMENT_BITS 9
`define VPN_BITS 27
`define PPN_BITS 44
`define PPN_HIGH_SEGMENT_BITS 26
`define PA_BITS 56

View File

@ -26,6 +26,8 @@
///////////////////////////////////////////
// Virtual Memory Constants (sv39)
`define VPN_SEGMENT_BITS 9
`define VPN_BITS 27
`define PPN_BITS 44
`define PPN_HIGH_SEGMENT_BITS 26
`define PA_BITS 56

View File

@ -26,6 +26,8 @@
///////////////////////////////////////////
// Virtual Memory Constants (sv39)
`define VPN_SEGMENT_BITS 9
`define VPN_BITS 27
`define PPN_BITS 44
`define PPN_HIGH_SEGMENT_BITS 26
`define PA_BITS 56

View File

@ -26,6 +26,8 @@
///////////////////////////////////////////
// Virtual Memory Constants (sv32)
`define VPN_SEGMENT_BITS 10
`define VPN_BITS 20
`define PPN_BITS 22
`define PPN_HIGH_SEGMENT_BITS 12
`define PA_BITS 34

View File

@ -25,11 +25,9 @@
// OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
///////////////////////////////////////////
// Interrupt configuration
`define PLIC_NUM_SRC 53
`define PLIC_UART_ID 4
// Virtual Memory Constants (sv39)
`define VPN_SEGMENT_BITS 9
`define VPN_BITS 27
`define PPN_BITS 44
`define PPN_HIGH_SEGMENT_BITS 26
`define PA_BITS 56

View File

@ -26,6 +26,8 @@
///////////////////////////////////////////
// Virtual Memory Constants (sv39)
`define VPN_SEGMENT_BITS 9
`define VPN_BITS 27
`define PPN_BITS 44
`define PPN_HIGH_SEGMENT_BITS 26
`define PA_BITS 56

View File

@ -26,6 +26,8 @@
///////////////////////////////////////////
// Virtual Memory Constants (sv39)
`define VPN_SEGMENT_BITS 9
`define VPN_BITS 27
`define PPN_BITS 44
`define PPN_HIGH_SEGMENT_BITS 26
`define PA_BITS 56

View File

@ -52,20 +52,23 @@ module dmem (
// TLB management
input logic [1:0] PrivilegeModeW,
input logic [`XLEN-1:0] PageTableEntryM,
input logic [1:0] PageTypeM,
input logic [`XLEN-1:0] SATP_REGW,
input logic DTLBWriteM, // DTLBFlushM,
input logic DTLBWriteM, DTLBFlushM,
output logic DTLBMissM, DTLBHitM
);
logic MemAccessM; // Whether memory needs to be accessed
logic SquashSCM;
// *** needs to be sent to trap unit
logic DTLBPageFaultM;
// *** temporary hack until walker is hooked up -- Thomas F
// logic [`XLEN-1:0] PageTableEntryM = '0;
logic DTLBFlushM = '0;
// logic DTLBWriteM = '0;
tlb #(3) dtlb(clk, reset, SATP_REGW, PrivilegeModeW, MemAccessM, MemAdrM, PageTableEntryM, DTLBWriteM,
DTLBFlushM, MemPAdrM, DTLBMissM, DTLBHitM);
tlb #(3) dtlb(.TLBAccess(MemAccessM), .VirtualAddress(MemAdrM),
.PageTableEntryWrite(PageTableEntryM), .PageTypeWrite(PageTypeM),
.TLBWrite(DTLBWriteM), .TLBFlush(DTLBFlushM),
.PhysicalAddress(MemPAdrM), .TLBMiss(DTLBMissM),
.TLBHit(DTLBHitM), .TLBPageFault(DTLBPageFaultM),
.*);
// Determine if an Unaligned access is taking place
always_comb

View File

@ -48,6 +48,7 @@ module pagetablewalker (
// Outputs to the TLBs (PTEs to write)
output logic [`XLEN-1:0] PageTableEntryF, PageTableEntryM,
output logic [1:0] PageTypeF, PageTypeM,
output logic ITLBWriteF, DTLBWriteM,
// Signals from ahblite (PTEs from memory)
@ -78,6 +79,10 @@ module pagetablewalker (
// PTE descriptions
logic ValidPTE, AccessAlert, MegapageMisaligned, BadMegapage, LeafPTE;
// Outputs of walker
logic [`XLEN-1:0] PageTableEntry;
logic [1:0] PageType;
// 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};
@ -122,6 +127,12 @@ module pagetablewalker (
assign ValidPTE = Valid && ~(Writable && ~Readable);
assign AccessAlert = ~Accessed || (MemStore && ~Dirty);
// Assign specific outputs to general outputs
assign PageTableEntryF = PageTableEntry;
assign PageTableEntryM = PageTableEntry;
assign PageTypeF = PageType;
assign PageTypeM = PageType;
generate
if (`XLEN == 32) begin
logic [9:0] VPN1, VPN0;
@ -169,8 +180,8 @@ module pagetablewalker (
always_comb begin
// default values
assign TranslationPAdr = '0;
assign PageTableEntryF = '0;
assign PageTableEntryM = '0;
assign PageTableEntry = '0;
assign PageType ='0;
assign MMUTranslationComplete = '0;
assign DTLBWriteM = '0;
assign ITLBWriteF = '0;
@ -188,8 +199,8 @@ module pagetablewalker (
LEAF: begin
// Keep physical address alive to prevent HADDR dropping to 0
assign TranslationPAdr = {CurrentPPN, VPN0, 2'b00};
assign PageTableEntryF = CurrentPTE;
assign PageTableEntryM = CurrentPTE;
assign PageTableEntry = CurrentPTE;
assign PageType = (WalkerState == LEVEL1) ? 2'b01 : 2'b00;
assign MMUTranslationComplete = '1;
assign DTLBWriteM = DTLBMissM;
assign ITLBWriteF = ~DTLBMissM; // Prefer data over instructions
@ -204,8 +215,6 @@ module pagetablewalker (
endcase
end
// Capture page table entry from ahblite
flopenr #(32) ptereg(HCLK, ~HRESETn, MMUReady, MMUReadPTE, SavedPTE);
mux2 #(32) ptemux(SavedPTE, MMUReadPTE, MMUReady, CurrentPTE);
@ -271,8 +280,8 @@ module pagetablewalker (
always_comb begin
// default values
assign TranslationPAdr = '0;
assign PageTableEntryF = '0;
assign PageTableEntryM = '0;
assign PageTableEntry = '0;
assign PageType = '0;
assign MMUTranslationComplete = '0;
assign DTLBWriteM = '0;
assign ITLBWriteF = '0;
@ -293,8 +302,9 @@ module pagetablewalker (
LEAF: begin
// Keep physical address alive to prevent HADDR dropping to 0
assign TranslationPAdr = {CurrentPPN, VPN0, 3'b000};
assign PageTableEntryF = CurrentPTE;
assign PageTableEntryM = CurrentPTE;
assign PageTableEntry = CurrentPTE;
assign PageType = (WalkerState == LEVEL2) ? 2'b11 :
((WalkerState == LEVEL1) ? 2'b01 : 2'b00);
assign MMUTranslationComplete = '1;
assign DTLBWriteM = DTLBMissM;
assign ITLBWriteF = ~DTLBMissM; // Prefer data over instructions

View File

@ -60,6 +60,7 @@ module ifu (
// TLB management
input logic [1:0] PrivilegeModeW,
input logic [`XLEN-1:0] PageTableEntryF,
input logic [1:0] PageTypeF,
input logic [`XLEN-1:0] SATP_REGW,
input logic ITLBWriteF, ITLBFlushF,
output logic ITLBMissF, ITLBHitF
@ -74,9 +75,15 @@ module ifu (
logic [31:0] InstrRawD, InstrE, InstrW;
logic [31:0] nop = 32'h00000013; // instruction for NOP
logic [`XLEN-1:0] ITLBInstrPAdrF, ICacheInstrPAdrF;
// *** send this to the trap unit
logic ITLBPageFaultF;
tlb #(3) itlb(clk, reset, SATP_REGW, PrivilegeModeW, 1'b1, PCF, PageTableEntryF, ITLBWriteF, ITLBFlushF,
ITLBInstrPAdrF, ITLBMissF, ITLBHitF);
tlb #(3) itlb(.TLBAccess(1'b1), .VirtualAddress(PCF),
.PageTableEntryWrite(PageTableEntryF), .PageTypeWrite(PageTypeF),
.TLBWrite(ITLBWriteF), .TLBFlush(ITLBFlushF),
.PhysicalAddress(ITLBInstrPAdrF), .TLBMiss(ITLBMissF),
.TLBHit(ITLBHitF), .TLBPageFault(ITLBPageFaultF),
.*);
// branch predictor signals
logic SelBPPredF;

View File

@ -0,0 +1,79 @@
///////////////////////////////////////////
// cam_line.sv
//
// Written: tfleming@hmc.edu & jtorrey@hmc.edu 6 April 2021
// Modified:
//
// Purpose: CAM line for the translation lookaside buffer (TLB)
// Determines whether a virtual address matches the stored key.
//
// 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"
`include "wally-constants.vh"
module cam_line #(parameter KEY_BITS = 20,
parameter HIGH_SEGMENT_BITS = 10) (
input clk, reset,
// The requested page number to compare against the key
input [KEY_BITS-1:0] VirtualPageNumber,
// Signals to write a new entry to this line
input CAMLineWrite,
input [1:0] PageTypeWrite,
// Flush this line (set valid to 0)
input TLBFlush,
// This entry is a key for a giga, mega, or kilopage.
// PageType == 2'b00 --> kilopage
// PageType == 2'b01 --> megapage
// PageType == 2'b11 --> gigapage
output [1:0] PageType, // *** should this be the stored version or the always updated one?
output Match
);
// This entry has KEY_BITS for the key plus one valid bit.
logic Valid;
logic [KEY_BITS-1:0] Key;
// When determining a match for a superpage, we might use only a portion of
// the input VirtualPageNumber. Unused parts of the VirtualPageNumber are
// zeroed in VirtualPageNumberQuery to better match with Key.
logic [KEY_BITS-1:0] VirtualPageNumberQuery;
// On a write, update the type of the page referred to by this line.
flopenr #(2) pagetypeflop(clk, reset, CAMLineWrite, PageTypeWrite, PageType);
//mux2 #(2) pagetypemux(StoredPageType, PageTypeWrite, CAMLineWrite, PageType);
// On a write, set the valid bit high and update the stored key.
// On a flush, zero the valid bit and leave the key unchanged.
// *** Might we want to update stored key right away to output match on the
// write cycle? (using a mux)
flopenrc #(1) validbitflop(clk, reset, TLBFlush, CAMLineWrite, 1'b1, Valid);
flopenr #(KEY_BITS) keyflop(clk, reset, CAMLineWrite, VirtualPageNumber, Key);
// Calculate the actual query key based on the input key and the page type.
// For example, a megapage in sv39 only cares about VPN2 and VPN1, so VPN0
// should automatically match.
page_number_mixer #(KEY_BITS, HIGH_SEGMENT_BITS) mixer(VirtualPageNumber, Key, PageType, VirtualPageNumberQuery);
assign Match = ({1'b1, VirtualPageNumberQuery} == Key);
endmodule

View File

@ -0,0 +1,36 @@
///////////////////////////////////////////
// decoder.sv
//
// Written: tfleming@hmc.edu & jtorrey@hmc.edu 7 April 2021
// Modified:
//
// Purpose: Binary encoding to one-hot decoder
//
// 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"
module decoder #(parameter BINARY_BITS = 3) (
input [BINARY_BITS-1:0] binary,
output [(2**BINARY_BITS)-1:0] one_hot
);
// *** Double check whether this synthesizes as expected
assign one_hot = 1 << binary;
endmodule

View File

@ -0,0 +1,85 @@
///////////////////////////////////////////
// page_number_mixer.sv
//
// Written: tfleming@hmc.edu & jtorrey@hmc.edu 6 April 2021
// Modified:
//
// Purpose: Takes two page numbers and replaces segments of the first page
// number with segments from the second, based on the page type.
//
// 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"
module page_number_mixer #(parameter BITS = 20,
parameter HIGH_SEGMENT_BITS = 10) (
input [BITS-1:0] PageNumber,
input [BITS-1:0] MixPageNumber,
input [1:0] PageType,
output [BITS-1:0] PageNumberCombined
);
generate
// *** Just checking XLEN is not enough to support sv39 AND sv48.
if (`XLEN == 32) begin
// The upper segment might have a different width than the lower segments.
// For example, an sv39 PTE has 26 bits for PPN2 and 9 bits for the other
// segments.
localparam LOW_SEGMENT_BITS = (BITS - HIGH_SEGMENT_BITS);
logic [HIGH_SEGMENT_BITS-1:0] Segment1, MixSegment1, Segment1Combined;
logic [LOW_SEGMENT_BITS-1:0] Segment0, MixSegment0, Segment0Combined;
// Unswizzle segments of the input page numbers
assign {Segment1, Segment0} = PageNumber;
assign {MixSegment1, MixSegment0} = MixPageNumber;
// Pass through the high segment
assign Segment1Combined = Segment1;
// Either pass through or zero out segment 0
mux2 #(LOW_SEGMENT_BITS) segment0mux(Segment0, MixSegment0, PageType[0], Segment0Combined);
// Reswizzle segments of the combined page number
assign PageNumberCombined = {Segment1Combined, Segment0Combined};
end else begin
// The upper segment might have a different width than the lower segments.
// For example, an sv39 PTE has 26 bits for PPN2 and 9 bits for the other
// segments.
localparam LOW_SEGMENT_BITS = (BITS - HIGH_SEGMENT_BITS) / 2;
logic [HIGH_SEGMENT_BITS-1:0] Segment2, MixSegment2, Segment2Combined;
logic [LOW_SEGMENT_BITS-1:0] Segment1, MixSegment1, Segment1Combined;
logic [LOW_SEGMENT_BITS-1:0] Segment0, MixSegment0, Segment0Combined;
// Unswizzle segments of the input page number
assign {Segment2, Segment1, Segment0} = PageNumber;
assign {MixSegment2, MixSegment1, MixSegment0} = MixPageNumber;
// Pass through the high segment
assign Segment2Combined = Segment2;
// Either pass through or zero out segments 1 and 0 based on the page type
mux2 #(LOW_SEGMENT_BITS) segment1mux(Segment1, MixSegment1, PageType[1], Segment1Combined);
mux2 #(LOW_SEGMENT_BITS) segment0mux(Segment0, MixSegment0, PageType[0], Segment0Combined);
// Reswizzle segments of the combined page number
assign PageNumberCombined = {Segment2Combined, Segment1Combined, Segment0Combined};
end
endgenerate
endmodule

View File

@ -0,0 +1,48 @@
///////////////////////////////////////////
// priority_encoder.sv
//
// Written: tfleming@hmc.edu & jtorrey@hmc.edu 7 April 2021
// Modified:
//
// Purpose: One-hot encoding to binary encoder
//
// 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"
// *** We should look for a better parameterized priority encoder. This has a
// bad code smell and might not synthesize
module priority_encoder #(parameter BINARY_BITS = 3) (
input [(2**BINARY_BITS)-1:0] one_hot,
output [BINARY_BITS-1:0] binary
);
localparam ONE_HOT_BITS = 2**BINARY_BITS;
genvar i, j;
generate
for (i = 0; i < ONE_HOT_BITS; i++) begin
for (j = 0; j < BINARY_BITS; j++) begin
if (i[j]) begin
assign binary[j] = one_hot[i];
end
end
end
endgenerate
endmodule

View File

@ -71,6 +71,7 @@ module tlb #(parameter ENTRY_BITS = 3) (
// Controls for writing a new entry to the TLB
input [`XLEN-1:0] PageTableEntryWrite,
input [1:0] PageTypeWrite,
input TLBWrite,
// Invalidate all TLB entries
@ -79,7 +80,10 @@ module tlb #(parameter ENTRY_BITS = 3) (
// Physical address outputs
output [`XLEN-1:0] PhysicalAddress,
output TLBMiss,
output TLBHit
output TLBHit,
// Faults
output TLBPageFault
);
logic SvMode;
@ -108,19 +112,18 @@ module tlb #(parameter ENTRY_BITS = 3) (
// Sections of the virtual and physical addresses
logic [`VPN_BITS-1:0] VirtualPageNumber;
logic [`PPN_BITS-1:0] PhysicalPageNumber;
logic [`PPN_BITS-1:0] PhysicalPageNumber, PhysicalPageNumberMixed;
logic [7:0] PTEAccessBits;
logic [11:0] PageOffset;
logic [`PA_BITS-1:0] PhysicalAddressFull;
// Pattern and pattern location in the CAM
// Pattern location in the CAM and type of page hit
logic [ENTRY_BITS-1:0] VPNIndex;
logic [1:0] HitPageType;
// RAM access location
logic [ENTRY_BITS-1:0] EntryIndex;
// Page table entry matching the virtual address
logic [`XLEN-1:0] PageTableEntry;
logic CAMHit;
assign VirtualPageNumber = VirtualAddress[`VPN_BITS+11:12];
@ -130,9 +133,21 @@ module tlb #(parameter ENTRY_BITS = 3) (
tlb_rand rdm(.*);
tlb_ram #(ENTRY_BITS) ram(.*);
tlb_cam #(ENTRY_BITS, `VPN_BITS) cam(.*);
tlb_cam #(ENTRY_BITS, `VPN_BITS, `VPN_SEGMENT_BITS) cam(.*);
assign PhysicalAddressFull = (TLBHit) ? {PhysicalPageNumber, PageOffset} : '0;
// *** check whether access is allowed, otherwise fault
assign TLBPageFault = 0; // *** temporary
localparam EXTRA_PHYSICAL_BITS = `PPN_HIGH_SEGMENT_BITS - `VPN_SEGMENT_BITS;
page_number_mixer #(`PPN_BITS, `PPN_HIGH_SEGMENT_BITS)
physical_mixer(PhysicalPageNumber,
{{EXTRA_PHYSICAL_BITS{1'b0}}, VirtualPageNumber},
HitPageType,
PhysicalPageNumberMixed);
assign PhysicalAddressFull = (TLBHit) ?
{PhysicalPageNumberMixed, PageOffset} : '0;
generate
if (`XLEN == 32) begin
@ -154,18 +169,22 @@ module tlb_ram #(parameter ENTRY_BITS = 3) (
input [`XLEN-1:0] PageTableEntryWrite,
input TLBWrite,
output [`XLEN-1:0] PageTableEntry
output [`PPN_BITS-1:0] PhysicalPageNumber,
output [7:0] PTEAccessBits
);
localparam NENTRIES = 2**ENTRY_BITS;
logic [`XLEN-1:0] ram [0:NENTRIES-1];
logic [`XLEN-1:0] PageTableEntry;
always @(posedge clk) begin
if (TLBWrite) ram[WriteIndex] <= PageTableEntryWrite;
end
assign PageTableEntry = ram[VPNIndex];
assign PTEAccessBits = PageTableEntry[7:0];
assign PhysicalPageNumber = PageTableEntry[`PPN_BITS+9:10];
initial begin
for (int i = 0; i < NENTRIES; i++)
ram[i] = `XLEN'b0;
@ -174,54 +193,49 @@ module tlb_ram #(parameter ENTRY_BITS = 3) (
endmodule
module tlb_cam #(parameter ENTRY_BITS = 3,
parameter KEY_BITS = 20) (
parameter KEY_BITS = 20,
parameter HIGH_SEGMENT_BITS = 10) (
input clk, reset,
input [KEY_BITS-1:0] VirtualPageNumber,
input [1:0] PageTypeWrite,
input [ENTRY_BITS-1:0] WriteIndex,
input TLBWrite,
input TLBFlush,
output [ENTRY_BITS-1:0] VPNIndex,
output [1:0] HitPageType,
output CAMHit
);
localparam NENTRIES = 2**ENTRY_BITS;
// Each entry of this memory has KEY_BITS for the key plus one valid bit.
logic [KEY_BITS:0] ram [0:NENTRIES-1];
logic [NENTRIES-1:0] CAMLineWrite;
logic [1:0] PageTypeList [0:NENTRIES-1];
logic [NENTRIES-1:0] Matches;
logic [ENTRY_BITS-1:0] matched_address_comb;
logic match_found_comb;
// Determine which CAM line should be written, based on a binary index
decoder #(ENTRY_BITS) decoder(WriteIndex, CAMLineWrite);
always @(posedge clk) begin
if (TLBWrite) ram[WriteIndex] <= {1'b1,VirtualPageNumber};
if (TLBFlush) begin
for (int i = 0; i < NENTRIES; i++)
ram[i][KEY_BITS] = 1'b0; // Zero out msb (valid bit) of all entries
// Create NENTRIES CAM lines, each of which will independently consider
// whether the requested virtual address is a match. Each line stores the
// original virtual page number from when the address was written, regardless
// of page type. However, matches are determined based on a subset of the
// page number segments.
generate
genvar i;
for (i = 0; i < NENTRIES; i++) begin
cam_line #(KEY_BITS, HIGH_SEGMENT_BITS) cam_line(
.CAMLineWrite(CAMLineWrite[i] && TLBWrite),
.PageType(PageTypeList[i]),
.Match(Matches[i]),
.*);
end
end
endgenerate
// *** Check whether this for loop synthesizes correctly
always_comb begin
match_found_comb = 1'b0;
matched_address_comb = '0;
for (int i = 0; i < NENTRIES; i++) begin
if (ram[i] == {1'b1,VirtualPageNumber} && !match_found_comb) begin
matched_address_comb = i;
match_found_comb = 1;
end else begin
matched_address_comb = matched_address_comb;
match_found_comb = match_found_comb;
end
end
end
// In case there are multiple matches in the CAM, select only one
priority_encoder #(ENTRY_BITS) match_priority(Matches, VPNIndex);
assign VPNIndex = matched_address_comb;
assign CAMHit = match_found_comb & ~TLBFlush;
initial begin
for (int i = 0; i < NENTRIES; i++)
ram[i] = '0;
end
assign CAMHit = |Matches & ~TLBFlush;
assign HitPageType = PageTypeList[VPNIndex];
endmodule

View File

@ -105,6 +105,7 @@ module wallypipelinedhart (
logic [1:0] PrivilegeModeW;
logic [`XLEN-1:0] PageTableEntryF, PageTableEntryM;
logic [1:0] PageTypeF, PageTypeM;
// IMem stalls
logic ICacheStallF;

View File

@ -369,7 +369,7 @@ string tests32i[] = {
// if (`F_SUPPORTED) tests = {tests64f, tests};
// if (`D_SUPPORTED) tests = {tests64d, tests};
if (`A_SUPPORTED) tests = {tests, tests64a};
//if (`MEM_VIRTMEM) tests = {tests, tests64mmu};
if (`MEM_VIRTMEM) tests = {tests64mmu, tests};
end
// tests = {tests64a, tests};
tests = {tests, tests64p};

View File

@ -198,7 +198,7 @@ rv32 = Architecture(32)
rv64 = Architecture(64)
if __name__ == "__main__":
arch = rv32
arch = rv64
pgdir = PageTable("page_directory", next_ppn(), arch)
# Directly map the first 20 pages of RAM