from collections import namedtuple
-import operator as _operator
-import functools as _functools
+import operator
+import functools
-from openpower.decoder.power_enums import find_wiki_file as _find_wiki_file
+from openpower.decoder.power_enums import find_wiki_file
from openpower.decoder.selectable_int import (
- SelectableInt as _SelectableInt,
- BitRange as _BitRange,
- selectconcat as _selectconcat,
+ SelectableInt,
+ BitRange,
+ selectconcat,
+ selectltu,
)
self.__cls(storage=instance.storage).assign(value)
-@_functools.total_ordering
+@functools.total_ordering
class Reference:
def __init__(self, storage, *args, **kwargs):
- if not isinstance(storage, _SelectableInt):
+ if not isinstance(storage, SelectableInt):
raise ValueError(storage)
self.storage = storage
_ = (args, kwargs)
def __binary_operator(self, op, other):
- span = self.__class__.span
- lhs = _selectconcat(*(self.storage[bit] for bit in span))
+ span = dict.fromkeys(self.__class__.span).keys()
+ lhs = selectconcat(*(self.storage[bit] for bit in span))
- if isinstance(other, Field):
- bits = len(other.__class__)
- value = int(other)
- rhs = _SelectableInt(value=value, bits=bits)
+ if isinstance(other, Reference):
+ span = dict.fromkeys(other.__class__.span).keys()
+ rhs = selectconcat(*(other.storage[bit] for bit in span))
elif isinstance(other, int):
bits = len(self.__class__)
if other.bit_length() > bits:
raise OverflowError(other)
- rhs = _SelectableInt(value=other, bits=bits)
- elif isinstance(other, _SelectableInt):
+ rhs = SelectableInt(value=other, bits=bits)
+ elif isinstance(other, SelectableInt):
rhs = other
else:
raise ValueError(other)
return op(lhs, rhs)
def __lt__(self, other):
- return self.__binary_operator(_operator.lt, other)
+ return self.__binary_operator(selectltu, other)
def __eq__(self, other):
- return self.__binary_operator(_operator.eq, other)
+ return self.__binary_operator(operator.eq, other)
+
+ def __bool__(self):
+ return bool(int(self))
def __int__(self):
span = dict.fromkeys(self.__class__.span).keys()
- return int(_selectconcat(*(self.storage[bit] for bit in span)))
+ return int(selectconcat(*(self.storage[bit] for bit in span)))
def __index__(self):
return int(self).__index__()
@storage.setter
def storage(self, storage):
- if not isinstance(storage, _SelectableInt):
+ if not isinstance(storage, SelectableInt):
raise ValueError(storage)
self.__storage = storage
- def assign(self, value):
- if isinstance(value, int):
- bits = len(self.__class__)
- value = _SelectableInt(value=value, bits=bits)
- if not isinstance(value, _SelectableInt):
+ def assign(self, value, bits=None):
+ if bits is None:
+ bits = range(len(self.__class__))
+ elif isinstance(bits, int):
+ bits = (bits,)
+ elif isinstance(bits, slice):
+ assert bits.step is None or bits.step == 1
+ bits = range(bits.start, bits.stop)
+ bits = tuple(bits)
+
+ if isinstance(value, (int, self.__class__)):
+ value = int(value)
+ if value.bit_length() > len(bits):
+ raise OverflowError(value)
+ value = SelectableInt(value=value, bits=len(bits))
+ if not isinstance(value, SelectableInt):
raise ValueError(value)
+ if value.bits != len(bits):
+ raise OverflowError(value)
- span = frozenset(self.__class__.span)
- for (src_bit, dst_bit) in enumerate(span):
- self.storage[dst_bit] = value[src_bit]
+ span = tuple(self.__class__.span)
+ mapping = dict(enumerate(span))
+ for (src, bit) in enumerate(bits):
+ if src >= value.bits:
+ raise OverflowError(src)
+ dst = mapping.get(bit)
+ if dst is None:
+ raise OverflowError(bit)
+ self.storage[dst] = value[src]
class FieldMeta(type):
return super().__new__(metacls, clsname, bases, ns)
- def __getitem__(cls, size):
- clsname = f"{cls.__name__}[{size}]"
- items = ((Field,) * size)
- return ArrayMeta(clsname, (Array,), {}, items=items)
-
def __repr__(cls):
if not cls.__members__:
return cls.__name__
def __len__(cls):
return len(cls.__members__)
- @property
- def span(cls):
- return cls.__members__
+ def __getitem__(cls, selector):
+ if isinstance(selector, int):
+ selector = (selector,)
+
+ items = []
+ for idx in selector:
+ if not isinstance(idx, int):
+ raise ValueError(selector)
+ item = cls.__members__[idx]
+ items.append(item)
+
+ return cls.__class__(cls.__name__, (Field,), {}, items=items)
def remap(cls, scheme):
if isinstance(scheme, type) and issubclass(scheme, Mapping):
rlen = f"len({cls.__name__})"
raise RemapError(f"{llen} != {rlen}")
+ ns = {}
+ ns["__doc__"] = cls.__doc__
items = map(lambda item: scheme.__members__[item], cls)
- return cls.__class__(cls.__name__, (cls,), {}, items=items)
+ return cls.__class__(cls.__name__, (cls,), ns, items=items)
+ @property
+ def span(cls):
+ return cls.__members__
-class Field(Reference, metaclass=FieldMeta):
- def __len__(self):
- return self.__class__.__len__()
+class Field(Reference, metaclass=FieldMeta):
def __repr__(self):
return f"[{len(self.__class__)}]0x{int(self):x}"
for bit in self.__class__:
yield self.storage[bit]
-
-class ArrayMeta(type):
- def __new__(metacls, clsname, bases, ns, items=()):
- assert "__members__" not in ns
-
- members = []
- for item in items:
- if not (isinstance(item, type) and issubclass(item, Field)):
- item = FieldMeta("Field", (Field,), {}, items=item)
- members.append(item)
-
- ns["__members__"] = tuple(members)
-
- return super().__new__(metacls, clsname, bases, ns)
-
- def __repr__(cls):
- if not cls.__members__:
- return cls.__name__
- return f"{cls.__name__}{cls.__members__!r}"
-
- def __iter__(cls):
- yield from enumerate(cls.__members__)
-
- def __len__(cls):
- length = 0
- for field in cls.__members__:
- length += len(field)
- return length
-
- def remap(cls, scheme):
- scheme_md = []
- scheme_sd = []
-
- for item in scheme:
- if not isinstance(item, int):
- scheme_md.append(item)
- else:
- scheme_sd.append(item)
-
- if scheme_md and scheme_sd:
- raise ValueError(scheme)
-
- def remap_md(scheme):
- scheme = cls.__class__(cls.__name__, (cls,), {}, items=scheme)
- if len(cls) == 0:
- if len(cls.__members__) != len(scheme.__members__):
- llen = f"len(scheme.__members__)"
- rlen = f"len({cls.__name__}.__members__)"
- raise RemapError(f"{llen} != {rlen}")
- return scheme
- elif len(scheme) != len(cls):
- llen = f"len(scheme)"
- rlen = f"len({cls.__name__})"
- raise RemapError(f"{llen} != {rlen}")
-
- items = []
- for (idx, field) in enumerate(cls):
- try:
- item = field.remap(scheme.__members__[idx])
- except RemapError as error:
- raise RemapError(f"[{idx}]: {error}")
- items.append(item)
-
- return cls.__class__(cls.__name__, (cls,), {}, items=items)
-
- def remap_sd(scheme):
- items = tuple(item.remap(scheme) for item in cls.__members__)
- return cls.__class__(cls.__name__, (cls,), {}, items=items)
-
- if scheme_md:
- return remap_md(scheme_md)
- else:
- return remap_sd(scheme_sd)
-
- @property
- def span(cls):
- for field in cls.__members__:
- yield from field.span
-
-
-class Array(Reference, metaclass=ArrayMeta):
- def __init__(self, storage):
- members = []
- for (idx, cls) in self.__class__:
- members.append(cls(storage))
-
- self.__members = tuple(members)
-
- return super().__init__(storage)
-
- def __repr__(self):
- items = tuple(f"[{idx}]={field!r}" for (idx, field) in self)
- return f"[{', '.join(items)}]"
-
- def __iter__(self):
- yield from enumerate(self.__members)
-
def __getitem__(self, key):
- return self.__members[key]
+ if isinstance(key, int):
+ bit = self.storage[self.__class__.__members__[key]]
+ return SelectableInt(value=bit, bits=1)
+ if isinstance(key, slice):
+ assert key.step is None or key.step == 1
+ key = range(key.start, key.stop)
+
+ return selectconcat(*(self[bit] for bit in key))
def __setitem__(self, key, value):
- self.__members[key].assign(value)
+ return self.assign(value=value, bits=key)
+
+ @classmethod
+ def traverse(cls, path):
+ yield (path, cls.__members__)
class MappingMeta(type):
for (name, cls) in ns.get("__annotations__", {}).items():
if not (isinstance(cls, type) and
- issubclass(cls, (Mapping, Array, Field))):
+ issubclass(cls, (Mapping, Field))):
raise ValueError(f"{clsname}.{name}: {cls!r}")
if name in ns:
except RemapError as error:
raise RemapError(f"{name}: {error}")
else:
- if cls in (Array, Field):
- raise ValueError(f"{clsname}.{name}: " + \
- "base class without initializer")
+ if cls is Field:
+ raise ValueError(f"{clsname}.{name}: missing initializer")
members[name] = cls
ns["__members__"] = members
length = max(length, len(field))
return length
+ def __getitem__(cls, selector):
+ return cls.__members__["_"][selector]
+
def remap(cls, scheme):
ns = {}
annotations = {}
for (name, field) in cls:
annotations[name] = field.remap(scheme)
ns["__annotations__"] = annotations
+ ns["__doc__"] = cls.__doc__
return cls.__class__(cls.__name__, (cls,), ns)
def __getitem__(self, key):
if isinstance(key, (int, slice, list, tuple, range)):
- return self.storage[key]
+ return self["_"].__getitem__(key)
+
+ return self.__members.__getitem__(key)
+
+ def __setitem__(self, key, value):
+ if isinstance(key, (int, slice, list, tuple, range)):
+ return self["_"].assign(value=value, bits=key)
- return self.__members[key]
+ return self.assign(value=value, bits=key)
+
+ def __getattr__(self, key):
+ raise AttributeError(key)
+
+ @classmethod
+ def traverse(cls, path):
+ for (name, member) in cls.__members__.items():
+ if name == "_":
+ yield from member.traverse(path=path)
+ elif path == "":
+ yield from member.traverse(path=name)
+ else:
+ yield from member.traverse(path=f"{path}.{name}")
def decode_instructions(form):
class DecodeFields:
- def __init__(self, bitkls=_BitRange, bitargs=(), fname=None,
+ def __init__(self, bitkls=BitRange, bitargs=(), fname=None,
name_on_wiki=None):
self.bitkls = bitkls
self.bitargs = bitargs
assert name_on_wiki is None
fname = "fields.txt"
name_on_wiki = "fields.text"
- self.fname = _find_wiki_file(name_on_wiki)
+ self.fname = find_wiki_file(name_on_wiki)
@property
def form_names(self):
#print ("decode", txt)
forms = {}
reading_data = False
- for l in txt:
+ for lineno, l in enumerate(txt):
l = l.strip()
if len(l) == 0:
continue
if l[0] == '#':
reading_data = False
else:
- forms[heading].append(l)
+ form = forms[heading]
+ form.append(l)
+ if len(form) <= 1:
+ continue
+ # check separators line up with header
+ for i, ch in enumerate(l):
+ if ch != '|':
+ continue
+ if i >= len(form[0]) or form[0][i] != '|':
+ col = len(txt[lineno]) - len(txt[lineno].lstrip())
+ col += i + 1
+ raise SyntaxError("form line field separator ('|') "
+ "with no corresponding separator in header",
+ (self.fname, lineno + 1, col, txt[lineno]))
if not reading_data:
assert l[0] == '#'
heading = l[1:].strip()