From 21552eaf9dcc1914c782c5445966994f7cd5b25d Mon Sep 17 00:00:00 2001
From: Thomas Fleming <tfleming@hmc.edu>
Date: Thu, 18 Feb 2021 18:06:09 -0500
Subject: [PATCH 1/3] Create simple TLB

This TLB is just a demonstration and is not currently
instantiated by the IFU or DFU.
---
 wally-pipelined/src/tlb_toy/tlb_testbench.sv |  53 +++++
 wally-pipelined/src/tlb_toy/tlb_toy.sv       | 208 +++++++++++++++++++
 wally-pipelined/src/tlb_toy/tlb_toy.tv       |  11 +
 3 files changed, 272 insertions(+)
 create mode 100644 wally-pipelined/src/tlb_toy/tlb_testbench.sv
 create mode 100644 wally-pipelined/src/tlb_toy/tlb_toy.sv
 create mode 100644 wally-pipelined/src/tlb_toy/tlb_toy.tv

diff --git a/wally-pipelined/src/tlb_toy/tlb_testbench.sv b/wally-pipelined/src/tlb_toy/tlb_testbench.sv
new file mode 100644
index 000000000..add65d3db
--- /dev/null
+++ b/wally-pipelined/src/tlb_toy/tlb_testbench.sv
@@ -0,0 +1,53 @@
+module testbench();
+  logic clk, reset;
+
+  // DUT inputs
+  logic [31:0] PCF;
+  logic [31:0] PageTableEntryF;
+  logic ITLBWriteF, ITLBFlushF;
+
+  // DUT outputs
+  logic [31:0] PCPF;
+  logic ITLBMissF, ITLBHitF;
+
+  // Testbench signals
+  logic [33:0] expected;
+  logic [31:0] vectornum, errors;
+  logic [99:0] testvectors[10000:0];
+
+  // instantiate device under test
+  tlb_toy dut(.*);
+
+  // generate clock
+  always begin
+    clk=1; #5; clk=0; #5;
+  end
+
+  // at start of test, load vectors and pulse reset
+  initial begin
+    $readmemb("tlb_toy.tv", testvectors);
+    vectornum = 0; errors = 0; reset = 1; #22; reset = 0;
+  end
+
+  // apply test vectors on rising edge of clk
+  always @(posedge clk) begin
+    #1; {PCF, PageTableEntryF, ITLBWriteF, ITLBFlushF, 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);
+      $display(" outputs = %b %b %b (%b expected)",
+        PCPF, ITLBMissF, ITLBHitF, expected);
+      errors = errors + 1;
+    end
+    vectornum = vectornum + 1;
+    if (testvectors[vectornum] === 100'bx) begin
+      $display("%d tests completed with %d errors", vectornum, errors);
+      $stop;
+    end
+  end
+endmodule 
diff --git a/wally-pipelined/src/tlb_toy/tlb_toy.sv b/wally-pipelined/src/tlb_toy/tlb_toy.sv
new file mode 100644
index 000000000..43c94babe
--- /dev/null
+++ b/wally-pipelined/src/tlb_toy/tlb_toy.sv
@@ -0,0 +1,208 @@
+///////////////////////////////////////////
+// tlb_toy.sv
+//
+// Written: jtorrey@hmc.edu 16 February 2021
+// Modified:
+//
+// Purpose: Example translation lookaside buffer
+//           Cache of virtural-to-physical address translations
+// 
+// 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"
+
+/**
+ * sv32 specs
+ * ----------
+ * Virtual address [31:0] (32 bits)
+ *    [________________________________]
+ *     |--VPN1--||--VPN0--||----OFF---|
+ *         10        10         12
+ * 
+ * Physical address [33:0] (34 bits)
+ *  [__________________________________]
+ *   |---PPN1---||--PPN0--||----OFF---|
+ *        12         10         12
+ * 
+ * Page Table Entry [31:0] (32 bits)
+ *    [________________________________]
+ *     |---PPN1---||--PPN0--|||DAGUXWRV
+ *          12         10    ^^
+ *                         RSW(2) -- for OS
+ */
+
+/* *** 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,
+
+  // Virtual address input
+  input  [31:0] PCF,
+
+  // Controls for writing a new entry to the TLB
+  input  [31:0] PageTableEntryF,
+  input         ITLBWriteF,
+
+  // Invalidate all TLB entries
+  input         ITLBFlushF,
+
+  // Physical address outputs
+  output [31:0] PCPF,
+  output        ITLBMissF,
+  output        ITLBHitF
+);
+  // Index (currently random) to write the next TLB entry
+  logic [2:0] WriteIndexF;
+
+  // Sections of the virtual and physical addresses
+  logic [19:0] VirtualPageNumberF;
+  logic [21:0] PhysicalPageNumberF;
+  logic [11:0] PageOffsetF;
+  logic [33:0] PhysicalAddressF;
+
+  // Pattern and pattern location in the CAM
+  logic [2:0] VPNIndexF;
+
+  // RAM access location
+  logic [2:0] ITLBEntryIndex;
+
+  // Page table entry matching the virtual address
+  logic [31:0] PTEMatchF;
+
+  assign VirtualPageNumberF = PCF[31:12];
+  assign PageOffsetF        = PCF[11:0];
+
+  // Choose a read or write location to the entry list
+  mux2 #(3) indexmux(VPNIndexF, WriteIndexF, ITLBWriteF, ITLBEntryIndex);
+
+  // Currently use random replacement algorithm
+  rand3 rdm(clk, reset, WriteIndexF);
+
+  ram8x32 ram(clk, reset, ITLBEntryIndex, PageTableEntryF, ITLBWriteF, PTEMatchF);
+  cam8x21 cam(clk, reset, ITLBWriteF, VirtualPageNumberF, WriteIndexF,
+    ITLBFlushF, VPNIndexF, ITLBHitF);
+
+  always_comb begin
+    assign PhysicalPageNumberF = PTEMatchF[31:10];
+
+    if (ITLBHitF) begin
+      assign PhysicalAddressF = {PhysicalPageNumberF, PageOffsetF};
+    end else begin
+      assign PhysicalAddressF = 34'b0;
+    end
+  end
+
+  assign PCPF = PhysicalAddressF[31:0];
+  assign ITLBMissF = ~ITLBHitF & ~(ITLBWriteF | ITLBFlushF);
+
+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,
+
+  output [31:0] out_data
+);
+
+  logic [31:0] ram [0:7];
+  always @(posedge clk) begin
+    if (we) ram[address] <= data;
+  end
+
+  assign out_data = ram[address];
+    
+  initial begin
+    for (int i = 0; i < 8; i++)
+      ram[i] = 32'h0;
+  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
+);
+
+  logic [20:0] ram [0:7];
+  logic [7:0] match_line;
+
+  logic [2: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;
+    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 = i;
+        match_found_comb = 1;
+      end else begin
+        matched_address_comb = matched_address_comb;
+        match_found_comb = match_found_comb;
+      end
+    end
+  end
+
+  assign matched_address = matched_address_comb;
+  assign match_found = match_found_comb & ~(we | ITLBFlushF);
+
+  initial begin
+    for (int i = 0; i < 8; 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 (
+  input        clk, reset,
+  output [2:0] WriteIndexF
+);
+
+  logic [31:0] data;
+  assign data = $urandom;
+  assign WriteIndexF = data[2:0];
+  
+endmodule
diff --git a/wally-pipelined/src/tlb_toy/tlb_toy.tv b/wally-pipelined/src/tlb_toy/tlb_toy.tv
new file mode 100644
index 000000000..329f3aacc
--- /dev/null
+++ b/wally-pipelined/src/tlb_toy/tlb_toy.tv
@@ -0,0 +1,11 @@
+// tlb_toy.tv
+// PCF _ PageTableEntryF _ ITLBWriteF _ ITLBFlushF ___ PCPF _ ITLBMissF _ ITLBHitF
+10101010101010101010101010101010_00000000000000000000000000000000_0_0___00000000000000000000000000000000_1_0
+// Write test: Add translation aaaaa -> 044444 to TLB
+10101010101010101010101010101010_00010001000100010001001100110010_1_0___00000000000000000000000000000000_0_0
+10101010101010101010101010101010_00000000000000000000000000000000_0_0___01000100010001000100101010101010_0_1
+10101010101010101010101010101010_00000000000000000000000000000000_0_0___01000100010001000100101010101010_0_1
+10101010100010101010101010101010_00000000000000000000000000000000_0_0___00000000000000000000000000000000_1_0
+// Flush test: should invalidate all entries
+00000000000000000000000000000000_00000000000000000000000000000000_0_1___00000000000000000000000000000000_0_0
+10101010101010101010101010101010_00000000000000000000000000000000_0_0___00000000000000000000000000000000_1_0

From 347275e7eeb7aa163273199a0ec858ff5e625d4e Mon Sep 17 00:00:00 2001
From: Thomas Fleming <tfleming@hmc.edu>
Date: Thu, 4 Mar 2021 01:13:31 -0500
Subject: [PATCH 2/3] Generalize tlb module

- number of tlb entries is now parameterized
- tlb now supports rv64i
---
 wally-pipelined/src/tlb_toy/tlb_testbench.sv |  23 +--
 wally-pipelined/src/tlb_toy/tlb_toy.sv       | 179 +++++++++++--------
 2 files changed, 115 insertions(+), 87 deletions(-)

diff --git a/wally-pipelined/src/tlb_toy/tlb_testbench.sv b/wally-pipelined/src/tlb_toy/tlb_testbench.sv
index add65d3db..4e2c71997 100644
--- a/wally-pipelined/src/tlb_toy/tlb_testbench.sv
+++ b/wally-pipelined/src/tlb_toy/tlb_testbench.sv
@@ -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;
diff --git a/wally-pipelined/src/tlb_toy/tlb_toy.sv b/wally-pipelined/src/tlb_toy/tlb_toy.sv
index 43c94babe..cafc15faf 100644
--- a/wally-pipelined/src/tlb_toy/tlb_toy.sv
+++ b/wally-pipelined/src/tlb_toy/tlb_toy.sv
@@ -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

From 5f98c932bf61c9af785e675ff2621d2ef1968a6e Mon Sep 17 00:00:00 2001
From: Thomas Fleming <tfleming@hmc.edu>
Date: Thu, 4 Mar 2021 02:39:08 -0500
Subject: [PATCH 3/3] Move tlb into mmu directory

---
 wally-pipelined/src/mmu/tlb.sv               | 233 +++++++++++++++++++
 wally-pipelined/src/tlb_toy/tlb_testbench.sv |   4 +-
 2 files changed, 236 insertions(+), 1 deletion(-)
 create mode 100644 wally-pipelined/src/mmu/tlb.sv

diff --git a/wally-pipelined/src/mmu/tlb.sv b/wally-pipelined/src/mmu/tlb.sv
new file mode 100644
index 000000000..cafc15faf
--- /dev/null
+++ b/wally-pipelined/src/mmu/tlb.sv
@@ -0,0 +1,233 @@
+///////////////////////////////////////////
+// tlb_toy.sv
+//
+// Written: jtorrey@hmc.edu 16 February 2021
+// Modified:
+//
+// Purpose: Example translation lookaside buffer
+//           Cache of virtural-to-physical address translations
+// 
+// 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"
+
+/**
+ * sv32 specs
+ * ----------
+ * Virtual address [31:0] (32 bits)
+ *    [________________________________]
+ *     |--VPN1--||--VPN0--||----OFF---|
+ *         10        10         12
+ * 
+ * Physical address [33:0] (34 bits)
+ *  [__________________________________]
+ *   |---PPN1---||--PPN0--||----OFF---|
+ *        12         10         12
+ * 
+ * Page Table Entry [31:0] (32 bits)
+ *    [________________________________]
+ *     |---PPN1---||--PPN0--|||DAGUXWRV
+ *          12         10    ^^
+ *                         RSW(2) -- for OS
+ */
+
+/* *** TODO:
+ * - add LRU algorithm (select the write index based on which entry was used
+ *   least recently)
+ */
+
+// 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  [`XLEN-1:0] VirtualAddress,
+
+  // Controls for writing a new entry to the TLB
+  input  [`XLEN-1:0] PageTableEntryWrite,
+  input              TLBWrite,
+
+  // Invalidate all TLB entries
+  input              TLBFlush,
+
+  // Physical address outputs
+  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 [ENTRY_BITS-1:0] WriteIndex;
+
+  // Sections of the virtual and physical addresses
+  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 [ENTRY_BITS-1:0] VPNIndex;
+
+  // RAM access location
+  logic [ENTRY_BITS-1:0] EntryIndex;
+
+  // Page table entry matching the virtual address
+  logic [`XLEN-1:0] PageTableEntry;
+
+  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(VPNIndex, WriteIndex, TLBWrite, EntryIndex);
+
+  // Currently use random replacement algorithm
+  tlb_rand rdm(.*);
+
+  tlb_ram #(ENTRY_BITS) ram(.*);
+  tlb_cam #(ENTRY_BITS, ARCH.VPN_BITS) cam(.*);
+
+  always_comb begin
+    assign PhysicalPageNumber = PageTableEntry[ARCH.PPN_BITS+9:10];
+
+    if (TLBHit) begin
+      assign PhysicalAddressFull = {PhysicalPageNumber, PageOffset};
+    end else begin
+      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
+
+  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
+
+module tlb_ram #(parameter ENTRY_BITS = 3) (
+  input                   clk, reset,
+  input  [ENTRY_BITS-1:0] EntryIndex,
+  input  [`XLEN-1:0]      PageTableEntryWrite,
+  input                   TLBWrite,
+
+  output [`XLEN-1:0]      PageTableEntry
+);
+
+  localparam NENTRIES = 2**ENTRY_BITS;
+
+  logic [`XLEN-1:0] ram [0:NENTRIES-1];
+  always @(posedge clk) begin
+    if (TLBWrite) ram[EntryIndex] <= PageTableEntryWrite;
+  end
+
+  assign PageTableEntry = ram[EntryIndex];
+    
+  initial begin
+    for (int i = 0; i < NENTRIES; i++)
+      ram[i] = `XLEN'b0;
+  end
+
+endmodule
+
+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
+);
+
+  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 [ENTRY_BITS-1:0] matched_address_comb;
+  logic                  match_found_comb;
+
+  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
+    end
+  end
+
+  // *** 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
+
+  assign VPNIndex = matched_address_comb;
+  assign TLBHit = match_found_comb & ~(TLBWrite | TLBFlush);
+
+  initial begin
+    for (int i = 0; i < NENTRIES; i++)
+      ram[i] <= '0;
+  end
+
+endmodule
+
+module tlb_rand #(parameter ENTRY_BITS = 3) (
+  input        clk, reset,
+  output [ENTRY_BITS:0] WriteIndex
+);
+
+  logic [31:0] data;
+  assign data = $urandom;
+  assign WriteIndex = data[ENTRY_BITS:0];
+  
+endmodule
diff --git a/wally-pipelined/src/tlb_toy/tlb_testbench.sv b/wally-pipelined/src/tlb_toy/tlb_testbench.sv
index 4e2c71997..4aa30542e 100644
--- a/wally-pipelined/src/tlb_toy/tlb_testbench.sv
+++ b/wally-pipelined/src/tlb_toy/tlb_testbench.sv
@@ -1,4 +1,6 @@
-module testbench();
+`include "wally-config.vh"
+
+module tlb_testbench();
   logic clk, reset;
 
   // DUT inputs