def _config(self): self.DATA_WIDTH = Param(8) self.FORMAT = Param( ("AxiS_strFormat" ": hex: 0x", AxiS_strFormatItem(TypePath("data"), 'x', 32 // 4), ", dec: ", AxiS_strFormatItem(TypePath("data"), 'd', BinToBcd.decadic_deciamls_for_bin(32)), " is the value of data from example")) self.INPUT_T = Param(HStruct((uint32_t, "data"), )) self.ENCODING = Param("utf-8")
def _loadFromHStruct(self, dtype: HdlType, bitAddr: int): """ Parse HStruct type to this transaction template instance :return: address of it's end """ for f in dtype.fields: t = f.dtype isPadding = f.name is None if isPadding: width = t.bit_length() bitAddr += width else: origin = (*self.origin, f) fi = TransTmpl(t, bitAddr, parent=self, origin=origin, rel_field_path=TypePath(f.name,), ) self.children.append(fi) bitAddr = fi.bitAddrEnd return bitAddr
def walkFlatten(self, offset: int=0, shouldEnterFn=_default_shouldEnterFn ) -> Generator[ Union[Tuple[Tuple[int, int], 'TransTmpl'], 'OneOfTransaction'], None, None]: """ Walk fields in instance of TransTmpl :param offset: optional offset for all children in this TransTmpl :param shouldEnterFn: function (transTmpl) which returns True when field should be split on it's children :param shouldEnterFn: function(transTmpl) which should return (shouldEnter, shouldUse) where shouldEnter is flag that means iterator should look inside of this actual object and shouldUse flag means that this field should be used (=generator should yield it) :return: generator of tuples ((startBitAddress, endBitAddress), TransTmpl instance) """ t = self.dtype base = self.bitAddr + offset end = self.bitAddrEnd + offset shouldEnter, shouldYield = shouldEnterFn(self) if shouldYield: yield ((base, end), self) if shouldEnter: if isinstance(t, Bits): pass elif isinstance(t, HStruct): for c in self.children: yield from c.walkFlatten( offset, shouldEnterFn) elif isinstance(t, (HArray, HStream)): itemSize = (self.bitAddrEnd - self.bitAddr) // self.itemCnt for i in range(self.itemCnt): if i == 0: c = self.children else: # spot a new array item c = deepcopy(self.children) assert c.rel_field_path == (0,), c.rel_field_path # replace the index c.rel_field_path = TypePath(i, ) yield from c.walkFlatten( base + i * itemSize, shouldEnterFn) elif isinstance(t, HUnion): yield OneOfTransaction(self, offset, shouldEnterFn, self.children) else: raise TypeError(t)
def getFieldPath(self): """ Get field path which specifies the location in original HdlType data type """ path = [] tmpl = self while tmpl is not None: path.extend(reversed(tmpl.rel_field_path)) tmpl = tmpl.parent return TypePath(*reversed(path))
def _reg(self, name: str, dtype: HdlType = BIT, def_val: Union[int, None, dict, list] = None, clk: Union[RtlSignalBase, None, Tuple[RtlSignalBase, OpDefinition]] = None, rst: Optional[RtlSignalBase] = None) -> RtlSyncSignal: """ Create RTL FF register in this unit :param def_val: s default value of this register, if this value is specified reset signal of this component is used to generate a reset logic :param clk: optional clock signal specification, (signal or tuple(signal, edge type (AllOps.RISING_EDGE/FALLING_EDGE))) :param rst: optional reset signal specification :note: rst/rst_n resolution is done from signal type, if it is negated type the reset signal is interpreted as rst_n :note: if clk or rst is not specified default signal from parent unit instance will be used """ if clk is None: clk = getClk(self) if def_val is None: # if no value is specified reset is not required rst = None elif rst is None: rst = getRst(self) if isinstance(dtype, HStruct): container = HdlType_to_Interface(dtype) container._loadDeclarations() flattened_def_val = {} _flatten_map(TypePath(), def_val, flattened_def_val) for path, intf in container._fieldsToInterfaces.items(): if isinstance(intf, Signal): _def_val = flattened_def_val.get(path, None) intf._sig = self._reg( "%s_%s" % (name, intf._getFullName(separator_getter=lambda x: "_")), intf._dtype, def_val=_def_val) return container elif isinstance(dtype, HArray): raise NotImplementedError() return self._ctx.sig(name, dtype=dtype, clk=clk, syncRst=rst, def_val=def_val)
def _loadFromArray(self, dtype: HdlType, bitAddr: int) -> int: """ Parse HArray type to this transaction template instance :return: address of it's end """ self.itemCnt = int(dtype.size) self.children = TransTmpl( dtype.element_t, 0, parent=self, origin=(*self.origin, 0), rel_field_path=TypePath(0,) ) return bitAddr + self.itemCnt * self.children.bitAddrEnd
def _loadFromUnion(self, dtype: HdlType, bitAddr: int) -> int: """ Parse HUnion type to this transaction template instance :return: address of it's end """ for f in dtype.fields.values(): ch = TransTmpl(f.dtype, 0, parent=self, origin=(*self.origin, f), rel_field_path=TypePath(f.name,), ) self.children.append(ch) return bitAddr + dtype.bit_length()
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._structT = structT self._instantiateFieldFn = instantiateFieldFn self._fieldsToInterfaces = {}
def _loadFromHStream(self, dtype: HStream, bitAddr: int) -> int: """ Parse HStream type to this transaction template instance :return: address of it's end """ self.children = TransTmpl( dtype.element_t, 0, parent=self, origin=self.origin, rel_field_path=TypePath(0,)) if not isinstance(dtype.len_min, int) or dtype.len_min != dtype.len_max: raise ValueError("This template is ment only" " for types of constant and finite size") self.itemCnt = dtype.len_min return bitAddr + dtype.element_t.bit_length() * self.itemCnt
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 mebers (othervise this interface is useless)" self._instantiateFieldFn = instantiateFieldFn self._fieldsToInterfaces = {}
def __init__(self, dtype: HdlType, bitAddr: int=0, parent: Optional['TransTmpl']=None, origin: Optional[HStructField]=None, rel_field_path: TypePath=TypePath()): self.parent = parent assert isinstance(dtype, HdlType), dtype assert isinstance(rel_field_path, TypePath), rel_field_path assert parent is None or isinstance(parent, TransTmpl), parent if origin is None: origin = (dtype,) else: assert isinstance(origin, tuple), origin self.origin = origin self.dtype = dtype self.children = [] self.itemCnt = None self.rel_field_path = rel_field_path self._loadFromHType(dtype, bitAddr)
def axiS_strFormat(parent: Unit, name: str, data_width: int, format_str: str, *args, **kwargs): """ Instanciate an :class:`hwtLib.amba.axis_comp.strformat.AxiS_strFormat` using simplified str.format syntax The syntax is allows for an utf-8 string with a variable format groups and several escape sequences in addition to normal string escape sequences. The escape sequences are (same as :func:`str.format`) +=======+=================+ | char | escape sequence | +=======+=================+ | { | {{ | +-------+-----------------+ | } | }} | +-------+-----------------+ The syntax for format group is as folowing: .. code-block:: text {[index/name]:[nuber_of_digits][type]} * The index or name specifies the name or the index of the input parameter. * The width specifies how mahy digits should the output have. * Format types can be found at :class:`hwtLib.amba.axis_comp.strformat.AxiS_strFormatItem` * If nuber_of_digits starts with 0 the leading zeros will be used instead of default space char (' ') * The sign char is included in nuber_of_digits ('{0:04X}'.format(-1) == '-001') * The type is described in :class:`hwtLib.amba.axis_comp.strformat.AxiS_strFormatItem` """ f = AxiS_strFormat() f.DATA_WIDTH = data_width # construct input t for configuration arg_prefix = "arg_" while True: arg_names = [f"{arg_prefix}{a_i}" for a_i, _ in enumerate(args)] if not kwargs: break else: colliding = False for a in arg_names: if a in kwargs.keys(): colliding = True if colliding: arg_prefix = f"{arg_prefix}0_" else: break in_intf_name_tuples = [ *zip(args, arg_names), *[(a, a_name) for a_name, a in sorted(kwargs.items(), key=lambda x: x[0])] ] format_items = tuple(_parse_format_groups(format_str)) for fi in format_items: if isinstance(fi, str): continue elif isinstance(fi.member_path[0], int): # convert arg index to name in input interface fi.member_path = TypePath(arg_names[fi.member_path[0]]) arg_usage = {} for fi in format_items: if isinstance(fi, str): continue usage_cnt = arg_usage.get(fi.member_path, 0) + 1 arg_usage[fi.member_path] = usage_cnt if fi.format_type == 's': assert usage_cnt == 1, ( "string arguments may be used only once as string is consumed") for i, (a, a_name) in enumerate(in_intf_name_tuples): assert arg_usage.get(TypePath(a_name), 0) > 0, ( "arg ", i, " named ", a_name, " not used during formating") if in_intf_name_tuples: struct_members = [] for a, a_name in in_intf_name_tuples: if isinstance(a, AxiStream): t = HStream(Bits(8), start_offsets=[0]) else: t = Interface_to_HdlType().apply(a) struct_members.append((t, a_name)) f.INPUT_T = HStruct(*struct_members) else: f.INPUT_T = None f.FORMAT = tuple(format_items) # connect inputs setattr(parent, name, f) for a, a_name in in_intf_name_tuples: a_in = getattr(f.data_in, a_name) a_in(a) return f.data_out
def _parse_format_groups( f_str: str) -> Generator[Union[str, AxiS_strFormatItem], None, None]: _tokens = re.split("([\{\}])", f_str) + [ None, ] group_start = None current_group_body = None tokens = iter(enumerate(_tokens)) for i, t in tokens: if t is None: assert group_start is None break t_next = _tokens[i + 1] if group_start is None: if t == "{": if t_next == "{": # escape of { next(tokens) yield t elif t_next == None: raise ValueError( "Group syntax error: missing closing } for { after reading:", tokens[:i + 1]) else: group_start = i elif t == '}': if t_next == '}': # escape of } next(tokens) yield t else: raise ValueError( "Group syntax error: closing } without { after reading:", _tokens[:i + 1]) else: yield t else: if t == "{": raise ValueError( "Group syntax error: { in a group after reading:", _tokens[:i + 1], ", this group starts at", group_start) elif t == "}": if not current_group_body: raise ValueError( "Group syntax error: empty group after reading:", _tokens[:i + 1]) else: f = current_group_body.split(":") name_or_index = f[0] if len(f) == 1: format_type = None digits = None else: assert len(f) == 2, f format_type = f[1] for i, c in enumerate(format_type): if not c.isdigit(): break if i > 0: digits = int(format_type[:i]) else: digits = None format_type = format_type[i:] if name_or_index.isdigit(): name_or_index = int(name_or_index) yield AxiS_strFormatItem(TypePath(name_or_index), format_type, digits) current_group_body = None group_start = None else: assert not current_group_body, ( "group body has to be in a single string chunk", current_group_body, t) current_group_body = t