From e807f5d77136898a75d85cbb1350d1b1c4c0c105 Mon Sep 17 00:00:00 2001 From: Thomas Fleming Date: Thu, 8 Apr 2021 02:44:59 -0400 Subject: [PATCH] Implement support for superpages --- .../config/busybear/wally-constants.vh | 2 + .../config/coremark/wally-constants.vh | 2 + .../config/coremark_bare/wally-constants.vh | 2 + .../config/rv32ic/wally-constants.vh | 2 + .../config/rv64ic/wally-constants.vh | 6 +- .../config/rv64icfd/wally-constants.vh | 2 + .../config/rv64imc/wally-constants.vh | 2 + wally-pipelined/src/dmem/dmem.sv | 17 ++-- wally-pipelined/src/ebu/pagetablewalker.sv | 30 ++++-- wally-pipelined/src/ifu/ifu.sv | 11 ++- wally-pipelined/src/mmu/cam_line.sv | 79 +++++++++++++++ wally-pipelined/src/mmu/decoder.sv | 36 +++++++ wally-pipelined/src/mmu/page_number_mixer.sv | 85 ++++++++++++++++ wally-pipelined/src/mmu/priority_encoder.sv | 48 +++++++++ wally-pipelined/src/mmu/tlb.sv | 98 +++++++++++-------- .../src/wally/wallypipelinedhart.sv | 1 + .../testbench/testbench-imperas.sv | 2 +- .../testgen/virtual_memory_util.py | 2 +- 18 files changed, 360 insertions(+), 67 deletions(-) create mode 100644 wally-pipelined/src/mmu/cam_line.sv create mode 100644 wally-pipelined/src/mmu/decoder.sv create mode 100644 wally-pipelined/src/mmu/page_number_mixer.sv create mode 100644 wally-pipelined/src/mmu/priority_encoder.sv diff --git a/wally-pipelined/config/busybear/wally-constants.vh b/wally-pipelined/config/busybear/wally-constants.vh index 55fb4e947..43d958632 100644 --- a/wally-pipelined/config/busybear/wally-constants.vh +++ b/wally-pipelined/config/busybear/wally-constants.vh @@ -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 diff --git a/wally-pipelined/config/coremark/wally-constants.vh b/wally-pipelined/config/coremark/wally-constants.vh index 55fb4e947..43d958632 100644 --- a/wally-pipelined/config/coremark/wally-constants.vh +++ b/wally-pipelined/config/coremark/wally-constants.vh @@ -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 diff --git a/wally-pipelined/config/coremark_bare/wally-constants.vh b/wally-pipelined/config/coremark_bare/wally-constants.vh index 55fb4e947..43d958632 100644 --- a/wally-pipelined/config/coremark_bare/wally-constants.vh +++ b/wally-pipelined/config/coremark_bare/wally-constants.vh @@ -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 diff --git a/wally-pipelined/config/rv32ic/wally-constants.vh b/wally-pipelined/config/rv32ic/wally-constants.vh index ffa26727a..ec4a48b4d 100644 --- a/wally-pipelined/config/rv32ic/wally-constants.vh +++ b/wally-pipelined/config/rv32ic/wally-constants.vh @@ -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 diff --git a/wally-pipelined/config/rv64ic/wally-constants.vh b/wally-pipelined/config/rv64ic/wally-constants.vh index a9041d4da..43d958632 100644 --- a/wally-pipelined/config/rv64ic/wally-constants.vh +++ b/wally-pipelined/config/rv64ic/wally-constants.vh @@ -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 diff --git a/wally-pipelined/config/rv64icfd/wally-constants.vh b/wally-pipelined/config/rv64icfd/wally-constants.vh index 55fb4e947..43d958632 100644 --- a/wally-pipelined/config/rv64icfd/wally-constants.vh +++ b/wally-pipelined/config/rv64icfd/wally-constants.vh @@ -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 diff --git a/wally-pipelined/config/rv64imc/wally-constants.vh b/wally-pipelined/config/rv64imc/wally-constants.vh index 55fb4e947..43d958632 100644 --- a/wally-pipelined/config/rv64imc/wally-constants.vh +++ b/wally-pipelined/config/rv64imc/wally-constants.vh @@ -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 diff --git a/wally-pipelined/src/dmem/dmem.sv b/wally-pipelined/src/dmem/dmem.sv index d23e16e99..75559c3f9 100644 --- a/wally-pipelined/src/dmem/dmem.sv +++ b/wally-pipelined/src/dmem/dmem.sv @@ -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 diff --git a/wally-pipelined/src/ebu/pagetablewalker.sv b/wally-pipelined/src/ebu/pagetablewalker.sv index 1a5df96a2..83c1de84d 100644 --- a/wally-pipelined/src/ebu/pagetablewalker.sv +++ b/wally-pipelined/src/ebu/pagetablewalker.sv @@ -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 diff --git a/wally-pipelined/src/ifu/ifu.sv b/wally-pipelined/src/ifu/ifu.sv index bc867bd85..bc0443002 100644 --- a/wally-pipelined/src/ifu/ifu.sv +++ b/wally-pipelined/src/ifu/ifu.sv @@ -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; diff --git a/wally-pipelined/src/mmu/cam_line.sv b/wally-pipelined/src/mmu/cam_line.sv new file mode 100644 index 000000000..36765b277 --- /dev/null +++ b/wally-pipelined/src/mmu/cam_line.sv @@ -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 \ No newline at end of file diff --git a/wally-pipelined/src/mmu/decoder.sv b/wally-pipelined/src/mmu/decoder.sv new file mode 100644 index 000000000..0d34df7a7 --- /dev/null +++ b/wally-pipelined/src/mmu/decoder.sv @@ -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 diff --git a/wally-pipelined/src/mmu/page_number_mixer.sv b/wally-pipelined/src/mmu/page_number_mixer.sv new file mode 100644 index 000000000..57b8e4b77 --- /dev/null +++ b/wally-pipelined/src/mmu/page_number_mixer.sv @@ -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 diff --git a/wally-pipelined/src/mmu/priority_encoder.sv b/wally-pipelined/src/mmu/priority_encoder.sv new file mode 100644 index 000000000..aa309da79 --- /dev/null +++ b/wally-pipelined/src/mmu/priority_encoder.sv @@ -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 diff --git a/wally-pipelined/src/mmu/tlb.sv b/wally-pipelined/src/mmu/tlb.sv index 664fd92d0..194b1c22f 100644 --- a/wally-pipelined/src/mmu/tlb.sv +++ b/wally-pipelined/src/mmu/tlb.sv @@ -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 diff --git a/wally-pipelined/src/wally/wallypipelinedhart.sv b/wally-pipelined/src/wally/wallypipelinedhart.sv index 9f11db98c..9b2bfe6a9 100644 --- a/wally-pipelined/src/wally/wallypipelinedhart.sv +++ b/wally-pipelined/src/wally/wallypipelinedhart.sv @@ -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; diff --git a/wally-pipelined/testbench/testbench-imperas.sv b/wally-pipelined/testbench/testbench-imperas.sv index 416f1c414..12bf180ba 100644 --- a/wally-pipelined/testbench/testbench-imperas.sv +++ b/wally-pipelined/testbench/testbench-imperas.sv @@ -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}; diff --git a/wally-pipelined/testgen/virtual_memory_util.py b/wally-pipelined/testgen/virtual_memory_util.py index 758e0faf9..27ca742b3 100644 --- a/wally-pipelined/testgen/virtual_memory_util.py +++ b/wally-pipelined/testgen/virtual_memory_util.py @@ -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