add is_512G to the data structure
[soc.git] / src / TLB / ariane / ptw.py
index 05ec2d7d55f42d35df6865fb856ce74c3bb3831f..706d6518f7fb9418f4af80d41bd2ca65f21c0510 100644 (file)
@@ -25,7 +25,7 @@ see linux kernel source:
 
 """
 
-from nmigen import Const, Signal, Cat, Module
+from nmigen import Const, Signal, Cat, Module, Elaboratable
 from nmigen.hdl.ast import ArrayProxy
 from nmigen.cli import verilog, rtlil
 from math import log2
@@ -132,6 +132,7 @@ class TLBUpdate:
         self.valid = Signal()      # valid flag
         self.is_2M = Signal()
         self.is_1G = Signal()
+        self.is_512G = Signal()
         self.vpn = Signal(27)
         self.asid = Signal(asid_width)
         self.content = PTE()
@@ -147,13 +148,14 @@ 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:
+class PTW(Elaboratable):
     def __init__(self, asid_width=8):
         self.asid_width = asid_width
 
@@ -163,7 +165,7 @@ class PTW:
         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 +177,7 @@ class PTW:
         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 +222,17 @@ class PTW:
         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 +241,7 @@ class PTW:
         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,13 +262,16 @@ class PTW:
             # -----------
             # 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]),
             # update the correct page table level
-            self.itlb_update_o.is_2M.eq(ptw_lvl2),
-            self.itlb_update_o.is_1G.eq(ptw_lvl1),
-            self.dtlb_update_o.is_2M.eq(ptw_lvl2),
-            self.dtlb_update_o.is_1G.eq(ptw_lvl1),
+            self.itlb_update_o.is_2M.eq(ptw_lvl3),
+            self.itlb_update_o.is_1G.eq(ptw_lvl2),
+            self.itlb_update_o.is_512G.eq(ptw_lvl1),
+            self.dtlb_update_o.is_2M.eq(ptw_lvl3),
+            self.dtlb_update_o.is_1G.eq(ptw_lvl2),
+            self.dtlb_update_o.is_512G.eq(ptw_lvl1),
+            
             # output the correct ASID
             self.itlb_update_o.asid.eq(tlb_update_asid),
             self.dtlb_update_o.asid.eq(tlb_update_asid),
@@ -277,12 +285,12 @@ class PTW:
         ]
 
         #-------------------
-        # 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 +346,7 @@ class PTW:
             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 +395,7 @@ class PTW:
                                         ~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 +406,7 @@ class PTW:
 
         # 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 +434,7 @@ class PTW:
             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
@@ -443,8 +451,9 @@ class PTW:
 
         l1err = Signal(reset_less=True)
         l2err = Signal(reset_less=True)
-        m.d.comb += [l2err.eq((ptw_lvl2) & pte.ppn[0:9] != Const(0, 9)),
-                     l1err.eq((ptw_lvl1) & pte.ppn[0:18] != Const(0, 18)) ]
+        m.d.comb += [l3err.eq((ptw_lvl3) & pte.ppn[0:9] != Const(0,0)),
+                     l2err.eq((ptw_lvl2) & pte.ppn[0:18] != Const(0, 18)),
+                     l1err.eq((ptw_lvl1) & pte.ppn[0:27] != Const(0, 27))]
 
         # check if the global mapping bit is set
         with m.If (pte.g):
@@ -503,7 +512,7 @@ class PTW:
                     m.next = "PROPAGATE_ERROR"
 
             # check if the ppn is correctly aligned: Case (6)
-            with m.If(l1err | l2err):
+            with m.If(l1err | l2err | l3err):
                 m.next = "PROPAGATE_ERROR"
                 m.d.comb += [self.dtlb_update_o.valid.eq(0),
                              self.itlb_update_o.valid.eq(0)]
@@ -513,22 +522,29 @@ class PTW:
             # 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"