X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=src%2Fopenpower%2Fdecoder%2Fpower_fields.py;h=57678d071c639d63b3aee7721658d6dfab48e775;hb=49da0707a02513a99f913dc94ba2c86e978dfc84;hp=c2dac292c2c4af6e1d050da60d655b91db160714;hpb=fe91773d8c1505404dc4d7a8a656108a508e58e9;p=openpower-isa.git diff --git a/src/openpower/decoder/power_fields.py b/src/openpower/decoder/power_fields.py index c2dac292..57678d07 100644 --- a/src/openpower/decoder/power_fields.py +++ b/src/openpower/decoder/power_fields.py @@ -1,13 +1,14 @@ 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, ) @@ -31,10 +32,10 @@ class Descriptor: 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 @@ -47,17 +48,17 @@ class Reference: def __binary_operator(self, op, other): span = dict.fromkeys(self.__class__.span).keys() - lhs = _selectconcat(*(self.storage[bit] for bit in span)) + lhs = selectconcat(*(self.storage[bit] for bit in span)) if isinstance(other, Reference): span = dict.fromkeys(other.__class__.span).keys() - rhs = _selectconcat(*(other.storage[bit] for bit in span)) + 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) @@ -65,14 +66,17 @@ class Reference: 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__() @@ -83,21 +87,40 @@ class Reference: @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): @@ -152,22 +175,18 @@ class FieldMeta(type): 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__ - def traverse(cls, path): - yield (path, cls.__members__) - class Field(Reference, metaclass=FieldMeta): - def __len__(self): - return self.__class__.__len__() - def __repr__(self): return f"[{len(self.__class__)}]0x{int(self):x}" @@ -178,9 +197,19 @@ class Field(Reference, metaclass=FieldMeta): def __getitem__(self, key): if isinstance(key, int): bit = self.storage[self.__class__.__members__[key]] - return _SelectableInt(value=bit, bits=1) + 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 tuple(key))) + return selectconcat(*(self[bit] for bit in key)) + + def __setitem__(self, key, value): + return self.assign(value=value, bits=key) + + @classmethod + def traverse(cls, path): + yield (path, cls.__members__) class MappingMeta(type): @@ -225,17 +254,7 @@ class MappingMeta(type): return length def __getitem__(cls, selector): - best_min = 0 - best_max = 0 - for field in cls.__members__.values(): - length = len(field) - best_min = min(best_min, length) - best_max = max(best_max, length) - - items = tuple(range(best_min, best_max)) - field = FieldMeta(cls.__name__, (Field,), {}, items=items) - - return field[selector] + return cls.__members__["_"][selector] def remap(cls, scheme): ns = {} @@ -244,6 +263,7 @@ class MappingMeta(type): for (name, field) in cls: annotations[name] = field.remap(scheme) ns["__annotations__"] = annotations + ns["__doc__"] = cls.__doc__ return cls.__class__(cls.__name__, (cls,), ns) @@ -252,15 +272,6 @@ class MappingMeta(type): for field in cls.__members__.values(): yield from field.span - def traverse(cls, path=""): - for (name, field) in cls: - if name == "_": - yield from field.traverse(path=path) - elif path == "": - yield from field.traverse(path=name) - else: - yield from field.traverse(path=f"{path}.{name}") - class Mapping(Reference, metaclass=MappingMeta): def __init__(self, storage, **kwargs): @@ -281,9 +292,28 @@ class Mapping(Reference, metaclass=MappingMeta): 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): @@ -381,7 +411,7 @@ def decode_form(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 @@ -389,7 +419,7 @@ class DecodeFields: 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): @@ -459,7 +489,7 @@ class DecodeFields: #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 @@ -467,7 +497,20 @@ class DecodeFields: 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()