mirror of
				https://github.com/openhwgroup/cvw
				synced 2025-02-11 06:05:49 +00:00 
			
		
		
		
	Generalize tlb module
- number of tlb entries is now parameterized - tlb now supports rv64i
This commit is contained in:
		
							parent
							
								
									21552eaf9d
								
							
						
					
					
						commit
						347275e7ee
					
				@ -2,19 +2,22 @@ module testbench();
 | 
			
		||||
  logic clk, reset;
 | 
			
		||||
 | 
			
		||||
  // DUT inputs
 | 
			
		||||
  logic [31:0] PCF;
 | 
			
		||||
  logic [31:0] PageTableEntryF;
 | 
			
		||||
  logic ITLBWriteF, ITLBFlushF;
 | 
			
		||||
  logic [`XLEN-1:0] SATP;
 | 
			
		||||
  logic [`XLEN-1:0] VirtualAddress;
 | 
			
		||||
  logic [`XLEN-1:0] PageTableEntryWrite;
 | 
			
		||||
  logic TLBWrite, TLBFlush;
 | 
			
		||||
 | 
			
		||||
  // DUT outputs
 | 
			
		||||
  logic [31:0] PCPF;
 | 
			
		||||
  logic ITLBMissF, ITLBHitF;
 | 
			
		||||
  logic [`XLEN-1:0] PhysicalAddress;
 | 
			
		||||
  logic TLBMiss, TLBHit;
 | 
			
		||||
 | 
			
		||||
  // Testbench signals
 | 
			
		||||
  logic [33:0] expected;
 | 
			
		||||
  logic [31:0] vectornum, errors;
 | 
			
		||||
  logic [99:0] testvectors[10000:0];
 | 
			
		||||
 | 
			
		||||
  assign SATP = {1'b1, 31'b0};
 | 
			
		||||
 | 
			
		||||
  // instantiate device under test
 | 
			
		||||
  tlb_toy dut(.*);
 | 
			
		||||
 | 
			
		||||
@ -31,17 +34,17 @@ module testbench();
 | 
			
		||||
 | 
			
		||||
  // apply test vectors on rising edge of clk
 | 
			
		||||
  always @(posedge clk) begin
 | 
			
		||||
    #1; {PCF, PageTableEntryF, ITLBWriteF, ITLBFlushF, expected} = testvectors[vectornum];
 | 
			
		||||
    #1; {VirtualAddress, PageTableEntryWrite, TLBWrite, TLBFlush, expected} = testvectors[vectornum];
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  // check results on falling edge of clk
 | 
			
		||||
  always @(negedge clk)
 | 
			
		||||
    if (~reset) begin // skip during reset
 | 
			
		||||
      if ({PCPF, ITLBMissF, ITLBHitF} !== expected) begin // check result
 | 
			
		||||
      $display("Error: PCF = %b, write = %b, data = %b, flush = %b", PCF,
 | 
			
		||||
        ITLBWriteF, PageTableEntryF, ITLBFlushF);
 | 
			
		||||
      if ({PhysicalAddress, TLBMiss, TLBHit} !== expected) begin // check result
 | 
			
		||||
      $display("Error: VirtualAddress = %b, write = %b, data = %b, flush = %b", VirtualAddress,
 | 
			
		||||
        TLBWrite, PageTableEntryWrite, TLBFlush);
 | 
			
		||||
      $display(" outputs = %b %b %b (%b expected)",
 | 
			
		||||
        PCPF, ITLBMissF, ITLBHitF, expected);
 | 
			
		||||
        PhysicalAddress, TLBMiss, TLBHit, expected);
 | 
			
		||||
      errors = errors + 1;
 | 
			
		||||
    end
 | 
			
		||||
    vectornum = vectornum + 1;
 | 
			
		||||
 | 
			
		||||
@ -24,7 +24,7 @@
 | 
			
		||||
// OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 | 
			
		||||
///////////////////////////////////////////
 | 
			
		||||
 | 
			
		||||
// `include "wally-config.vh"
 | 
			
		||||
