from copy import copy
from typing import Optional, Union, Set
from hwt.code import And, Or
from hwt.doc_markers import internal
from hwt.hdl.constants import DIRECTION
from hwt.hdl.types.array import HArray
from hwt.hdl.types.bits import Bits
from hwt.hdl.types.enum import HEnum
from hwt.hdl.types.hdlType import HdlType
from hwt.hdl.types.struct import HStruct
from hwt.hdl.types.structCast import hstruct_reinterpret
from hwt.hdl.types.structValBase import StructValBase
from hwt.interfaces.agents.structIntf import StructIntfAgent
from hwt.interfaces.std import Signal
from hwt.synthesizer.hObjList import HObjList
from hwt.synthesizer.interface import Interface
from hwt.synthesizer.rtlLevel.rtlSignal import RtlSignal
from hwt.synthesizer.typePath import TypePath
from hwtSimApi.hdlSimulator import HdlSimulator
[docs]class StructIntf(Interface):
"""
Create dynamic interface based on HStruct or HUnion description
:ivar ~._fieldsToInterfaces: dictionary {field_path: sub interface for it}
field path is a tuple of HStructFields which leads to this interface
:ivar ~._dtype: HStruct instance used as template for this interface
:param _instantiateFieldFn: function(FieldTemplateItem instance)
return interface instance
:attention: _instantiateFieldFn should also share _fieldsToInterfaces
with all other instances of StructIntf on this interface
"""
[docs] def __init__(self, structT: HStruct,
field_path: TypePath,
instantiateFieldFn,
masterDir=DIRECTION.OUT,
loadConfig=True):
Interface.__init__(self,
masterDir=masterDir,
loadConfig=loadConfig)
if not field_path:
field_path = TypePath()
else:
assert isinstance(field_path, TypePath), field_path
self._field_path = field_path
self._dtype = structT
assert self._dtype.fields, "Needs to have at least some members (otherwise this interface is useless)"
self._instantiateFieldFn = instantiateFieldFn
self._fieldsToInterfaces = {}
[docs] def _declr(self):
_t = self._dtype
if isinstance(_t, HStruct):
fields = _t.fields
else:
fields = _t.fields.values()
self._fieldsToInterfaces[self._field_path] = self
for field in fields:
# skip padding
if field.name is not None:
# generate interface based on struct field
intf = self._instantiateFieldFn(self, field)
p = self._field_path / field.name
assert p not in self._fieldsToInterfaces, p
self._fieldsToInterfaces[p] = intf
setattr(self, field.name, intf)
[docs] def _initSimAgent(self, sim: HdlSimulator):
self._ag = StructIntfAgent(sim, self)
[docs] def _eq(self, other: Union["StructIntf", StructValBase]):
if isinstance(other, self.__class__):
assert self._dtype == other._dtype
return And(*(si._eq(oi) for si, oi in zip(self._interfaces, other._interfaces)))
else:
return And(*(si._eq(getattr(other, si._name)) for si in self._interfaces))
def __ne__(self, other: Union["StructIntf", StructValBase]):
if isinstance(other, self.__class__):
assert self._dtype == other._dtype
return Or(*(si != oi for si, oi in zip(self._interfaces, other._interfaces)))
else:
return Or(*(si != getattr(other, si._name) for si in self._interfaces))
[docs] def _reinterpret_cast(self, toT: HdlType):
return hstruct_reinterpret(self._dtype, self, toT)
[docs]class HdlType_to_Interface():
"""
Convert instance of HdlType to an interface which represents same data.
:note: Interface is only instantiated, that means it does not have sub-interfaces
loaded yet, it can be done manually or by assigning to a property of parent Interface/Unit
instance.
"""
[docs] def apply(self, dtype: HdlType, field_path: Optional[TypePath]=None, masterDir=DIRECTION.OUT) -> Interface:
"""
Run the conversion
"""
if isinstance(dtype, HStruct):
return StructIntf(dtype, field_path,
instantiateFieldFn=self.instantiateFieldFn,
masterDir=masterDir)
elif isinstance(dtype, (Bits, HEnum)):
return Signal(dtype=dtype, masterDir=masterDir)
elif isinstance(dtype, HArray):
return HObjList(self.apply(dtype.element_t, masterDir=masterDir)
for _ in range(dtype.size))
else:
raise NotImplementedError(dtype)
[docs] @internal
def instantiateFieldFn(self, intf, fieldInfo) -> Interface:
if isinstance(intf, StructIntf):
c = self.apply(
fieldInfo.dtype,
field_path=intf._field_path / fieldInfo.name)
c._fieldsToInterfaces = intf._fieldsToInterfaces
return c
else:
raise NotImplementedError(intf)
[docs]class Interface_to_HdlType():
"""
Convert instance of HdlType to an interface which represents same data.
:note: Interface instance has to have definitions loaded.
"""
[docs] def apply(self, intf: Union[Interface, RtlSignal], const=False, exclude: Optional[Set[Interface]]=None):
"""
Run the conversion
"""
assert exclude is None or intf not in exclude
if isinstance(intf, Interface) and intf._interfaces:
if exclude is None:
return HStruct(
*((self.apply(i, const=const), i._name)
for i in intf._interfaces)
)
else:
return HStruct(
*((self.apply(i, const=const), i._name)
for i in intf._interfaces if i not in exclude)
)
else:
t = intf._dtype
if t.const != const:
t = copy(t)
t.const = const
return t