Source code for hwt.hdl.types.struct
from hwt.doc_markers import internal
from hwt.hdl.types.hdlType import HdlType
from hwt.hdl.types.structValBase import StructValBase
from hwt.serializer.generic.indent import getIndent
[docs]class HStructField(object):
[docs] def __init__(self, typ: HdlType, name: str, meta=None):
assert isinstance(name, str) or name is None, name
assert isinstance(typ, HdlType), typ
self.name = name
self.dtype = typ
self.meta = meta
def __eq__(self, other):
return self.name == other.name and\
self.dtype == other.dtype and\
self.meta == other.meta
def __hash__(self):
return hash((self.name, self.dtype, self.meta))
def __repr__(self):
name = self.name
if name is None:
name = "<padding>"
return f"<HStructField {self.dtype}, {name:s}>"
protectedNames = {"clone", "staticEval", "from_py", "_dtype"}
[docs]class HStruct(HdlType):
"""
HDL structure type
:ivar ~.fields: tuple of :class:`~.HStructField` instances in this struct
:ivar ~.name: name of this HStruct type
:ivar ~.field_by_name: dictionary which maps the name of the field to :class:`~.HStructField` instance
:ivar ~.valueCls: Class of value for this type as usual
in HdlType implementations
"""
[docs] def __init__(self, *template, name=None, const=False):
"""
:param template: list of tuples (type, name) or :class:`~.HStructField` objects
name can be None (= padding)
:param name: optional name used for debugging purposes
"""
super(HStruct, self).__init__(const=const)
fields = []
field_by_name = {}
self.name = name
bit_length = 0
for f in template:
try:
field = HStructField(*f)
except TypeError:
field = f
if not isinstance(field, HStructField):
raise TypeError(f"Template for struct field {f} is"
" not in valid format")
fields.append(field)
if field.name is not None:
assert field.name not in field_by_name, field.name
field_by_name[field.name] = field
t = field.dtype
if bit_length is not None:
try:
_bit_length = t.bit_length()
bit_length += _bit_length
except TypeError:
bit_length = None
self.fields = tuple(fields)
self.field_by_name = field_by_name
self.__hash = hash((self.name, self.const, self.fields))
self.__bit_length_val = bit_length
usedNames = set(field_by_name.keys())
assert not protectedNames.intersection(usedNames),\
protectedNames.intersection(usedNames)
class StructVal(StructValBase):
__slots__ = list(usedNames)
if name is not None:
StructVal.__name__ = name + "Val"
self.valueCls = StructVal
[docs] def bit_length(self):
bl = self.__bit_length_val
if bl is None:
raise TypeError("Can not request bit_lenght on type"
" which has not fixed size")
else:
return self.__bit_length_val
[docs] @internal
def getValueCls(self):
return self.valueCls
[docs] @internal
@classmethod
def get_reinterpret_cast_fn(cls):
from hwt.hdl.types.structCast import hstruct_reinterpret
return hstruct_reinterpret
@internal
def __fields__eq__(self, other):
if len(self.fields) != len(other.fields):
return False
for sf, of in zip(self.fields, other.fields):
if (sf.name != of.name or
sf.dtype != of.dtype or
sf.meta != of.meta):
return False
return True
def __eq__(self, other):
if self is other:
return True
if (type(self) is type(other)):
if self.name != other.name or self.const != other.const:
return False
try:
self_l = self.bit_length()
except TypeError:
self_l = -1
try:
other_l = other.bit_length()
except TypeError:
other_l = -1
return self_l == other_l and self.__fields__eq__(other)
return False
@internal
def __hash__(self):
return self.__hash
def __add__(self, other):
"""
override of addition, merge struct into one
"""
assert isinstance(other, HStruct)
return HStruct(*self.fields, *other.fields)
def __repr__(self, indent=0, withAddr=None, expandStructs=False):
"""
:param indent: number of indentation
:param withAddr: if is not None is used as a additional
information about on which address this type is stored
(used only by HStruct)
:param expandStructs: expand HStructTypes (used by HStruct and HArray)
"""
if self.name:
name = self.name + " "
else:
name = ""
myIndent = getIndent(indent)
childIndent = getIndent(indent + 1)
header = f"{myIndent:s}struct {name:s}{{"
buff = [header, ]
for f in self.fields:
if withAddr is not None:
withAddr_B = withAddr // 8
addrTag = f" // start:0x{withAddr:x}(bit) 0x{withAddr_B:x}(byte)"
else:
addrTag = ""
if f.name is None:
buff.append(f"{childIndent:s}//{f.dtype} empty space{addrTag:s}")
else:
buff.append("%s %s%s" % (
f.dtype.__repr__(indent=indent + 1,
withAddr=withAddr,
expandStructs=expandStructs),
f.name, addrTag))
if withAddr is not None:
withAddr += f.dtype.bit_length()
buff.append(f"{myIndent:s}}}")
return "\n".join(buff)