You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

85 lines
2.4 KiB
Python

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)