X-Git-Url: https://git.libre-soc.org/?p=soc.git;a=blobdiff_plain;f=src%2Fsoc%2Fdecoder%2Fselectable_int.py;h=53e85036d444619d94f28e03d6f42de6dfcb8c76;hp=1227335e45256aadd2021a9d0475fcbdf86e4ba7;hb=5e3f4f16cdf9de7ebdaf5971f586475f5c623ca6;hpb=8ea804463351bc17032f450beadf3f20d42af84b diff --git a/src/soc/decoder/selectable_int.py b/src/soc/decoder/selectable_int.py index 1227335e..53e85036 100644 --- a/src/soc/decoder/selectable_int.py +++ b/src/soc/decoder/selectable_int.py @@ -1,7 +1,8 @@ import unittest from copy import copy from soc.decoder.power_fields import BitRange -from operator import (add, sub, mul, truediv, mod, or_, and_, xor, neg, inv) +from operator import (add, sub, mul, floordiv, truediv, mod, or_, and_, xor, + neg, inv, lshift, rshift) def check_extsign(a, b): @@ -17,14 +18,15 @@ def check_extsign(a, b): class FieldSelectableInt: """FieldSelectableInt: allows bit-range selection onto another target """ + def __init__(self, si, br): - self.si = si # target selectable int + self.si = si # target selectable int if isinstance(br, list) or isinstance(br, tuple): _br = BitRange() for i, v in enumerate(br): _br[i] = v br = _br - self.br = br # map of indices. + self.br = br # map of indices. def eq(self, b): if isinstance(b, SelectableInt): @@ -45,46 +47,62 @@ class FieldSelectableInt: return self.merge(vi) def __getitem__(self, key): - print ("getitem", key, self.br) + print("getitem", key, self.br) if isinstance(key, SelectableInt): key = key.value - key = self.br[key] # don't do POWER 1.3.4 bit-inversion - return self.si[key] + if isinstance(key, int): + key = self.br[key] # don't do POWER 1.3.4 bit-inversion + return self.si[key] + if isinstance(key, slice): + key = self.br[key] + return selectconcat(*[self.si[x] for x in key]) def __setitem__(self, key, value): if isinstance(key, SelectableInt): key = key.value - key = self.br[key] # don't do POWER 1.3.4 bit-inversion - return self.si.__setitem__(key, value) + key = self.br[key] # don't do POWER 1.3.4 bit-inversion + if isinstance(key, int): + return self.si.__setitem__(key, value) + else: + if not isinstance(value, SelectableInt): + value = SelectableInt(value, bits=len(key)) + for i, k in enumerate(key): + self.si[k] = value[i] def __negate__(self): return self._op1(negate) + def __invert__(self): return self._op1(inv) + def __add__(self, b): return self._op(add, b) + def __sub__(self, b): return self._op(sub, b) + def __mul__(self, b): return self._op(mul, b) + def __div__(self, b): return self._op(truediv, b) + def __mod__(self, b): return self._op(mod, b) + def __and__(self, b): return self._op(and_, b) + def __or__(self, b): return self._op(or_, b) + def __xor__(self, b): return self._op(xor, b) def get_range(self): - print ("get_range", self.si) vi = SelectableInt(0, len(self.br)) for k, v in self.br.items(): - print ("get_range", k, v, self.si[v]) vi[k] = self.si[v] - print ("get_range", vi) return vi def merge(self, vi): @@ -96,6 +114,13 @@ class FieldSelectableInt: def __repr__(self): return "FieldSelectableInt(si=%s, br=%s)" % (self.si, self.br) + def asint(self, msb0=False): + res = 0 + brlen = len(self.br) + for i, key in enumerate(self.br): + res |= self.si[key].value << ((brlen-i-1) if msb0 else i) + return res + class FieldSelectableIntTestCase(unittest.TestCase): def test_arith(self): @@ -107,61 +132,128 @@ class FieldSelectableIntTestCase(unittest.TestCase): br[2] = 3 fs = FieldSelectableInt(a, br) c = fs + b - print (c) + print(c) #self.assertEqual(c.value, a.value + b.value) + def test_select(self): + a = SelectableInt(0b00001111, 8) + br = BitRange() + br[0] = 0 + br[1] = 1 + br[2] = 4 + br[3] = 5 + fs = FieldSelectableInt(a, br) + + self.assertEqual(fs.get_range(), 0b0011) + + def test_select_range(self): + a = SelectableInt(0b00001111, 8) + br = BitRange() + br[0] = 0 + br[1] = 1 + br[2] = 4 + br[3] = 5 + fs = FieldSelectableInt(a, br) + + self.assertEqual(fs[2:4], 0b11) + + fs[0:2] = 0b10 + self.assertEqual(fs.get_range(), 0b1011) class SelectableInt: + """SelectableInt - a class that behaves exactly like python int + + this class is designed to mirror precisely the behaviour of python int. + the only difference is that it must contain the context of the bitwidth + (number of bits) associated with that integer. + + FieldSelectableInt can then operate on partial bits, and because there + is a bit width associated with SelectableInt, slices operate correctly + including negative start/end points. + """ + def __init__(self, value, bits): + if isinstance(value, SelectableInt): + value = value.value mask = (1 << bits) - 1 self.value = value & mask self.bits = bits + self.overflow = (value & ~mask) != 0 def eq(self, b): self.value = b.value self.bits = b.bits - def __add__(self, b): + def to_signed_int(self): + print ("to signed?", self.value & (1<<(self.bits-1)), self.value) + if self.value & (1<<(self.bits-1)) != 0: # negative + res = self.value - (1<> b.value, self.bits) def __getitem__(self, key): + if isinstance(key, SelectableInt): + key = key.value + print("getitem", key, self.bits, hex(self.value)) if isinstance(key, int): assert key < self.bits, "key %d accessing %d" % (key, self.bits) assert key >= 0 @@ -192,12 +297,15 @@ class SelectableInt: start = self.bits - key.stop bits = stop - start - #print ("__getitem__ slice num bits", bits) + #print ("__getitem__ slice num bits", start, stop, bits) mask = (1 << bits) - 1 value = (self.value >> start) & mask return SelectableInt(value, bits) def __setitem__(self, key, value): + if isinstance(key, SelectableInt): + key = key.value + print("setitem", key, self.bits, hex(self.value)) if isinstance(key, int): assert key < self.bits assert key >= 0 @@ -233,9 +341,9 @@ class SelectableInt: if isinstance(other, SelectableInt): other = check_extsign(self, other) assert other.bits == self.bits - other = other.value + other = other.to_signed_int() if isinstance(other, int): - return other >= self.value + return onebit(self.to_signed_int() >= other) assert False def __le__(self, other): @@ -244,9 +352,9 @@ class SelectableInt: if isinstance(other, SelectableInt): other = check_extsign(self, other) assert other.bits == self.bits - other = other.value + other = other.to_signed_int() if isinstance(other, int): - return onebit(other <= self.value) + return onebit(self.to_signed_int() <= other) assert False def __gt__(self, other): @@ -255,30 +363,35 @@ class SelectableInt: if isinstance(other, SelectableInt): other = check_extsign(self, other) assert other.bits == self.bits - other = other.value + other = other.to_signed_int() if isinstance(other, int): - return onebit(other > self.value) + return onebit(self.to_signed_int() > other) assert False def __lt__(self, other): + print ("SelectableInt lt", self, other) if isinstance(other, FieldSelectableInt): other = other.get_range() if isinstance(other, SelectableInt): other = check_extsign(self, other) assert other.bits == self.bits - other = other.value + other = other.to_signed_int() if isinstance(other, int): - return onebit(other < self.value) + a = self.to_signed_int() + res = onebit(a < other) + print (" a < b", a, other, res) + return res assert False def __eq__(self, other): - print ("__eq__", self, other) + print("__eq__", self, other) if isinstance(other, FieldSelectableInt): other = other.get_range() if isinstance(other, SelectableInt): other = check_extsign(self, other) assert other.bits == self.bits other = other.value + print (" eq", other, self.value, other == self.value) if isinstance(other, int): return onebit(other == self.value) assert False @@ -292,14 +405,19 @@ class SelectableInt: def __repr__(self): return "SelectableInt(value=0x{:x}, bits={})".format(self.value, - self.bits) + self.bits) def __len__(self): return self.bits + def asint(self): + return self.value + + def onebit(bit): return SelectableInt(1 if bit else 0, 1) + def selectltu(lhs, rhs): """ less-than (unsigned) """ @@ -307,6 +425,7 @@ def selectltu(lhs, rhs): rhs = rhs.value return onebit(lhs.value < rhs) + def selectgtu(lhs, rhs): """ greater-than (unsigned) """ @@ -324,7 +443,7 @@ def selectassign(lhs, idx, rhs): else: lower, upper, step = idx toidx = range(lower, upper, step) - fromidx = range(0, upper-lower, step) # XXX eurgh... + fromidx = range(0, upper-lower, step) # XXX eurgh... else: toidx = [idx] fromidx = [0] @@ -335,7 +454,7 @@ def selectassign(lhs, idx, rhs): def selectconcat(*args, repeat=1): if repeat != 1 and len(args) == 1 and isinstance(args[0], int): args = [SelectableInt(args[0], 1)] - if repeat != 1: # multiplies the incoming arguments + if repeat != 1: # multiplies the incoming arguments tmp = [] for i in range(repeat): tmp += args @@ -347,7 +466,7 @@ def selectconcat(*args, repeat=1): assert isinstance(i, SelectableInt), "can only concat SIs, sorry" res.bits += i.bits res.value = (res.value << i.bits) | i.value - print ("concat", repeat, res) + print("concat", repeat, res) return res @@ -359,6 +478,8 @@ class SelectableIntTestCase(unittest.TestCase): d = a - b e = a * b f = -a + g = abs(f) + h = abs(a) self.assertEqual(c.value, a.value + b.value) self.assertEqual(d.value, (a.value - b.value) & 0xFF) self.assertEqual(e.value, (a.value * b.value) & 0xFF) @@ -366,6 +487,8 @@ class SelectableIntTestCase(unittest.TestCase): self.assertEqual(c.bits, a.bits) self.assertEqual(d.bits, a.bits) self.assertEqual(e.bits, a.bits) + self.assertEqual(a.bits, f.bits) + self.assertEqual(a.bits, h.bits) def test_logic(self): a = SelectableInt(0x0F, 8) @@ -413,5 +536,22 @@ class SelectableIntTestCase(unittest.TestCase): b = eval(repr(a)) self.assertEqual(a, b) + def test_cmp(self): + a = SelectableInt(10, bits=8) + b = SelectableInt(5, bits=8) + self.assertTrue(a > b) + self.assertFalse(a < b) + self.assertTrue(a != b) + self.assertFalse(a == b) + + def test_unsigned(self): + a = SelectableInt(0x80, bits=8) + b = SelectableInt(0x7f, bits=8) + self.assertTrue(a > b) + self.assertFalse(a < b) + self.assertTrue(a != b) + self.assertFalse(a == b) + + if __name__ == "__main__": unittest.main()