`include "wally-config.vh"
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * sv32 specs
 | 
			
		||||
@ -49,126 +49,159 @@
 | 
			
		||||
/* *** TODO:
 | 
			
		||||
 * - add LRU algorithm (select the write index based on which entry was used
 | 
			
		||||
 *   least recently)
 | 
			
		||||
 * - rename signals to use .* notation in CAM and RAM
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
module tlb_toy (
 | 
			
		||||
  input         clk, reset,
 | 
			
		||||
// The TLB will have 2**ENTRY_BITS total entries
 | 
			
		||||
module tlb_toy #(parameter ENTRY_BITS = 3) (
 | 
			
		||||
  input              clk, reset,
 | 
			
		||||
 | 
			
		||||
  // Current value of satp CSR (from privileged unit)
 | 
			
		||||
  input  [`XLEN-1:0] SATP,  // *** How do we get this?
 | 
			
		||||
 | 
			
		||||
  // Virtual address input
 | 
			
		||||
  input  [31:0] PCF,
 | 
			
		||||
  input  [`XLEN-1:0] VirtualAddress,
 | 
			
		||||
 | 
			
		||||
  // Controls for writing a new entry to the TLB
 | 
			
		||||
  input  [31:0] PageTableEntryF,
 | 
			
		||||
  input         ITLBWriteF,
 | 
			
		||||
  input  [`XLEN-1:0] PageTableEntryWrite,
 | 
			
		||||
  input              TLBWrite,
 | 
			
		||||
 | 
			
		||||
  // Invalidate all TLB entries
 | 
			
		||||
  input         ITLBFlushF,
 | 
			
		||||
  input              TLBFlush,
 | 
			
		||||
 | 
			
		||||
  // Physical address outputs
 | 
			
		||||
  output [31:0] PCPF,
 | 
			
		||||
  output        ITLBMissF,
 | 
			
		||||
  output        ITLBHitF
 | 
			
		||||
  output [`XLEN-1:0] PhysicalAddress,
 | 
			
		||||
  output             TLBMiss,
 | 
			
		||||
  output             TLBHit
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
  generate
 | 
			
		||||
    if (`XLEN == 32) begin: ARCH
 | 
			
		||||
      localparam VPN_BITS = 20;
 | 
			
		||||
      localparam PPN_BITS = 22;
 | 
			
		||||
      localparam PA_BITS = 34;
 | 
			
		||||
 | 
			
		||||
      logic SvMode;
 | 
			
		||||
      assign SvMode = SATP[31];  // *** change to an enum somehow?
 | 
			
		||||
    end else begin: ARCH
 | 
			
		||||
      localparam VPN_BITS = 27;
 | 
			
		||||
      localparam PPN_BITS = 44;
 | 
			
		||||
      localparam PA_BITS = 56;
 | 
			
		||||
 | 
			
		||||
      logic SvMode;  // currently just a boolean whether translation enabled
 | 
			
		||||
      assign SvMode = SATP[63];  // *** change to an enum somehow?
 | 
			
		||||
    end
 | 
			
		||||
  endgenerate
 | 
			
		||||
 | 
			
		||||
  // Index (currently random) to write the next TLB entry
 | 
			
		||||
  logic [2:0] WriteIndexF;
 | 
			
		||||
  logic [ENTRY_BITS-1:0] WriteIndex;
 | 
			
		||||
 | 
			
		||||
  // Sections of the virtual and physical addresses
 | 
			
		||||
  logic [19:0] VirtualPageNumberF;
 | 
			
		||||
  logic [21:0] PhysicalPageNumberF;
 | 
			
		||||
  logic [11:0] PageOffsetF;
 | 
			
		||||
  logic [33:0] PhysicalAddressF;
 | 
			
		||||
  logic [ARCH.VPN_BITS-1:0] VirtualPageNumber;
 | 
			
		||||
  logic [ARCH.PPN_BITS-1:0] PhysicalPageNumber;
 | 
			
		||||
  logic [11:0]              PageOffset;
 | 
			
		||||
  logic [ARCH.PA_BITS-1:0]  PhysicalAddressFull;
 | 
			
		||||
 | 
			
		||||
  // Pattern and pattern location in the CAM
 | 
			
		||||
  logic [2:0] VPNIndexF;
 | 
			
		||||
  logic [ENTRY_BITS-1:0] VPNIndex;
 | 
			
		||||
 | 
			
		||||
  // RAM access location
 | 
			
		||||
  logic [2:0] ITLBEntryIndex;
 | 
			
		||||
  logic [ENTRY_BITS-1:0] EntryIndex;
 | 
			
		||||
 | 
			
		||||
  // Page table entry matching the virtual address
 | 
			
		||||
  logic [31:0] PTEMatchF;
 | 
			
		||||
  logic [`XLEN-1:0] PageTableEntry;
 | 
			
		||||
 | 
			
		||||
  assign VirtualPageNumberF = PCF[31:12];
 | 
			
		||||
  assign PageOffsetF        = PCF[11:0];
 | 
			
		||||
  assign VirtualPageNumber = VirtualAddress[ARCH.VPN_BITS+11:12];
 | 
			
		||||
  assign PageOffset        = VirtualAddress[11:0];
 | 
			
		||||
 | 
			
		||||
  // Choose a read or write location to the entry list
 | 
			
		||||
  mux2 #(3) indexmux(VPNIndexF, WriteIndexF, ITLBWriteF, ITLBEntryIndex);
 | 
			
		||||
  mux2 #(3) indexmux(VPNIndex, WriteIndex, TLBWrite, EntryIndex);
 | 
			
		||||
 | 
			
		||||
  // Currently use random replacement algorithm
 | 
			
		||||
  rand3 rdm(clk, reset, WriteIndexF);
 | 
			
		||||
  tlb_rand rdm(.*);
 | 
			
		||||
 | 
			
		||||
  ram8x32 ram(clk, reset, ITLBEntryIndex, PageTableEntryF, ITLBWriteF, PTEMatchF);
 | 
			
		||||
  cam8x21 cam(clk, reset, ITLBWriteF, VirtualPageNumberF, WriteIndexF,
 | 
			
		||||
    ITLBFlushF, VPNIndexF, ITLBHitF);
 | 
			
		||||
  tlb_ram #(ENTRY_BITS) ram(.*);
 | 
			
		||||
  tlb_cam #(ENTRY_BITS, ARCH.VPN_BITS) cam(.*);
 | 
			
		||||
 | 
			
		||||
  always_comb begin
 | 
			
		||||
    assign PhysicalPageNumberF = PTEMatchF[31:10];
 | 
			
		||||
    assign PhysicalPageNumber = PageTableEntry[ARCH.PPN_BITS+9:10];
 | 
			
		||||
 | 
			
		||||
    if (ITLBHitF) begin
 | 
			
		||||
      assign PhysicalAddressF = {PhysicalPageNumberF, PageOffsetF};
 | 
			
		||||
    if (TLBHit) begin
 | 
			
		||||
      assign PhysicalAddressFull = {PhysicalPageNumber, PageOffset};
 | 
			
		||||
    end else begin
 | 
			
		||||
      assign PhysicalAddressF = 34'b0;
 | 
			
		||||
      assign PhysicalAddressFull = 8'b0; // *** Actual behavior; disabled until walker functioning
 | 
			
		||||
      //assign PhysicalAddressFull = {2'b0, VirtualPageNumber, PageOffset} // *** pass through should be removed as soon as walker ready
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  assign PCPF = PhysicalAddressF[31:0];
 | 
			
		||||
  assign ITLBMissF = ~ITLBHitF & ~(ITLBWriteF | ITLBFlushF);
 | 
			
		||||
  generate
 | 
			
		||||
    if (`XLEN == 32) begin
 | 
			
		||||
      mux2 #(`XLEN) addressmux(VirtualAddress, PhysicalAddressFull[31:0], ARCH.SvMode, PhysicalAddress);
 | 
			
		||||
    end else begin
 | 
			
		||||
      mux2 #(`XLEN) addressmux(VirtualAddress, {8'b0, PhysicalAddressFull}, ARCH.SvMode, PhysicalAddress);
 | 
			
		||||
    end
 | 
			
		||||
  endgenerate
 | 
			
		||||
 | 
			
		||||
  assign TLBMiss = ~TLBHit & ~(TLBWrite | TLBFlush) & ARCH.SvMode;
 | 
			
		||||
