|
|
|
from operator import attrgetter
|
|
|
|
|
|
|
|
from amaranth import *
|
|
|
|
|
|
|
|
|
|
|
|
__all__ = ["InsnField", "WordInsn"]
|
|
|
|
|
|
|
|
|
|
|
|
class InsnField:
|
|
|
|
def __init__(self, value=None):
|
|
|
|
self.value = value
|
|
|
|
|
|
|
|
@property
|
|
|
|
def shape(self):
|
|
|
|
return self._shape
|
|
|
|
|
|
|
|
@property
|
|
|
|
def offset(self):
|
|
|
|
return self._offset
|
|
|
|
|
|
|
|
@property
|
|
|
|
def name(self):
|
|
|
|
return self._name
|
|
|
|
|
|
|
|
@property
|
|
|
|
def value(self):
|
|
|
|
return self._value
|
|
|
|
|
|
|
|
@value.setter
|
|
|
|
def value(self, value):
|
|
|
|
if value is not None and not isinstance(value, int):
|
|
|
|
raise TypeError("Field value must be an integer, not {!r}"
|
|
|
|
.format(value))
|
|
|
|
self._value = value
|
|
|
|
|
|
|
|
|
|
|
|
class WordInsn(Record):
|
|
|
|
SIZE = 32
|
|
|
|
|
|
|
|
def __init__(self, name=None, src_loc_at=0):
|
|
|
|
curr_offset = 0
|
|
|
|
layout = []
|
|
|
|
pattern = ""
|
|
|
|
|
|
|
|
for field in sorted(self._fields, key=attrgetter("offset")):
|
|
|
|
if not isinstance(field, InsnField):
|
|
|
|
raise TypeError("Field must be an instance of InsnField, not {!r}"
|
|
|
|
.format(field))
|
|
|
|
if curr_offset > field.offset:
|
|
|
|
raise ValueError("Field '{}' at offset {} overlaps with its predecessor"
|
|
|
|
.format(field.name, field.offset))
|
|
|
|
|
|
|
|
# Add undefined bits located between this field and its predecessor.
|
|
|
|
if curr_offset < field.offset:
|
|
|
|
undef_bits = field.offset - curr_offset
|
|
|
|
layout.append((f"_{curr_offset}", unsigned(undef_bits)))
|
|
|
|
pattern += "-" * undef_bits
|
|
|
|
|
|
|
|
layout.append((field.name, field.shape))
|
|
|
|
if field.value is not None:
|
|
|
|
pattern += "{:0{}b}".format(field.value, field.shape.width)
|
|
|
|
else:
|
|
|
|
pattern += "-" * field.shape.width
|
|
|
|
|
|
|
|
curr_offset = field.offset + field.shape.width
|
|
|
|
|
|
|
|
if curr_offset > self.SIZE:
|
|
|
|
raise ValueError
|
|
|
|
|
|
|
|
# Add undefined bits located after the last field.
|
|
|
|
if curr_offset < self.SIZE:
|
|
|
|
undef_bits = self.SIZE - curr_offset
|
|
|
|
layout.append((f"_{curr_offset}", unsigned(undef_bits)))
|
|
|
|
pattern += "-" * undef_bits
|
|
|
|
|
|
|
|
self._pattern = pattern
|
|
|
|
super().__init__(reversed(layout), name=name, src_loc_at=1 + src_loc_at)
|
|
|
|
|
|
|
|
@property
|
|
|
|
def pattern(self):
|
|
|
|
return self._pattern
|
|
|
|
|
|
|
|
def is_valid(self):
|
|
|
|
return self.as_value().matches(self.pattern)
|