implement page table lookup using 4 levels
authorisengaara <isengaara@anna>
Sun, 21 Jul 2019 11:31:43 +0000 (13:31 +0200)
committerisengaara <isengaara@anna>
Sun, 21 Jul 2019 11:31:43 +0000 (13:31 +0200)
src/TLB/ariane/mmu.py
src/TLB/ariane/ptw.py
src/TLB/ariane/test/test_ptw.py
src/TLB/ariane/tlb.py
src/TLB/ariane/tlb_content.py

index c0739cc00a25997bd3ed7d1cf0b64a575b362752..77838d1089463a6ea0a441786ebf3c1f92438954 100644 (file)
@@ -12,8 +12,8 @@
 # Author: Florian Zaruba, ETH Zurich
 # Date: 19/04/2017
 # Description: Memory Management Unit for Ariane, contains TLB and
-#              address translation unit. SV39 as defined in RISC-V
-#              privilege specification 1.11-WIP
+#              address translation unit. SV48 as defined in
+#              Volume II: RISC-V Privileged Architectures V1.10 Page 63
 
 import ariane_pkg::*;
 """
@@ -139,7 +139,7 @@ class MMU:
         walking_instr = Signal() # PTW is walking because of an ITLB miss
         ptw_error = Signal()     # PTW threw an exception
 
-        update_vaddr = Signal(39)
+        update_vaddr = Signal(48)                                # guessed
         uaddr64 = Cat(update_vaddr, Const(0, 25)) # extend to 64bit with zeros
         update_ptw_itlb = TLBUpdate(self.asid_width)
         update_ptw_dtlb = TLBUpdate(self.asid_width)
@@ -264,7 +264,7 @@ class MMU:
         # or when PTW performs walk due to ITLB miss and raises
         # an error.
         with m.If (self.enable_translation_i):
-            # we work with SV39, so if VM is enabled, check that
+            # we work with SV48, so if VM is enabled, check that
             # all bits [63:38] are equal
             with m.If (self.icache_areq_i.fetch_req & \
                 ~(((~self.icache_areq_i.fetch_vaddr[38:64]) == 0) | \
index ace44d146d920b22bf3b5cebd5b22f2f4135529f..c632194ac994bfc392f597023424a8b4a1c0ffee 100644 (file)
@@ -147,10 +147,11 @@ class TLBUpdate:
                 self.content.ports()
 
 
-# SV39 defines three levels of page tables
+# SV48 defines four levels of page tables
 LVL1 = Const(0, 2) # defined to 0 so that ptw_lvl default-resets to LVL1
 LVL2 = Const(1, 2)
 LVL3 = Const(2, 2)
+LVL4 = Const(3, 2)
 
 
 class PTW(Elaboratable):
@@ -163,7 +164,7 @@ class PTW(Elaboratable):
         self.ptw_active_o = Signal(reset=1)    # active if not IDLE
         self.walking_instr_o = Signal()        # set when walking for TLB
         self.ptw_error_o = Signal()            # set when an error occurred
-        self.enable_translation_i = Signal()   # CSRs indicate to enable SV39
+        self.enable_translation_i = Signal()   # CSRs indicate to enable SV48
         self.en_ld_st_translation_i = Signal() # enable VM translation for ld/st
 
         self.lsu_is_store_i = Signal()       # translation triggered by store
@@ -175,7 +176,7 @@ class PTW(Elaboratable):
         self.itlb_update_o = TLBUpdate(asid_width)
         self.dtlb_update_o = TLBUpdate(asid_width)
 
-        self.update_vaddr_o = Signal(39)
+        self.update_vaddr_o = Signal(48)
 
         self.asid_i = Signal(self.asid_width)
         # from TLBs
@@ -220,14 +221,17 @@ class PTW(Elaboratable):
         pte = PTE()
         m.d.comb += pte.flatten().eq(data_rdata)
 
-        # SV39 defines three levels of page tables
+        # SV48 defines four levels of page tables
         ptw_lvl = Signal(2) # default=0=LVL1 on reset (see above)
         ptw_lvl1 = Signal()
         ptw_lvl2 = Signal()
         ptw_lvl3 = Signal()
+        ptw_lvl4 = Signal()
         m.d.comb += [ptw_lvl1.eq(ptw_lvl == LVL1),
                      ptw_lvl2.eq(ptw_lvl == LVL2),
-                     ptw_lvl3.eq(ptw_lvl == LVL3)]
+                     ptw_lvl3.eq(ptw_lvl == LVL3),
+                     ptw_lvl4.eq(ptw_lvl == LVL4)
+                     ]
 
         # is this an instruction page table walk?
         is_instr_ptw = Signal()
@@ -236,7 +240,7 @@ class PTW(Elaboratable):
         tag_valid = Signal()
         # register the ASID
         tlb_update_asid = Signal(self.asid_width)
-        # register VPN we need to walk, SV39 defines a 39 bit virtual addr
+        # register VPN we need to walk, SV48 defines a 48 bit virtual addr
         vaddr = Signal(64)
         # 4 byte aligned physical pointer
         ptw_pptr = Signal(56)
@@ -257,8 +261,9 @@ class PTW(Elaboratable):
             # -----------
             # TLB Update
             # -----------
-            self.itlb_update_o.vpn.eq(vaddr[12:39]),
-            self.dtlb_update_o.vpn.eq(vaddr[12:39]),
+            self.itlb_update_o.vpn.eq(vaddr[12:48]),
+            self.dtlb_update_o.vpn.eq(vaddr[12:48]),
+            #TODO_PLATEN: extend by 9 bits
             # update the correct page table level
             self.itlb_update_o.is_2M.eq(ptw_lvl2),
             self.itlb_update_o.is_1G.eq(ptw_lvl1),
@@ -277,12 +282,12 @@ class PTW(Elaboratable):
         ]
 
         #-------------------
-        # Page table walker
+        # Page table walker   #needs update
         #-------------------
         # A virtual address va is translated into a physical address pa as
         # follows:
-        # 1. Let a be sptbr.ppn × PAGESIZE, and let i = LEVELS-1. (For Sv39,
-        #    PAGESIZE=2^12 and LEVELS=3.)
+        # 1. Let a be sptbr.ppn × PAGESIZE, and let i = LEVELS-1. (For Sv48,
+        #    PAGESIZE=2^12 and LEVELS=4.)
         # 2. Let pte be the value of the PTE at address a+va.vpn[i]×PTESIZE.
         #    (For Sv32, PTESIZE=4.)
         # 3. If pte.v = 0, or if pte.r = 0 and pte.w = 1, stop and raise an
@@ -338,7 +343,7 @@ class PTW(Elaboratable):
             with m.State("PTE_LOOKUP"):
                 # we wait for the valid signal
                 with m.If(data_rvalid):
-                    self.lookup(m, pte, ptw_lvl, ptw_lvl1, ptw_lvl2, ptw_lvl3,
+                    self.lookup(m, pte, ptw_lvl, ptw_lvl1, ptw_lvl2, ptw_lvl3, ptw_lvl4,
                                 data_rvalid, global_mapping,
                                 is_instr_ptw, ptw_pptr)
 
@@ -387,7 +392,7 @@ class PTW(Elaboratable):
                                         ~self.dtlb_hit_i)
         # we got an ITLB miss?
         with m.If(self.itlb_miss_o):
-            pptr = Cat(Const(0, 3), self.itlb_vaddr_i[30:39],
+            pptr = Cat(Const(0, 3), self.itlb_vaddr_i[30:48],
                        self.satp_ppn_i)
             m.d.sync += [ptw_pptr.eq(pptr),
                          is_instr_ptw.eq(1),
@@ -398,7 +403,7 @@ class PTW(Elaboratable):
 
         # we got a DTLB miss?
         with m.Elif(self.dtlb_miss_o):
-            pptr = Cat(Const(0, 3), self.dtlb_vaddr_i[30:39],
+            pptr = Cat(Const(0, 3), self.dtlb_vaddr_i[30:48],
                        self.satp_ppn_i)
             m.d.sync += [ptw_pptr.eq(pptr),
                          vaddr.eq(self.dtlb_vaddr_i),
@@ -426,7 +431,7 @@ class PTW(Elaboratable):
             with m.Else():
                 m.next = "PTE_LOOKUP"
 
-    def lookup(self, m, pte, ptw_lvl, ptw_lvl1, ptw_lvl2, ptw_lvl3,
+    def lookup(self, m, pte, ptw_lvl, ptw_lvl1, ptw_lvl2, ptw_lvl3, ptw_lvl4, 
                             data_rvalid, global_mapping,
                             is_instr_ptw, ptw_pptr):
         # temporaries
@@ -513,22 +518,29 @@ class PTW(Elaboratable):
             # pointer to next level of page table
             with m.If (ptw_lvl1):
                 # we are in the second level now
-                pptr = Cat(Const(0, 3), self.dtlb_vaddr_i[21:30], pte.ppn)
+                pptr = Cat(Const(0, 3), self.dtlb_vaddr_i[30:39], pte.ppn)
                 m.d.sync += [ptw_pptr.eq(pptr),
                              ptw_lvl.eq(LVL2)
                             ]
             with m.If(ptw_lvl2):
                 # here we received a pointer to the third level
-                pptr = Cat(Const(0, 3), self.dtlb_vaddr_i[12:21], pte.ppn)
+                pptr = Cat(Const(0, 3), self.dtlb_vaddr_i[21:30], pte.ppn)
                 m.d.sync += [ptw_pptr.eq(pptr),
                              ptw_lvl.eq(LVL3)
                             ]
+            with m.If(ptw_lvl3): #guess: shift page levels by one
+                # here we received a pointer to the fourth level
+                # the last one is near the page offset
+                pptr = Cat(Const(0, 3), self.dtlb_vaddr_i[12:21], pte.ppn)
+                m.d.sync += [ptw_pptr.eq(pptr),
+                             ptw_lvl.eq(LVL4)
+                            ]
             self.set_grant_state(m)
 
-            with m.If (ptw_lvl3):
+            with m.If (ptw_lvl4):
                 # Should already be the last level
                 # page table => Error
-                m.d.sync += ptw_lvl.eq(LVL3)
+                m.d.sync += ptw_lvl.eq(LVL4)
                 m.next = "PROPAGATE_ERROR"
 
 
index 7a8a893dd161e8504ceca24fc59af535b7fc1006..b5deb28b5ab607eb6a9a2f4543585683dd998f23 100644 (file)
@@ -6,6 +6,7 @@ from nmigen.compat.sim import run_simulation
 
 from TLB.ariane.ptw import PTW, PTE
 
+# unit was changed, test needs to be changed
 
 def tbench(dut):
 
index 31505118e5fe2a55f9d5ae55773ddd8be92be5fc..1f1fa86c5abe419a926f7cc7ca4058af40c061df 100644 (file)
@@ -12,7 +12,7 @@
 # Author: David Schaffenrath, TU Graz
 # Author: Florian Zaruba, ETH Zurich
 # Date: 21.4.2017
-# Description: Translation Lookaside Buffer, SV39
+# Description: Translation Lookaside Buffer, SV48
 #              fully set-associative
 
 Implementation in c++:
@@ -56,6 +56,7 @@ class TLB:
     def elaborate(self, platform):
         m = Module()
 
+        vpn3 = Signal(9) #FIXME unused signal
         vpn2 = Signal(9)
         vpn1 = Signal(9)
         vpn0 = Signal(9)
@@ -64,10 +65,11 @@ class TLB:
         # Translation
         #-------------
 
-        # SV39 defines three levels of page tables
+        # SV48 defines four levels of page tables
         m.d.comb += [ vpn0.eq(self.lu_vaddr_i[12:21]),
                       vpn1.eq(self.lu_vaddr_i[21:30]),
-                      vpn2.eq(self.lu_vaddr_i[30:39]),
+                      vpn2.eq(self.lu_vaddr_i[30:39]),      ### PLATEN ### OK
+                      vpn3.eq(self.lu_vaddr_i[39:48]),      ### PLATEN ### now using SV48
                     ]
 
         tc = []
@@ -80,6 +82,7 @@ class TLB:
             m.d.comb += [tlc.vpn0.eq(vpn0),
                          tlc.vpn1.eq(vpn1),
                          tlc.vpn2.eq(vpn2),
+                         # TODO 4th
                          tlc.flush_i.eq(self.flush_i),
                          #tlc.update_i.eq(self.update_i),
                          tlc.lu_asid_i.eq(self.lu_asid_i)]
index 5c005b84bbf97d98b6879f71d4adbb6ed888aa61..c4f03ed337e41ed5ce2e78e67dfe4b2b1b995d3b 100644 (file)
@@ -6,10 +6,12 @@ from TLB.ariane.ptw import TLBUpdate, PTE
 class TLBEntry:
     def __init__(self, asid_width):
         self.asid = Signal(asid_width)
-        # SV39 defines three levels of page tables
+        # SV48 defines four levels of page tables
         self.vpn0 = Signal(9)
         self.vpn1 = Signal(9)
         self.vpn2 = Signal(9)
+        self.vpn3 = Signal(9)
+        #TODO_PLATEN: use that signal
         self.is_2M = Signal()
         self.is_1G = Signal()
         self.valid = Signal()