endmodule
 | 
			
		||||
 | 
			
		||||
// *** Add parameter for number of tlb lines (currently 8)
 | 
			
		||||
module ram8x32 (
 | 
			
		||||
  input         clk, reset,
 | 
			
		||||
  input   [2:0] address,
 | 
			
		||||
  input  [31:0] data,
 | 
			
		||||
  input         we,
 | 
			
		||||
module tlb_ram #(parameter ENTRY_BITS = 3) (
 | 
			
		||||
  input                   clk, reset,
 | 
			
		||||
  input  [ENTRY_BITS-1:0] EntryIndex,
 | 
			
		||||
  input  [`XLEN-1:0]      PageTableEntryWrite,
 | 
			
		||||
  input                   TLBWrite,
 | 
			
		||||
 | 
			
		||||
  output [31:0] out_data
 | 
			
		||||
  output [`XLEN-1:0]      PageTableEntry
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
  logic [31:0] ram [0:7];
 | 
			
		||||
  localparam NENTRIES = 2**ENTRY_BITS;
 | 
			
		||||
 | 
			
		||||
  logic [`XLEN-1:0] ram [0:NENTRIES-1];
 | 
			
		||||
  always @(posedge clk) begin
 | 
			
		||||
    if (we) ram[address] <= data;
 | 
			
		||||
    if (TLBWrite) ram[EntryIndex] <= PageTableEntryWrite;
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  assign out_data = ram[address];
 | 
			
		||||
  assign PageTableEntry = ram[EntryIndex];
 | 
			
		||||
    
 | 
			
		||||
  initial begin
 | 
			
		||||
    for (int i = 0; i < 8; i++)
 | 
			
		||||
      ram[i] = 32'h0;
 | 
			
		||||
    for (int i = 0; i < NENTRIES; i++)
 | 
			
		||||
      ram[i] = `XLEN'b0;
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
endmodule
 | 
			
		||||
 | 
			
		||||
module cam8x21 (
 | 
			
		||||
  input         clk, reset, we,
 | 
			
		||||
  input  [19:0] pattern,
 | 
			
		||||
  input  [2:0]  write_address,
 | 
			
		||||
  input         ITLBFlushF,
 | 
			
		||||
  output [2:0]  matched_address,
 | 
			
		||||
  output        match_found
 | 
			
		||||
module tlb_cam #(parameter ENTRY_BITS = 3,
 | 
			
		||||
                 parameter KEY_BITS   = 20) (
 | 
			
		||||
  input                    clk, reset,
 | 
			
		||||
  input  [KEY_BITS-1:0]    VirtualPageNumber,
 | 
			
		||||
  input  [ENTRY_BITS-1:0]  WriteIndex,
 | 
			
		||||
  input                    TLBWrite,
 | 
			
		||||
  input                    TLBFlush,
 | 
			
		||||
  output [ENTRY_BITS-1:0]  VPNIndex,
 | 
			
		||||
  output                   TLBHit
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
  logic [20:0] ram [0:7];
 | 
			
		||||
  logic [7:0] match_line;
 | 
			
		||||
  localparam NENTRIES = 2**ENTRY_BITS;
 | 
			
		||||
 | 
			
		||||
  logic [2:0] matched_address_comb;
 | 
			
		||||
  logic       match_found_comb;
 | 
			
		||||
  // Each entry of this memory has KEY_BITS for the key plus one valid bit.
 | 
			
		||||
  logic [KEY_BITS:0] ram [0:NENTRIES-1];
 | 
			
		||||
 | 
			
		||||
  logic [ENTRY_BITS-1:0] matched_address_comb;
 | 
			
		||||
  logic                  match_found_comb;
 | 
			
		||||
 | 
			
		||||
  always @(posedge clk) begin
 | 
			
		||||
    if (we) ram[write_address] <= {1'b1,pattern};
 | 
			
		||||
    if (ITLBFlushF) begin
 | 
			
		||||
      for (int i = 0; i < 8; i++)
 | 
			
		||||
        ram[i][20] = 1'b0;
 | 
			
		||||
    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
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  // *** Check whether this for loop synthesizes correctly
 | 
			
		||||
  always_comb begin
 | 
			
		||||
    match_found_comb = 1'b0;
 | 
			
		||||
    matched_address_comb = 3'b0;
 | 
			
		||||
    for (int i = 0; i < 8; i++) begin
 | 
			
		||||
      if (ram[i] == {1'b1,pattern} && !match_found_comb) begin
 | 
			
		||||
    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
 | 
			
		||||
@ -178,31 +211,23 @@ module cam8x21 (
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  assign matched_address = matched_address_comb;
 | 
			
		||||
  assign match_found = match_found_comb & ~(we | ITLBFlushF);
 | 
			
		||||
  assign VPNIndex = matched_address_comb;
 | 
			
		||||
  assign TLBHit = match_found_comb & ~(TLBWrite | TLBFlush);
 | 
			
		||||
 | 
			
		||||
  initial begin
 | 
			
		||||
    for (int i = 0; i < 8; i++)
 | 
			
		||||
      ram[i] <= 0;
 | 
			
		||||
    for (int i = 0; i < NENTRIES; i++)
 | 
			
		||||
      ram[i] <= '0;
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
endmodule
 | 
			
		||||
 | 
			
		||||
module mux2 #(parameter WIDTH = 8) (
 | 
			
		||||
  input  logic [WIDTH-1:0] d0, d1, 
 | 
			
		||||
  input  logic             s, 
 | 
			
		||||
  output logic [WIDTH-1:0] y);
 | 
			
		||||
 | 
			
		||||
  assign y = s ? d1 : d0; 
 | 
			
		||||
endmodule
 | 
			
		||||
 | 
			
		||||
module rand3 (
 | 
			
		||||
module tlb_rand #(parameter ENTRY_BITS = 3) (
 | 
			
		||||
  input        clk, reset,
 | 
			
		||||
  output [2:0] WriteIndexF
 | 
			
		||||
  output [ENTRY_BITS:0] WriteIndex
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
  logic [31:0] data;
 | 
			
		||||
  assign data = $urandom;
 | 
			
		||||
  assign WriteIndexF = data[2:0];
 | 
			
		||||
  assign WriteIndex = data[ENTRY_BITS:0];
 | 
			
		||||
  
 | 
			
		||||
endmodule
 | 
			
		||||
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user