split out new_lookup function
[soc.git] / src / soc / decoder / isa / radixmmu.py
index 528932b869b4776a7a5e7549d4d525111b5a20b8..fa03fa125b2d927fa30f03af1fa489b211322175 100644 (file)
@@ -212,15 +212,20 @@ class RADIX:
         print("RADIX memread", addr, sz, val)
         return SelectableInt(val, sz*8)
 
-    def ld(self, address, width=8, swap=True, check_in_mem=False):
+    def ld(self, address, width=8, swap=True, check_in_mem=False,
+                 instr_fetch=False):
         print("RADIX: ld from addr 0x%x width %d" % (address, width))
 
-        mode = 'LOAD' # XXX TODO: executable load (icache)
+        priv = 1 # XXX TODO: read MSR PR bit here priv = not ctrl.msr(MSR_PR);
+        if instr_fetch:
+            mode = 'EXECUTE'
+        else:
+            mode = 'LOAD'
         addr = SelectableInt(address, 64)
         (shift, mbits, pgbase) = self._decode_prte(addr)
         #shift = SelectableInt(0, 32)
 
-        pte = self._walk_tree(addr, pgbase, mode, mbits, shift)
+        pte = self._walk_tree(addr, pgbase, mode, mbits, shift, priv)
         # use pte to caclculate phys address
         return self.mem.ld(address, width, swap, check_in_mem)
 
@@ -230,10 +235,11 @@ class RADIX:
     def st(self, address, v, width=8, swap=True):
         print("RADIX: st to addr 0x%x width %d data %x" % (address, width, v))
 
+        priv = 1 # XXX TODO: read MSR PR bit here priv = not ctrl.msr(MSR_PR);
         mode = 'STORE'
         addr = SelectableInt(address, 64)
         (shift, mbits, pgbase) = self._decode_prte(addr)
-        pte = self._walk_tree(addr, pgbase, mode, mbits, shift)
+        pte = self._walk_tree(addr, pgbase, mode, mbits, shift, priv)
 
         # use pte to caclculate phys address (addr)
         return self.mem.st(addr.value, v, width, swap)
@@ -251,7 +257,7 @@ class RADIX:
         ## DSISR_NOPTE
         ## Prepare for next iteration
 
-    def _walk_tree(self, addr, pgbase, mode, mbits, shift):
+    def _walk_tree(self, addr, pgbase, mode, mbits, shift, priv=1):
         """walk tree
 
         // vaddr                    64 Bit
@@ -337,6 +343,7 @@ class RADIX:
         check_in_mem = False
         entry_width = 8
         value = self.mem.ld(prtable_addr.value, entry_width, swap, check_in_mem)
+        data = SelectableInt(value, 64) # convert to SelectableInt
         print("value",value)
 
         test_input = [
@@ -350,30 +357,45 @@ class RADIX:
             print("nextlevel----------------------------")
             l = test_input[index]
             index += 1
-            valid,leaf = self._next_level(l)
-            if not leaf:
-                mbits = l[59:64]
-                print("mbits=")
-                print(mbits)
-                if mbits < 5 or mbits > 16:
-                    print("badtree")
+            valid, leaf = self._next_level(l)
+            print("    valid, leaf", valid, leaf)
+            if leaf:
+                ok = self._check_perms(data, priv, mode)
+                # TODO: check permissions
+            else:
+                data = l # TODO put actual data here
+                newlookup = self._new_lookup(data, mbits, shift)
+                if newlookup == 'badtree':
                     return None
-                """
-                mbits := unsigned('0' & data(4 downto 0));
-                if mbits < 5 or mbits > 16 or mbits > r.shift then
-                    v.state := RADIX_FINISH;
-                    v.badtree := '1'; -- throw error
-                else
-                    v.shift := v.shift - mbits;
-                    v.mask_size := mbits(4 downto 0);
-                    v.pgbase := data(55 downto 8) & x"00"; NLB?
-                    v.state := RADIX_LOOKUP; --> next level
-                end if;
-                """
-            print(valid)
-            print(leaf)
-            if not valid: return None
-            if leaf: return None
+                shift, mask, pgbase = newlookup
+                print ("   next level", shift, mask, pgbase)
+            if not valid:
+                return None # TODO: return error
+            if leaf:
+                return None # TODO return something
+
+    def _new_lookup(self, data, mbits, shift):
+        """
+        mbits := unsigned('0' & data(4 downto 0));
+        if mbits < 5 or mbits > 16 or mbits > r.shift then
+            v.state := RADIX_FINISH;
+            v.badtree := '1'; -- throw error
+        else
+            v.shift := v.shift - mbits;
+            v.mask_size := mbits(4 downto 0);
+            v.pgbase := data(55 downto 8) & x"00"; NLB?
+            v.state := RADIX_LOOKUP; --> next level
+        end if;
+        """
+        mbits = data[59:64]
+        print("mbits=", mbits)
+        if mbits < 5 or mbits > 16:
+            print("badtree")
+            return "badtree"
+        shift = shift - mbits
+        mask_size = mbits[1:5] # get 4 LSBs
+        pgbase = selectconcat(data[8:56], SelectableInt(0, 8)) # shift up 8
+        return shift, mask_size, pgbase
 
     def _decode_prte(self, data):
         """PRTE0 Layout
@@ -426,7 +448,7 @@ class RADIX:
         new_shift = shift + (31 - 12) - mbits
         return new_shift
 
-    def _check_perms(self, data, priv, iside, store):
+    def _check_perms(self, data, priv, mode):
         """check page permissions
         // Leaf PDE                                           |
         // |------------------------------|           |----------------|
@@ -471,10 +493,17 @@ class RADIX:
                             v.rc_error := perm_ok;
                         end if;
         """
+        # decode mode into something that matches microwatt equivalent code
+        instr_fetch, store = 0, 0
+        if mode == 'STORE':
+            store = 1
+        if mode == 'EXECUTE':
+            inst_fetch = 1
+
         # check permissions and RC bits
         perm_ok = 0
         if priv == 1 or data[60] == 0:
-            if iside == 0:
+            if instr_fetch == 0:
                 perm_ok = data[62] | (data[61] & (store == 0))
             # no IAMR, so no KUEP support for now
             # deny execute permission if cache inhibited
@@ -482,6 +511,7 @@ class RADIX:
         rc_ok = data[55] & (data[56] | (store == 0))
         if perm_ok == 1 and rc_ok == 1:
             return True
+
         return "perm_err" if perm_ok == 0 else "rc_err"
 
     def _get_prtable_addr(self, shift, prtbl, addr, pid):