hwtLib.abstract package¶
A package of abstract components (components which needs to have some methods implemented before use) and other utilities.
Subpackages¶
- hwtLib.abstract.frame_utils package
- Subpackages
- hwtLib.abstract.frame_utils.join package
- Submodules
- hwtLib.abstract.frame_utils.alignment_utils module
FrameAlignmentUtilsFrameAlignmentUtils.__init__()FrameAlignmentUtils._resolve_input_bytes_destinations()FrameAlignmentUtils.can_produce_zero_len_frame()FrameAlignmentUtils.create_frame()FrameAlignmentUtils.get_bytes_in_frame_info()FrameAlignmentUtils.get_important_byte_cnts()FrameAlignmentUtils.join_streams()FrameAlignmentUtils.resolve_input_bytes_destinations()FrameAlignmentUtils.stream_to_all_possible_frame_formats()FrameAlignmentUtils.streams_to_all_possible_frame_formats()
count_not_none()freeze_frame()next_frame_offsets()
- hwtLib.abstract.frame_utils.byte_src_info module
- Subpackages
Submodules¶
hwtLib.abstract.addressStepTranslation module¶
- class hwtLib.abstract.addressStepTranslation.AddressStepTranslation(src_addr_step: int = 8, dst_addr_step: int = 8)[source]¶
Bases:
object- Variables:
align_bits – number of bits on source/destination address which are addressing in a single word or other address
src_addr_step – how many bits is addressing one unit of src_addr_sig
dst_addr_step – how many bits is addressing one unit of dst_addr_sig
hwtLib.abstract.busBridge module¶
hwtLib.abstract.busEndpoint module¶
- class hwtLib.abstract.busEndpoint.BusEndpoint(structTemplate, hwIOCls: Type[HwIO] = None, shouldEnterFn=None)[source]¶
Bases:
HwModuleAbstract unit
Delegate request from bus to fields of structure (fields are represented by various interfaces) write has higher priority
- Note:
implementation is usually address decoder
- __annotations__ = {}¶
- __init__(structTemplate, hwIOCls: Type[HwIO] = None, shouldEnterFn=None)[source]¶
- Parameters:
structTemplate – instance of HStruct which describes address space of this endpoint
hwIOCls – class of bus interface which should be used
shouldEnterFn – function(root_t, structFieldPath) return (shouldEnter, shouldUse) where shouldEnter is flag that means iterator over this interface should look inside of this actual object and shouldUse flag means that this field should be used (to create interface)
- static _defaultShouldEnterFn(root: HdlType, field_path: Tuple[str | int])[source]¶
Default method which resolves how the parts of input data type should be represented on interface level.
- _getAddrStep() int[source]¶
- Returns:
how many bits does 1 address unit addresses, (e.g. AXI -> 8b, index to uint32_t[N] -> 32)
- _getWordAddrStep() int[source]¶
- Returns:
how many address units is one word on bus (e.g. 32b AXI -> 4)
- _mkFieldInterface(structHwIO: HwIOStruct, field: HStructField)[source]¶
Instantiate field interface for fields in structure template of this endpoint
- Returns:
interface for specified field
- connectByInterfaceMap(hwIOMap: HwIOObjMap)[source]¶
Connect “decoded” struct interface to interfaces specified in interface map
- connect_directly_mapped_read(ar_addr: RtlSignal, r_data: RtlSignal, default_r_data_drive)[source]¶
Connect the HwIORegCntrl.din interfaces to a bus
- connect_directly_mapped_write(aw_addr: RtlSignal, w_data: RtlSignal, en: RtlSignal)[source]¶
Connect the HwIORegCntrl.dout interfaces to a bus
- classmethod fromHwIOMap(interfaceMap)[source]¶
Generate converter by struct data type specified by interface map
- Parameters:
interfaceMap –
hwt.hwIOs.hwIO_map.HTypeFromHwIOObjMap()
- propagateAddr(src_addr_sig: RtlSignal, src_addr_step: int, dst_addr_sig: RtlSignal, dst_addr_step: int, transTmpl: TransTmpl)[source]¶
- Parameters:
src_addr_sig – input signal with address
src_addr_step – how many bits is addressing one unit of src_addr_sig
dst_addr_sig – output signal for address
dst_addr_step – how many bits is addressing one unit of dst_addr_sig
transTmpl – TransTmpl which has meta-informations about this address space transition
hwtLib.abstract.busInterconnect module¶
- class hwtLib.abstract.busInterconnect.AUTO_ADDR[source]¶
Bases:
objectconstant which means that address should be picked automatically
- class hwtLib.abstract.busInterconnect.BusInterconnect(hdlName: str | None = None)[source]¶
Bases:
HwModuleAbstract class of bus interconnects
- Variables:
~.m – HObjList of master interfaces
~.s – HObjList of slave interfaces
- __annotations__ = {}¶
- class hwtLib.abstract.busInterconnect.BusInterconnectUtils[source]¶
Bases:
object- classmethod _extract_separable_group(mi: int, seen_m: Set[int], masters_connected_to: List[Set[int]], slaves_connected_to: List[Set[int]])[source]¶
Transitive enclosure of master/stalave ports on connected relation (Extract a group of all ports which are somehow connected to each other)
hwtLib.abstract.busStaticRemap module¶
- class hwtLib.abstract.busStaticRemap.BusStaticRemap(hdlName: str | None = None)[source]¶
Bases:
HwModuleAbstract class for component which remaps memory regions on bus interfaces
- Variables:
~.MEM_MAP – list of tuples (addr_from, size, addr_to) for each memory region on second interface
~.m – slave interface of first HwIO class where master should be connected
~.s – slave interface of second HwIO class where master slave be connected
- __annotations__ = {}¶
hwtLib.abstract.componentBuilder module¶
- class hwtLib.abstract.componentBuilder.AbstractComponentBuilder(parent: HwModule, srcInterface: HwIO | HObjList, name: str | None = None, master_to_slave: bool = True)[source]¶
Bases:
objectHelper class which simplifies instantiation of commonly used components with configuration based on input/output interface
- Variables:
~.parent – unit in which will be all units created by this builder instantiated
~.compId – last component sequential number, used to avoid name collisions
~.lastComp – last builded component
~.end – last interface of data-path
~.name – prefix for all instantiated units
- Attention:
input port is taken from self.end
- __init__(parent: HwModule, srcInterface: HwIO | HObjList, name: str | None = None, master_to_slave: bool = True)[source]¶
- Parameters:
parent – HwModule where all submodules created by this builder will be instantiated
name – prefix for all instantiated units
srcInterface – start of data-path
master_to_slave – if True the circuit is build in natural direction (master to slave, input to output) othervise it is build in reverse direction
hwtLib.abstract.debug_bus_monitor module¶
- class hwtLib.abstract.debug_bus_monitor.DebugBusMonitor(bus_cls, bus_endpoint_cls)[source]¶
Bases:
HwModuleThis component is similar to ILA/ChipScope/SignalTAP but it is not connected to internal JTAG, but to a specified interface. This component generates an address decoder and connect all specified interfaces to a service bus. It also stores the names and bit widths of original interfaces in a ROM in order to display them later in test application. This component also supports for snapshots of values by a generic trigger method, transaction counters etc.
- Note:
addressspace size depends on how much data is actually monitored. But it has fixed structure.
Example of meta_memory JSON format:
- __annotations__ = {}¶
- build_meta_memory(monitored_data: List[DebugBusMonitorDataRecord])[source]¶
- build_meta_memory_json(monitored_data: List[DebugBusMonitorDataRecord], data_ids: Dict[DebugBusMonitorDataRecord, int], offset: int)[source]¶
- register(hwIO: HwIO, name: str | None = None, cdc: bool = False, trigger: RtlSignal | None = None, add_reg: bool = False)[source]¶
- Parameters:
hwIO – an interface to monitor
name – name override
cdc – if True instantiate Clock domain crossing to synchronize input data to clock domain of this component
trigger – an optional signal which triggers the snapshot of this interface
add_reg – if True an register is added between input and bus interface
- Note:
if cdc is set to True the trigger has to be synchonezed to a clock clock domain of hwIO
- class hwtLib.abstract.debug_bus_monitor.DebugBusMonitorDataRecord(hwIO: HwIO, name: str, cdc: bool, trigger: RtlSignal, add_reg: bool)[source]¶
Bases:
object- __annotations__ = {'children': 'List[DebugBusMonitorDataRecord]', 'successors': 'List[DebugBusMonitorDataRecord]'}¶
- add_children(c: DebugBusMonitorDataRecord)[source]¶
- add_link(dst: DebugBusMonitorDataRecord)[source]¶
- children: List[DebugBusMonitorDataRecord]¶
- successors: List[DebugBusMonitorDataRecord]¶
hwtLib.abstract.discoverAddressSpace module¶
- class hwtLib.abstract.discoverAddressSpace.AddressSpaceProbe(topHwIO, getMainSigFn, offset=0)[source]¶
Bases:
objectAn object which can be used to discover an address space of an interface. Discovery is made by walking on address signal.
hwtLib.abstract.emptyHwModule module¶
- class hwtLib.abstract.emptyHwModule.EmptyHwModule(hdlName: str | None = None)[source]¶
Bases:
HwModulehwt.hwModule.HwModuleused for prototyping all output interfaces are connected to _def_val and this is only think which architecture contains- Variables:
_def_val – this value is used to initialize all signals
- __annotations__ = {}¶
- _def_val = None¶
hwtLib.abstract.hwExceptionCtx module¶
- class hwtLib.abstract.hwExceptionCtx.ExceptionHandleInterface(exception: InHwError, masterDir=DIRECTION.OUT, loadConfig=True)[source]¶
Bases:
HwIORdVldSync- __annotations__ = {}¶
- __init__(exception: InHwError, masterDir=DIRECTION.OUT, loadConfig=True)[source]¶
This constructor is called when constructing new interface, it is usually done manually while creating
hwt.hwModule.HwModuleor automatically while extracting interfaces from HwModuleWithSoure- Parameters:
masterDir – direction which this interface should have for master
loadConfig – do load config in __init__
- class hwtLib.abstract.hwExceptionCtx.HwExceptionCtx(parent: HwModule, name='raise')[source]¶
Bases:
objectAn object which handles hardware exceptions.
- Attention:
exception handling requires a clock and reset signal to be present on parent
hwt.hwModule.HwModuleinstance.
- _HwModule_makePublicHwIOPrivateInImpl(hwIO: ExceptionHandleInterface)[source]¶
- _HwModule_registerPublicHwIOInImpl(hwIO: ExceptionHandleInterface, name: str, onParentPropertyPath: TypePath)[source]¶
- hw_catch(exception_cls: Type[InHwError] | Tuple[Type[InHwError], ...] | None = None) List[Tuple[InHwError, ExceptionHandleInterface]][source]¶
Catch all uncatched exceptions by exception class.
- Parameters:
exception_cls – An class on exceptions which should be catched (An exception is catched if its class is a subclass of exception_cls).
- Note:
Catching exception means getting IO for exception handling in this context. You need to drive all interfaces and possibly re-raise for those which should not be catched.
- Returns:
List of tuples (exception, interface) for every uncatched exception in current scope (includes children). (Due to parallel nature of hardware it is a list and exceptions may be raised simulately.)
- hw_raise(exception: InHwError, pending_flag: RtlSignalBase | None = None, raising_flag: RtlSignalBase | None = None)[source]¶
Construct a logic to raise an exception in generated hardware. This creates a flag and IO for exception handling status.
- Parameters:
pending_flag – An optional flag which should be set to 1 if exception was raised in some previous clock cycle an it has not beed catched yet.
raising_flag – An optional flag which should be set to 1 if exception exception is beeing raised in this clock cycle.
- Attention:
The arguments specified in the exception has to remain stable until the excetion is handled.
- Returns:
An expression which triggers the exception handling.
hwtLib.abstract.hwIOMonitor module¶
- class hwtLib.abstract.hwIOMonitor.HwIOMonitor(templateHwIO: HwIO)[source]¶
Bases:
HwIOInterfaces same as template interface, but with all signals as an input
- __annotations__ = {}¶
- __init__(templateHwIO: HwIO)[source]¶
This constructor is called when constructing new interface, it is usually done manually while creating
hwt.hwModule.HwModuleor automatically while extracting interfaces from HwModuleWithSoure- Parameters:
masterDir – direction which this interface should have for master
loadConfig – do load config in __init__
- class hwtLib.abstract.hwIOMonitor.HwIOMonitorDataVld(templateHwIO)[source]¶
Bases:
HwIODataVld- __annotations__ = {}¶
- __init__(templateHwIO)[source]¶
This constructor is called when constructing new interface, it is usually done manually while creating
hwt.hwModule.HwModuleor automatically while extracting interfaces from HwModuleWithSoure- Parameters:
masterDir – direction which this interface should have for master
loadConfig – do load config in __init__
- class hwtLib.abstract.hwIOMonitor.HwIOMonitorDataVldCdc(templateHwIO)[source]¶
Bases:
VldSyncedCdc- __annotations__ = {}¶
- class hwtLib.abstract.hwIOMonitor.HwIOMonitorReg(hwIOCls: Type[HwIOMonitor])[source]¶
Bases:
HwModule- __annotations__ = {}¶
- __init__(hwIOCls: Type[HwIOMonitor])[source]¶
- hwtLib.abstract.hwIOMonitor._connect_HwIOMonitor(src: HwIOMonitor, dst)[source]¶
- hwtLib.abstract.hwIOMonitor._connect_to_HwIOMonitor(src, dst: HwIOMonitor)[source]¶
- hwtLib.abstract.hwIOMonitor.connect_HwIOMonitor(src: HwIOMonitor, dst)[source]¶
Connect signal by signal and ignore the directions of struct interface (check only direction of low level signals)
- hwtLib.abstract.hwIOMonitor.connect_to_HwIOMonitor(src, dst: HwIOMonitor)[source]¶
Connect signal by signal and ignore the directions of struct interface (check only direction of low level signals)
hwtLib.abstract.simFrameUtils module¶
- class hwtLib.abstract.simFrameUtils.SimFrameUtils(DATA_WIDTH: int)[source]¶
Bases:
Generic[WordTupleTy]This class is a base class for utility classes which converts between pythonic formats of frames and formats used by simulation agents.
- Note:
The main purpose is to simplify work with the frames and to make test agnostic to a specific stream hwio type.
- __orig_bases__ = (typing.Generic[~WordTupleTy],)¶
- __parameters__ = (~WordTupleTy,)¶
- concatWordBits(frameBeats: Sequence[WordTupleTy]) Generator[HBitsConst, None, None][source]¶
Convert word tuple (produced by
send_bytes()andpack_frame()) to flatHBitsConst(members of input tuple are typically ints so they need to be cast to correct type first)
- classmethod from_HwIO(hwio: HwIO) Self[source]¶
Create a an instance of self configured for specified hwio instance
- pack_frame(structVal: HConst | Sequence[int]) Generator[WordTupleTy, None, None][source]¶
pack data of structure into words of target hwio Words are tuples specific to each hwio.
- Parameters:
structVal – value to be send, HConst instance or list of int for each byte
- Returns:
generator of word tuples
- receive_bytes(ag_data: Deque[WordTupleTy]) tuple[int, list[int]][source]¶
- Parameters:
ag_data – list of stream hwio words
- Returns:
tuple dataStartOffset, data_Bytes
- send_bytes(data_B: bytes | list[int], ag_data: Deque[WordTupleTy], offset: int = 0) list[WordTupleTy][source]¶
Build frame out of data_B bytes and insert it into ag_data deque which is expected to be a queue of driver sim agent
- unpack_frame(structT: HdlType, frameData: Deque[WordTupleTy]) HConst[source]¶
opposite of
pack_frame()
hwtLib.abstract.sim_ram module¶
- exception hwtLib.abstract.sim_ram.AllocationError[source]¶
Bases:
ExceptionException which says that requested allocation can not be performed
- class hwtLib.abstract.sim_ram.SimRam(cellSize: int, parent=None)[source]¶
Bases:
objectDense memory for simulation purposes with data pump interfaces
- Variables:
~.data – memory dict
- __init__(cellSize: int, parent=None)[source]¶
- Parameters:
cellSize – specifies the number of bytes of word (byte is unit of the addres and it does not have to be 8b)
clk – clk signal for synchronization
parent – parent instance of SimRam (memory will be shared with this instance)
- _getArray(offset, transTmpl)[source]¶
- Parameters:
offset – global offset of this transTmpl (and struct)
transTmpl – instance of TransTmpl which specifies items in array
- _getStruct(offset, transTmpl)[source]¶
- Parameters:
offset – global offset of this transTmpl (and struct)
transTmpl – instance of TransTmpl which specifies items in struct
- calloc(num, size, keepOut=None, initValues=None) int[source]¶
Allocates a block of memory for an array of num elements, each of them size bytes long, and initializes all its bits to zero.
- Parameters:
num – Number of elements to allocate.
size – Size of each element.
keepOut – optional memory spacing between this memory region and lastly allocated (number of bit between last allocated segment to avoid)
initValues – iterable of word values to init memory with
- Returns:
address (byte step) of allocated memory
- getBits(start: int, end: int, sign: bool | None) HBitsConst[source]¶
Gets value of bits between selected range from memory
- Parameters:
start – bit address of start of bit of bits
end – bit address of first bit behind bits
- Returns:
instance of BitsVal (derived from SimBits type) which contains copy of selected bits
- hwtLib.abstract.sim_ram.reshapedInitItems(actualCellSize, requestedCellSize, values)[source]¶
Convert array item size and items cnt while size of array remains unchanged
- Parameters:
actualCellSize – actual size of item in array
requestedCellSize – requested size of item in array
values – input array
- Returns:
generator of new items of specified characteristic
hwtLib.abstract.streamBuilder module¶
- class hwtLib.abstract.streamBuilder.AbstractStreamBuilder(parent: HwModule, srcInterface: HwIO | HObjList, name: str | None = None, master_to_slave: bool = True)[source]¶
Bases:
AbstractComponentBuilder- Note:
see
AbstractComponentBuilder- Attention:
this is just abstract class unit classes has to be specified in concrete implementation
- Variables:
~.FifoCls – FIFO unit class
~.FifoAsyncCls – asynchronous FIFO (FIFO with separate clock per port) unit class
~.JoinSelectCls – select order based join unit class
~.JoinFairCls – round robin based join unit class
~.JoinPrioritizedCls – priority based join unit class
~.RegCls – register unit class
~.RegCdcCls – Clock domain crossing register unit class
~.ResizerCls – resizer unit class (used to change data width of an interface)
~.SplitCopyCls – copy based split unit class
~.SplitSelectCls – select order based split unit class (demultiplexer)
~.SplitFairCls – round robin based split unit class
~.SplitPrioritizedCls – priority based split unit class
- FifoAsyncCls = NotImplemented¶
- FifoCls = NotImplemented¶
- JoinFairCls = NotImplemented¶
- JoinPrioritizedCls = NotImplemented¶
- JoinSelectCls = NotImplemented¶
- RegCls = NotImplemented¶
- ResizerCls = NotImplemented¶
- SplitCopyCls = NotImplemented¶
- SplitFairCls = NotImplemented¶
- SplitPrioritizedCls = NotImplemented¶
- SplitSelectCls = NotImplemented¶
- __annotations__ = {}¶
- _genericInstance(hwModuleCls: Type[HwModule], name: str, set_params_fn: Callable[[HwModule], None] | None = None, update_params=True, propagate_clk_rst=True, connect_in_out=True)[source]¶
Instantiate generic component and connect basics
- Parameters:
hwModuleCls – class of HMoudule which is being created
name – name for hwModuleCls instance
set_params_fn – function which updates parameters as is required (parameters are already shared with self.end interface)
- classmethod _join(joinCls: Type[HwModule], parent: HwModule, srcHwIOs: Sequence[HwIO], name: str | None, configAs: HwModule | None, extraConfigFn: Callable[[HwModule], None] | None)[source]¶
Create builder from many interfaces by joining them together
- Parameters:
joinCls – join component class which should be used
parent – unit where builder should place components
srcInterfacecs – sequence of interfaces which should be joined together (lower index = higher priority)
configureAs – interface or another object which configuration should be applied
extraConfigFn – function which is applied on join unit in configuration phase (can be None)
- buff(items: int = 1, latency: None | int | Tuple[int, int] = None, delay: int | None = None, init_data: tuple = ())[source]¶
Use registers and FIFOs to create buffer of specified parameters :note: if items <= latency registers are used else FIFO is used
- Parameters:
items – number of items in buffer
latency – latency of buffer (number of clk ticks required to get data from input to input)
delay – delay of buffer (number of clk ticks required to get data to buffer)
init_data – a reset value of buffer (data is transferred after reset) if items=1 and interface has just data:uint8_t signal the init_data will be in format ((0,),)
- Note:
delay can be used as synchronization method or to solve timing related problems because it will split valid signal path
- Note:
if latency or delay is None the most optimal value is used
- buff_cdc(clk: HwIOClk | RtlSignal, rst: HwIORst | HwIORst_n | RtlSignal, items: int = 1)[source]¶
Instantiate a CDC (Clock Domain Crossing) buffer or AsyncFifo on selected interface
- Note:
if items==1 CDC clock synchronization register is used if items>1 asynchronous FIFO is used
- classmethod join_fair(parent, srcInterfaces, name=None, configAs=None, exportSelected=False, extraConfigFn: Callable[[HwModule], None] | None = None)[source]¶
create builder from fairly joined interfaces (round robin for input select)
- Parameters:
exportSelected – if True join component will have handshaked interface with index of selected input
- Note:
other parameters same as in .AbstractStreamBuilder._join
- classmethod join_prioritized(parent: HwModule, srcInterfaces, name: str | None = None, configAs: HwModule | None = None, extraConfigFn: Callable[[HwModule], None] | None = None)[source]¶
create builder from fairly joined interfaces (round robin for input select)
- Note:
other parameters same as in .AbstractStreamBuilder._join
- split_copy(noOfOutputs: int)[source]¶
Clone input data to all outputs
- Parameters:
noOfOutputs – number of output interfaces of the split
- split_copy_to(*outputs: Sequence[HwIO])[source]¶
Same like split_copy, but outputs are automatically connected
- Parameters:
outputs – ports on which should be outputs of split component connected to
- split_fair(noOfOutputs: int, exportSelected=False)[source]¶
Create a round robin selector with number of outputs specified by noOfOutputs
- Parameters:
noOfOutputs – number of outputs of multiplexer
exportSelected – if is True split component will have interface “selectedOneHot” of type VldSynced wich will have one hot index of selected item
- split_fair_to(*outputs: Sequence[HwIO], exportSelected=False)[source]¶
Same like split_fair, but outputs are automatically connected
- Parameters:
outputs – ports on which should be outputs of split component connected to
exportSelected – if is True split component will have interface “selectedOneHot” of type VldSynced which will have one hot index of selected item
- split_prioritized(noOfOutputs: int)[source]¶
data from input is send to output which is ready and has highest priority from all ready outputs
- Parameters:
noOfOutputs – number of output interfaces of the fork
- split_prioritized_to(*outputs: Sequence[HwIO])[source]¶
Same like split_prioritized, but outputs are automatically connected
- Parameters:
outputs – ports on which should be outputs of split component connected to
- split_select(outputSelSignalOrSequence: Sequence[RtlSignalBase] | RtlSignalBase, noOfOutputs: int)[source]¶
Create a de-multiplexer with number of outputs specified by noOfOutputs
- Parameters:
noOfOutputs – number of outputs of multiplexer
outputSelSignalOrSequence – handshaked interface (onehot encoded) to control selected output or sequence of output indexes which should be used (will be repeated)
- split_select_to(outputSelSignalOrSequence: Sequence[RtlSignalBase] | RtlSignalBase, *outputs: Sequence[HwIO])[source]¶
Same like split_select, but outputs are automatically connected
- Parameters:
outputs – ports on which should be outputs of split component connected to
hwtLib.abstract.template_configured module¶
- hwtLib.abstract.template_configured.HdlType_separate(t: HdlType, do_separate_query: Callable[[HdlType], bool]) Generator[Tuple[bool, HdlType], None, None][source]¶
Split HStruct type hierachy on the specified fields to multiple type definitions.
- class hwtLib.abstract.template_configured.TemplateConfigured(structT: HdlType, tmpl: TransTmpl | None = None, frames: List[FrameTmpl] | None = None)[source]¶
Bases:
objectClass with functions for extracting metadata from frame template/HdlType. Used for resolving of data mapping between abstract type and physical interface.
- __init__(structT: HdlType, tmpl: TransTmpl | None = None, frames: List[FrameTmpl] | None = None)[source]¶
- Parameters:
structT – instance of HStruct used as template for this frame If name is None no input port is generated and space is filled with invalid values, little-endian encoding, supported types of interfaces are: Handshaked, Signal can be also instance of FrameTmpl
tmpl – instance of TransTmpl for this structT
frames – list of FrameTmpl instances for this tmpl
- Note:
if tmpl and frames are None they are resolved from structT parseTemplate