selectable_int now in power ordering, add setitem
authorMichael Nolan <mtnolan2640@gmail.com>
Wed, 1 Apr 2020 18:22:28 +0000 (14:22 -0400)
committerMichael Nolan <mtnolan2640@gmail.com>
Wed, 1 Apr 2020 18:37:51 +0000 (14:37 -0400)
src/soc/decoder/selectable_int.py

index daa834ac26f5de64a87c729e83e224a383ea8d6a..ad3bfdc18d9ca3cb80d09e99af3f1ee2a1e7632c 100644 (file)
@@ -1,4 +1,6 @@
 import unittest
+
+
 class SelectableInt:
     def __init__(self, value, bits):
         self.value = value
@@ -12,6 +14,7 @@ class SelectableInt:
         if isinstance(key, int):
             assert key < self.bits
             assert key >= 0
+            key = self.bits - (key + 1)
 
             value = (self.value >> key) & 1
             return SelectableInt(value, 1)
@@ -21,11 +24,43 @@ class SelectableInt:
             assert key.start >= 0
             assert key.stop <= self.bits
 
-            bits = key.stop - key.start
+            stop = self.bits - key.start
+            start = self.bits - key.stop
+
+            bits = stop - start
             mask = (1 << bits) - 1
-            value = (self.value >> key.start) & mask
+            value = (self.value >> start) & mask
             return SelectableInt(value, bits)
-    
+
+    def __setitem__(self, key, value):
+        if isinstance(key, int):
+            assert key < self.bits
+            assert key >= 0
+            key = self.bits - (key + 1)
+            if isinstance(value, SelectableInt):
+                assert value.bits == 1
+                value = value.value
+
+            value = value << key
+            mask = 1 << key
+            self.value = (self.value & ~mask) | (value & mask)
+        elif isinstance(key, slice):
+            assert key.step is None or key.step == 1
+            assert key.start < key.stop
+            assert key.start >= 0
+            assert key.stop <= self.bits
+
+            stop = self.bits - key.start
+            start = self.bits - key.stop
+
+            bits = stop - start
+            if isinstance(value, SelectableInt):
+                assert value.bits == bits
+                value = value.value
+            mask = ((1 << bits) - 1) << start
+            value = value << start
+            self.value = (self.value & ~mask) | (value & mask)
+
     def __eq__(self, other):
         if isinstance(other, SelectableInt):
             return other.value == self.value and other.bits == self.bits
@@ -34,7 +69,8 @@ class SelectableInt:
         assert False
 
     def __repr__(self):
-        return "SelectableInt(value={:x}, bits={})".format(self.value, self.bits)
+        return "SelectableInt(value={:x}, bits={})".format(self.value,
+                                                           self.bits)
 
 
 class SelectableIntTestCase(unittest.TestCase):
@@ -45,12 +81,23 @@ class SelectableIntTestCase(unittest.TestCase):
         assert c.value == a.value + b.value
         assert c.bits == a.bits
 
-    def test_select(self):
-        a = SelectableInt(0xa5, 8)
-        assert a[0] == 1
-        assert a[0:1] == 1
-        assert a[0:4] == 5
-        assert a[4:8] == 10
+    def test_get(self):
+        a = SelectableInt(0xa2, 8)
+        # These should be big endian
+        assert a[7] == 0
+        assert a[0:4] == 10
+        assert a[4:8] == 2
+
+    def test_set(self):
+        a = SelectableInt(0x5, 8)
+        a[7] = SelectableInt(0, 1)
+        self.assertEqual(a, 4)
+        a[4:8] = 9
+        self.assertEqual(a, 9)
+        a[0:4] = 3
+        self.assertEqual(a, 0x39)
+        a[0:4] = a[4:8]
+        self.assertEqual(a, 0x99)
 
 
 if __name__ == "__main__":