neg, inv, lshift, rshift, lt, eq)
from openpower.util import log
+EFFECTIVELY_UNLIMITED = 1024
def check_extsign(a, b):
if isinstance(b, FieldSelectableInt):
b = b.get_range()
if isinstance(b, int):
return SelectableInt(b, a.bits)
- if b.bits != 256:
+ if b.bits != EFFECTIVELY_UNLIMITED:
return b
return SelectableInt(b.value, a.bits)
self.br = br # map of indices
def eq(self, b):
- if isinstance(b, int):
- # convert integer to same SelectableInt of same bitlength as range
- blen = len(self.br)
- b = SelectableInt(b, blen)
- for i in range(b.bits):
- self[i] = b[i]
- elif isinstance(b, SelectableInt):
- for i in range(b.bits):
- self[i] = b[i]
- else:
- self.si = copy(b.si)
- self.br = copy(b.br)
+ if not isinstance(b, SelectableInt):
+ b = SelectableInt(b, len(self.br))
+ for i in range(b.bits):
+ self[i] = b[i]
def _op(self, op, b):
vi = self.get_range()
return len(self.br)
def __getitem__(self, key):
- log("getitem", key, self.br)
+ #log("getitem", key, self.br)
if isinstance(key, SelectableInt):
key = key.value
res = 0
brlen = len(self.br)
for i, key in self.br.items():
- log("asint", i, key, self.si[key])
+ #log("asint", i, key, self.si[key])
bit = self.si[key].value
#log("asint", i, key, bit)
res |= bit << ((brlen-i-1) if msb0 else i)
self.assertEqual(fs.get_range(), 0b1011)
+@functools.total_ordering
class SelectableInt:
"""SelectableInt - a class that behaves exactly like python int
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.
+
+ value: int
+ the bits contained by `self`
+ bits: int
+ the number of bits contained by `self`.
+ ok: bool
+ a flag to detect if outputs have been written by pseudo-code
+
+ instruction inputs have `ok` set to `False`, all changed or new
+ SelectableInt instances set `ok` to `True`.
"""
- def __init__(self, value, bits=None):
+ def __init__(self, value, bits=None, *, ok=True):
+ if isinstance(value, FieldSelectableInt):
+ value = value.get_range()
if isinstance(value, SelectableInt):
if bits is not None:
# check if the bitlength is different. TODO, allow override?
raise ValueError(value)
bits = value.bits
value = value.value
- elif isinstance(value, FieldSelectableInt):
- if bits is not None:
- raise ValueError(value)
- bits = len(value.br)
- value = value.si.value
+ # intentionally don't copy ok
else:
if not isinstance(value, int):
raise ValueError(value)
self.value = value & mask
self.bits = bits
self.overflow = (value & ~mask) != 0
+ self.ok = ok
def eq(self, b):
self.value = b.value
self.bits = b.bits
+ self.ok = True
def to_signed_int(self):
log ("to signed?", self.value & (1<<(self.bits-1)), self.value)
def __rsub__(self, b):
log("rsub", b, self.value)
if isinstance(b, int):
- b = SelectableInt(b, 256) # max extent
+ b = SelectableInt(b, EFFECTIVELY_UNLIMITED) # max extent
#b = check_extsign(self, b)
#assert b.bits == self.bits
return SelectableInt(b.value - self.value, b.bits)
return SelectableInt(self.value >> b.value, self.bits)
def __getitem__(self, key):
- log ("SelectableInt.__getitem__", self, key, type(key))
+ #log ("SelectableInt.__getitem__", self, key, type(key))
if isinstance(key, SelectableInt):
key = key.value
if isinstance(key, int):
key = self.bits - (key + 1)
value = (self.value >> key) & 1
- log("getitem", key, self.bits, hex(self.value), value)
+ #log("getitem", key, self.bits, hex(self.value), value)
return SelectableInt(value, 1)
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
-
+ start = key.start
+ if isinstance(start, SelectableInt):
+ start = start.value
+ stop = key.stop
+ if isinstance(stop, SelectableInt):
+ stop = stop.value
+ step = key.step
+ if isinstance(step, SelectableInt):
+ step = step.value
+
+ assert step is None or step == 1
+ assert start < stop
+ assert start >= 0
+ assert stop <= self.bits
+
+ (start, stop) = (
+ (self.bits - stop),
+ (self.bits - start),
+ )
bits = stop - start
- log ("__getitem__ slice num bits", start, stop, bits)
+ #log ("__getitem__ slice num bits", start, stop, bits)
mask = (1 << bits) - 1
value = (self.value >> start) & mask
- log("getitem", stop, start, self.bits, hex(self.value), value)
+ #log("getitem", stop, start, self.bits, hex(self.value), value)
return SelectableInt(value, bits)
else:
bits = []
- key = tuple(key)
for bit in key:
if not isinstance(bit, (int, SelectableInt)):
raise ValueError(key)
return selectconcat(*bits)
def __setitem__(self, key, value):
+ self.ok = True
if isinstance(key, SelectableInt):
key = key.value
if isinstance(key, int):
if isinstance(value, SelectableInt):
assert value.bits == 1
value = value.value
- log("setitem", key, self.bits, hex(self.value), hex(value))
+ #log("setitem", key, self.bits, hex(self.value), hex(value))
assert key < self.bits
assert key >= 0
if isinstance(kstart, SelectableInt): kstart = kstart.asint()
if isinstance(kstop, SelectableInt): kstop = kstop.asint()
if isinstance(kstep, SelectableInt): kstep = kstep.asint()
- log ("__setitem__ slice ", kstart, kstop, kstep)
+ #log ("__setitem__ slice ", kstart, kstop, kstep)
assert kstep is None or kstep == 1
assert kstart < kstop
assert kstart >= 0
if isinstance(value, SelectableInt):
assert value.bits == bits, "%d into %d" % (value.bits, bits)
value = value.value
- log("setitem", key, self.bits, hex(self.value), hex(value))
+ #log("setitem", key, self.bits, hex(self.value), hex(value))
mask = ((1 << bits) - 1) << start
value = value << start
self.value = (self.value & ~mask) | (value & mask)
else:
- raise ValueError(key)
-
- def __ge__(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.to_signed_int()
- if isinstance(other, int):
- return onebit(self.to_signed_int() >= other)
- assert False
+ bits = []
+ for bit in key:
+ if not isinstance(bit, (int, SelectableInt)):
+ raise ValueError(key)
+ bits.append(bit)
- def __le__(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.to_signed_int()
- if isinstance(other, int):
- return onebit(self.to_signed_int() <= other)
- assert False
+ if isinstance(value, int):
+ if value.bit_length() > len(bits):
+ raise ValueError(value)
+ value = SelectableInt(value=value, bits=len(bits))
+ if not isinstance(value, SelectableInt):
+ raise ValueError(value)
- def __gt__(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.to_signed_int()
- if isinstance(other, int):
- return onebit(self.to_signed_int() > other)
- assert False
+ for (src, dst) in enumerate(bits):
+ self[dst] = value[src]
def __lt__(self, other):
- log ("SelectableInt lt", self, other)
+ log ("SelectableInt __lt__", self, other)
if isinstance(other, FieldSelectableInt):
other = other.get_range()
if isinstance(other, SelectableInt):
assert False
def __eq__(self, other):
- log("__eq__", self, other)
+ log("SelectableInt __eq__", self, other)
if isinstance(other, FieldSelectableInt):
other = other.get_range()
if isinstance(other, SelectableInt):
return self.value != 0
def __repr__(self):
- value = f"value={hex(self.value)}, bits={self.bits}"
- return f"{self.__class__.__name__}({value})"
+ value = "value=%#x, bits=%d" % (self.value, self.bits)
+ if not self.ok:
+ value += ", ok=False"
+ return "%s(%s)" % (self.__class__.__name__, value)
def __len__(self):
return self.bits
"""convert to double-precision float. TODO, properly convert
rather than a hack-job: must actually support Power IEEE754 FP
"""
+ if self.bits == 32:
+ data = self.value.to_bytes(4, byteorder='little')
+ return struct.unpack('<f', data)[0]
assert self.bits == 64 # must be 64-bit
data = self.value.to_bytes(8, byteorder='little')
return struct.unpack('<d', data)[0]
def selectltu(lhs, rhs):
""" less-than (unsigned)
"""
+ if isinstance(lhs, SelectableInt):
+ lhs = lhs.value
if isinstance(rhs, SelectableInt):
rhs = rhs.value
- return onebit(lhs.value < rhs)
+ return onebit(lhs < rhs)
def selectgtu(lhs, rhs):
""" greater-than (unsigned)
"""
+ if isinstance(lhs, SelectableInt):
+ lhs = lhs.value
if isinstance(rhs, SelectableInt):
rhs = rhs.value
- return onebit(lhs.value > rhs)
+ return onebit(lhs > rhs)
# XXX this probably isn't needed...
def selectconcat(*args, repeat=1):
- if repeat != 1 and len(args) == 1 and isinstance(args[0], int):
+ if isinstance(repeat, SelectableInt):
+ repeat = repeat.value
+ if len(args) == 1 and isinstance(args[0], int) and args[0] in (0, 1):
args = [SelectableInt(args[0], 1)]
if repeat != 1: # multiplies the incoming arguments
tmp = []
for i in range(repeat):
tmp += args
args = tmp
- res = copy(args[0])
+ if isinstance(args[0], FieldSelectableInt):
+ res = args[0].get_range()
+ else:
+ assert isinstance(args[0], SelectableInt), "can only concat SIs, sorry"
+ res = SelectableInt(args[0])
for i in args[1:]:
if isinstance(i, FieldSelectableInt):
- i = i.si
+ i = i.get_range()
assert isinstance(i, SelectableInt), "can only concat SIs, sorry"
res.bits += i.bits
res.value = (res.value << i.bits) | i.value