forked from Github_Repos/cvw
implemented simpler page mixers, cleaned up a bit
This commit is contained in:
parent
b27abc53e8
commit
c96695b1b6
@ -7,7 +7,7 @@
|
||||
// Mostly this was done to make the PageNumberMixer work.
|
||||
//
|
||||
// Purpose: CAM line for the translation lookaside buffer (TLB)
|
||||
// Determines whether a virtual address matches the stored key.
|
||||
// Determines whether a virtual page number matches the stored key.
|
||||
//
|
||||
// A component of the Wally configurable RISC-V project.
|
||||
//
|
||||
@ -59,32 +59,40 @@ module cam_line #(parameter KEY_BITS = 20,
|
||||
logic [KEY_BITS-1:0] Key;
|
||||
|
||||
|
||||
// Split up key and VPN into sections for each page table level.
|
||||
logic [SEGMENT_BITS-1:0] Key0, Key1, VPN0, VPN1;
|
||||
logic MatchVPN0, MatchVPN1;
|
||||
// Split up key and query into sections for each page table level.
|
||||
logic [SEGMENT_BITS-1:0] Key0, Key1, Query0, Query1;
|
||||
logic Match0, Match1;
|
||||
|
||||
generate
|
||||
if (`XLEN == 32) begin
|
||||
|
||||
assign {Key1, Key0} = Key;
|
||||
assign {VPN1, VPN0} = VirtualPageNumber;
|
||||
assign {Query1, Query0} = VirtualPageNumber;
|
||||
|
||||
assign MatchVPN0 = (VPN0 == Key0) || (PageType[0]); // least signifcant section
|
||||
assign MatchVPN1 = (VPN1 == Key1);
|
||||
// Calculate the actual match value based on the input vpn and the page type.
|
||||
// For example, a megapage in SV32 only cares about VPN[1], so VPN[0]
|
||||
// should automatically match.
|
||||
assign Match0 = (Query0 == Key0) || (PageType[0]); // least signifcant section
|
||||
assign Match1 = (Query1 == Key1);
|
||||
|
||||
assign Match = MatchVPN0 & MatchVPN1 & Valid;
|
||||
assign Match = Match0 & Match1 & Valid;
|
||||
end else begin
|
||||
logic [SEGMENT_BITS-1:0] Key2, Key3, VPN2, VPN3;
|
||||
logic MatchVPN2, MatchVPN3;
|
||||
|
||||
assign {VPN3, VPN2, VPN1, VPN0} = VirtualPageNumber;
|
||||
logic [SEGMENT_BITS-1:0] Key2, Key3, Query2, Query3;
|
||||
logic Match2, Match3;
|
||||
|
||||
assign {Query3, Query2, Query1, Query0} = VirtualPageNumber;
|
||||
assign {Key3, Key2, Key1, Key0} = Key;
|
||||
|
||||
assign MatchVPN0 = (VPN0 == Key0) || (PageType > 2'd0); // least signifcant section
|
||||
assign MatchVPN1 = (VPN1 == Key1) || (PageType > 2'd1);
|
||||
assign MatchVPN2 = (VPN2 == Key2) || (PageType > 2'd2);
|
||||
assign MatchVPN3 = (VPN3 == Key3); // *** this should always match in sv39 since both vPN3 and key3 are zeroed by the pagetable walker before getting to the cam
|
||||
// Calculate the actual match value based on the input vpn and the page type.
|
||||
// For example, a gigapage in SV only cares about VPN[2], so VPN[0] and VPN[1]
|
||||
// should automatically match.
|
||||
assign Match0 = (Query0 == Key0) || (PageType > 2'd0); // least signifcant section
|
||||
assign Match1 = (Query1 == Key1) || (PageType > 2'd1);
|
||||
assign Match2 = (Query2 == Key2) || (PageType > 2'd2);
|
||||
assign Match3 = (Query3 == Key3); // *** this should always match in sv39 since both vPN3 and key3 are zeroed by the pagetable walker before getting to the cam
|
||||
|
||||
assign Match = MatchVPN0 & MatchVPN1 & MatchVPN2 & MatchVPN3 & Valid;
|
||||
assign Match = Match0 & Match1 & Match2 & Match3 & Valid;
|
||||
end
|
||||
endgenerate
|
||||
|
||||
@ -104,20 +112,4 @@ module cam_line #(parameter KEY_BITS = 20,
|
||||
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.
|
||||
// logic [KEY_BITS-1:0] PageNumberMask, MaskedKey, MaskedQuery;
|
||||
// this is the max possible length of the vpn, as listed in wally-constants.
|
||||
// for modes with a mode with fewer bits in the vpn, the extra levels in MaskedQuery
|
||||
// and MaskedKey should have been zeroed out by the tlb before coming through the cam as VirtualPageNumber.
|
||||
generate
|
||||
if (`XLEN == 32) begin
|
||||
|
||||
end else begin
|
||||
|
||||
end
|
||||
endgenerate
|
||||
|
||||
|
||||
endmodule
|
||||
|
@ -1,127 +0,0 @@
|
||||
///////////////////////////////////////////
|
||||
// page_number_mixer.sv
|
||||
//
|
||||
// Written: tfleming@hmc.edu & jtorrey@hmc.edu 6 April 2021
|
||||
// Modified: kmacsaigoren@hmc.edu 1 June 2021
|
||||
// Implemented SV48 on top of SV39. This included adding a 3rd Segment to each of the pagenumbers,
|
||||
// Ensuring that the BITS and HIGH_SEGMENT_BITS inputs were correct everywhere this module gets instatniated,
|
||||
// Adding seveeral muxes to decide the bit selection to turn pagenumbers into segments based on SV mode,
|
||||
// Adding support for terapage/newgigapage encoding.
|
||||
//
|
||||
// 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,
|
||||
input [`SVMODE_BITS-1:0] SvMode,
|
||||
|
||||
output [BITS-1:0] PageNumberCombined
|
||||
);
|
||||
|
||||
// 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. This is outside the 'if XLEN' b/c the constant is already configured
|
||||
// to the correct value for the XLEN in the relevant wally-constants.vh file.
|
||||
localparam LOW_SEGMENT_BITS = `VPN_SEGMENT_BITS;
|
||||
// *** each time this module is implemented, low segment bits is either
|
||||
// `VPN_SEGMENT_BITS or `PPN_LOW_SEGMENT_BITS (if it existed)
|
||||
// in every mode so far, these are the same, so it's left as it is above.
|
||||
|
||||
generate
|
||||
if (`XLEN == 32) begin
|
||||
|
||||
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
|
||||
|
||||
// After segment 0 and 1 of the page number, the width of each segment is dependant on the SvMode.
|
||||
// For this reason, each segment bus is the width of its widest value across each mode
|
||||
// when a smaller value needs to be loaded in to a wider bus, it's loaded in the least significant bits
|
||||
// and left padded with zeros. MAKE SURE that if a value is being padded with zeros here,
|
||||
// that it's padded with zeros everywhere else in the MMU ans beyond to avoid false misses in the TLB.
|
||||
logic [HIGH_SEGMENT_BITS-1:0] Segment3, MixSegment3, Segment3Combined;
|
||||
logic [HIGH_SEGMENT_BITS + LOW_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
|
||||
// *** these muxes assume that only Sv48 and SV39 are implemented in rv64. for future SV57 and up,
|
||||
// there will have to be more muxes to select which value each segment gets.
|
||||
// as a cool reminder: BITS is the width of the page number, virt or phys, coming into this module
|
||||
// while high segment bits is the width of the highest segment of that page number.
|
||||
// Note for future work: this module has to work with both VPNs and PPNs and due to their differing
|
||||
// widths and the fact that the ppn has one longer segment at the top makes the muxes below very confusing.
|
||||
// Potentially very annoying thing for future workers: the number of bits in a ppn is always 44 (for SV39 and48)
|
||||
// but in SV57 and above, this might be a new longer length. In that case these selectors will most likely
|
||||
// become even more complicated and confusing.
|
||||
assign Segment3 = (SvMode == `SV48) ?
|
||||
PageNumber[BITS-1:3*LOW_SEGMENT_BITS] : // take the top segment or not
|
||||
{HIGH_SEGMENT_BITS{1'b0}}; // for virtual page numbers in SV39, both options should be zeros.
|
||||
assign Segment2 = (SvMode == `SV48) ?
|
||||
{{HIGH_SEGMENT_BITS{1'b0}}, PageNumber[3*LOW_SEGMENT_BITS-1:2*LOW_SEGMENT_BITS]} : // just take another low segment left padded with zeros.
|
||||
PageNumber[BITS-1:2*LOW_SEGMENT_BITS]; // otherwise take the rest of the PageNumber
|
||||
assign Segment1 = PageNumber[2*LOW_SEGMENT_BITS-1:LOW_SEGMENT_BITS];
|
||||
assign Segment0 = PageNumber[LOW_SEGMENT_BITS-1:0];
|
||||
|
||||
|
||||
assign MixSegment3 = (SvMode == `SV48) ?
|
||||
MixPageNumber[BITS-1:3*LOW_SEGMENT_BITS] : // take the top segment or not
|
||||
{HIGH_SEGMENT_BITS{1'b0}}; // for virtual page numbers in SV39, both options should be zeros.
|
||||
assign MixSegment2 = (SvMode == `SV48) ?
|
||||
{{HIGH_SEGMENT_BITS{1'b0}}, MixPageNumber[3*LOW_SEGMENT_BITS-1:2*LOW_SEGMENT_BITS]} : // just take another low segment left padded with zeros.
|
||||
MixPageNumber[BITS-1:2*LOW_SEGMENT_BITS]; // otherwise take the rest of the PageNumber
|
||||
assign MixSegment1 = MixPageNumber[2*LOW_SEGMENT_BITS-1:LOW_SEGMENT_BITS];
|
||||
assign MixSegment0 = MixPageNumber[LOW_SEGMENT_BITS-1:0];
|
||||
|
||||
|
||||
// Pass through the high segment
|
||||
assign Segment3Combined = Segment3;
|
||||
|
||||
// Either pass through or zero out lower segments based on the page type
|
||||
assign Segment2Combined = (PageType[1] && PageType[0]) ? MixSegment2 : Segment2; // terapage (page == 11)
|
||||
assign Segment1Combined = (PageType[1]) ? MixSegment1 : Segment1; // gigapage and higher (page == 10 or 11)
|
||||
assign Segment0Combined = (PageType[1] || PageType[0]) ? MixSegment0 : Segment0; // megapage and higher (page == 01 or 10 or 11)
|
||||
|
||||
// Reswizzle segments of the combined page number
|
||||
assign PageNumberCombined = (SvMode == `SV48) ?
|
||||
{Segment3Combined, Segment2Combined[LOW_SEGMENT_BITS-1:0], Segment1Combined, Segment0Combined} :
|
||||
{Segment2Combined, Segment1Combined, Segment0Combined};
|
||||
end
|
||||
endgenerate
|
||||
endmodule
|
@ -1,12 +1,9 @@
|
||||
///////////////////////////////////////////
|
||||
// page_number_mixer.sv
|
||||
// physicalpagemask.sv
|
||||
//
|
||||
// Written: tfleming@hmc.edu & jtorrey@hmc.edu 6 April 2021
|
||||
// Modified: kmacsaigoren@hmc.edu 1 June 2021
|
||||
// Implemented SV48 on top of SV39. This included adding a 3rd Segment to each of the pagenumbers,
|
||||
// Ensuring that the BITS and HIGH_SEGMENT_BITS inputs were correct everywhere this module gets instatniated,
|
||||
// Adding seveeral muxes to decide the bit selection to turn pagenumbers into segments based on SV mode,
|
||||
// Adding support for terapage/newgigapage encoding.
|
||||
// Written: David Harris and kmacsaigoren@hmc.edu 7 June 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.
|
||||
@ -30,37 +27,43 @@
|
||||
|
||||
`include "wally-config.vh"
|
||||
|
||||
module physicalpagemask #(parameter BITS = 20,
|
||||
parameter HIGH_SEGMENT_BITS = 10) (
|
||||
input [BITS-1:0] VirtualAddress, //***
|
||||
input [BITS-1:0] PPN, //***
|
||||
module physicalpagemask (
|
||||
input [`VPN_BITS-1:0] VPN,
|
||||
input [`PPN_BITS-1:0] PPN,
|
||||
input [1:0] PageType,
|
||||
input [`SVMODE_BITS-1:0] SvMode,
|
||||
|
||||
output [BITS-1:0] PhysicalAddress //***
|
||||
output [`PPN_BITS-1:0] MixedPageNumber
|
||||
);
|
||||
|
||||
logic [34:0] OffsetMask;
|
||||
localparam EXTRA_BITS = `PPN_BITS - `VPN_BITS;
|
||||
logic ZeroExtendedVPN = {{EXTRA_BITS{1'b0}}, VPN}; // forces the VPN to be the same width as PPN.
|
||||
|
||||
logic [`PPN_BITS-1:0] OffsetMask;
|
||||
|
||||
|
||||
generate
|
||||
if (`XLEN == 32) begin
|
||||
always_comb
|
||||
case (PageType[0])
|
||||
0: OffsetMask = 34'h3FFFFF000; // kilopage: 22 bits of PPN, 12 bits of offset
|
||||
1: OffsetMask = 34'h3FFC00000; // megapage: 12 bits of PPN, 22 bits of offset
|
||||
// *** the widths of these constansts are hardocded here to match `PPN_BITS in the wally-constants file.
|
||||
0: OffsetMask = 22'h3FFFFF; // kilopage: 22 bits of PPN, 0 bits of VPN
|
||||
1: OffsetMask = 22'h3FFC00; // megapage: 12 bits of PPN, 10 bits of VPN
|
||||
endcase
|
||||
end else begin
|
||||
always_comb
|
||||
case (PageType[1:0])
|
||||
0: OffsetMask = 56'hFFFFFFFFFFF000; // kilopage: 44 bits of PPN, 12 bits of offset
|
||||
1: OffsetMask = 56'hFFFFFFFFE00000; // megapage: 35 bits of PPN, 21 bits of offset
|
||||
2: OffsetMask = 56'hFFFFFFC0000000; // gigapage: 26 bits of PPN, 30 bits of offset
|
||||
3: OffsetMask = 56'hFFFF8000000000; // terapage: 17 bits of PPN, 39 bits of offset
|
||||
0: OffsetMask = 44'hFFFFFFFFFFF; // kilopage: 44 bits of PPN, 0 bits of VPN
|
||||
1: OffsetMask = 44'hFFFFFFFFE00; // megapage: 35 bits of PPN, 9 bits of VPN
|
||||
2: OffsetMask = 44'hFFFFFFC0000; // gigapage: 26 bits of PPN, 18 bits of VPN
|
||||
3: OffsetMask = 44'hFFFF8000000; // terapage: 17 bits of PPN, 27 bits of VPN
|
||||
// *** make sure that this doesnt break when using sv39. In that case, all of these
|
||||
// busses are the widths for sv48, but extra bits should be zeroed out by the mux
|
||||
// in the tlb when it generates VPN from the full virtualadress.
|
||||
endcase
|
||||
end
|
||||
endgenerate
|
||||
|
||||
// merge low bits of the virtual address containing the offset with high bits of the PPN
|
||||
assign PhysicalAddress = VirtualAddress & ~OffsetMask | ((PPN<<12) & OffsetMask);
|
||||
assign MixedPageNumber = (ZeroExtendedVPN & ~OffsetMask) | (PPN & OffsetMask);
|
||||
|
||||
endmodule
|
||||
|
@ -185,19 +185,10 @@ module tlb #(parameter ENTRY_BITS = 3,
|
||||
end
|
||||
endgenerate
|
||||
|
||||
// The highest segment of the physical page number has some extra bits
|
||||
// than the highest segment of the virtual page number.
|
||||
localparam EXTRA_PHYSICAL_BITS = `PPN_HIGH_SEGMENT_BITS - `VPN_SEGMENT_BITS;
|
||||
|
||||
// Replace segments of the virtual page number with segments of the physical
|
||||
// page number. For 4 KB pages, the entire virtual page number is replaced.
|
||||
// For superpages, some segments are considered offsets into a larger page.
|
||||
page_number_mixer #(`PPN_BITS, `PPN_HIGH_SEGMENT_BITS)
|
||||
physical_mixer(PhysicalPageNumber,
|
||||
{{EXTRA_PHYSICAL_BITS{1'b0}}, VirtualPageNumber},
|
||||
HitPageType,
|
||||
SvMode,
|
||||
PhysicalPageNumberMixed);
|
||||
physicalpagemask PageNumberMixer(VirtualPageNumber, PhysicalPageNumber, HitPageType, PhysicalPageNumberMixed);
|
||||
|
||||
// Provide physical address only on TLBHits to cause catastrophic errors if
|
||||
// garbage address is used.
|
||||
|
@ -45,8 +45,8 @@ module testbench();
|
||||
logic [`XLEN-1:0] meminit;
|
||||
|
||||
string tests32mmu[] = '{
|
||||
"rv32mmu/WALLY-VIRTUALMEMORY-NOTRANSLATE", "2000",
|
||||
"rv32mmu/WALLY-VIRTUALMEMORY", "5000"
|
||||
"rv32mmu/WALLY-VIRTUALMEMORY-NOTRANSLATE", "2000"
|
||||
// "rv32mmu/WALLY-VIRTUALMEMORY", "5000" // *** commented out until we have better virtual memory tests.
|
||||
};
|
||||
|
||||
string tests64mmu[] = '{
|
||||
|
Loading…
Reference in New Issue
Block a user