Пример #1
0
class AxiS_FrameJoin_3x_in_1B_on_5B_TC(AxiS_FrameJoin_1x_2B_TC):
    D_B = 5
    T = HStruct(
        (HStream(Bits(8 * 1), (1, inf), [0]), "frame0"),
        (HStream(Bits(8 * 1), (1, inf), [0]), "frame1"),
        (HStream(Bits(8 * 1), (1, inf), [0]), "frame2"),
    )
Пример #2
0
 def _config(self):
     self.T = Param(HStruct(
         (HStream(Bits(8), frame_len=(1, inf),
                  start_offsets=[0]), "f0"),
         (HStream(Bits(16), frame_len=(1, 1)), "f1"),
     ))
     AxiStream._config(self)
     self.DATA_WIDTH = 16
     self.USE_KEEP = True
     self.OUT_OFFSET = Param(0)
Пример #3
0
 def test_separate_streams_simple(self):
     t = HStruct(
         (HStream(Bits(8)), "data"),
         (Bits(32), "footer"),
     )
     sep = list(separate_streams(t))
     self.assertSequenceEqual(sep,
                              [(True, HStruct(
                                  (HStream(Bits(8)), "data"), )),
                               (False, HStruct((Bits(32), "footer"), ))])
Пример #4
0
def to_primitive_stream_t(t: HdlType):
    """
    Convert type to a HStream of Bits
    With proper frame len, offset etc.
    """
    if isinstance(t, HStruct) and len(t.fields) == 1:
        return to_primitive_stream_t(t.fields[0].dtype)
    frame_len = (1, 1)
    start_offsets = [0, ]
    if isinstance(t, HStream):
        e_t = t.element_t
        if isinstance(e_t, Bits):
            return t
        else:
            frame_len = t.frame_len
            start_offsets = t.start_offsets
            t = e_t

    try:
        bit_len = t.bit_length()
    except TypeError:
        bit_len = None

    if bit_len is not None:
        return HStream(Bits(bit_len),
                       frame_len=frame_len,
                       start_offsets=start_offsets)
    else:
        raise NotImplementedError(t)
Пример #5
0
    def test_fsm0(self):
        word_bytes = 2
        f_len = (1, 1)
        streams = [
            HStream(Bits(8), frame_len=f_len, start_offsets=[1]),
        ]
        out_offset = 0
        sju = FrameAlignmentUtils(word_bytes, out_offset)
        input_B_dst = sju.resolve_input_bytes_destinations(streams)
        tt = input_B_dst_to_fsm(word_bytes, len(streams), input_B_dst)

        def st(d):
            return StateTransItem.from_dict(tt, d)

        ref = [
            [
                st({
                    'st': '0->0',
                    'in': [[{
                        'keep': [0, 1],
                        'relict': 0,
                        'last': 1
                    }]],
                    'in.keep_mask': [[[0, 0]]],
                    'in.rd': [1],
                    'out.keep': [1, 0],
                    'out.mux': [(0, 0, 1), None],
                    'out.last': 1
                })
            ],
        ]

        self.assertSequenceEqual(tt.state_trans, ref)
Пример #6
0
def get_packet_data_t(usb_ver: USB_VER):
    max_frame_len = USB_MAX_FRAME_LEN[usb_ver]
    # pid has to be one of DATA_0, DATA_1, DATA_2, DATA_M
    return HStruct(
        (pid_t, "pid"),
        (HStream(Bits(8), frame_len=(1, max_frame_len)), "data"),
        (crc16_t, "crc"),
    )
Пример #7
0
    def test_fsm_1x3B_on_2B_offset_1(self):
        word_bytes = 2
        streams = [
            HStream(Bits(8 * 3), (1, 1), [1]),
        ]
        out_offset = 0
        sju = FrameAlignmentUtils(word_bytes, out_offset)
        input_B_dst = sju.resolve_input_bytes_destinations(streams)
        tt = input_B_dst_to_fsm(word_bytes, len(streams), input_B_dst)

        def st(d):
            return StateTransItem.from_dict(tt, d)

        ref = [[
            st({
                'st':
                '0->0',
                'in': [[{
                    'keep': [0, 1],
                    'relict': 1,
                    'last': 1
                }, {
                    'keep': ['X', 'X'],
                    'relict': 'X',
                    'last': 'X'
                }]],
                'in.keep_mask': [[[0, 0], [1, 1]]],
                'in.rd': [1],
                'out.keep': [1, 0],
                'out.mux': [(0, 0, 1), None],
                'out.last':
                1
            }),
            st({
                'st':
                '0->0',
                'in': [[{
                    'keep': [0, 1],
                    'relict': 'X',
                    'last': 0
                }, {
                    'keep': [1, 1],
                    'relict': 'X',
                    'last': 1
                }]],
                'in.keep_mask': [[[0, 0], [0, 1]]],
                'in.rd': [1],
                'out.keep': [1, 1],
                'out.mux': [(0, 0, 1), (0, 1, 0)],
                'out.last':
                0
            })
        ]]
        self.assertSequenceEqual(tt.state_trans, ref)
Пример #8
0
def _example_AxiS_frameParser():
    from hwtLib.types.ctypes import uint8_t, uint16_t, uint32_t, uint64_t
    # t = HStruct(
    #  (uint64_t, "item0"),  # tuples (type, name) where type has to be instance of Bits type
    #  (uint64_t, None),  # name = None means this field will be ignored
    #  (uint64_t, "item1"),
    #  (uint64_t, None),
    #  (uint16_t, "item2"),
    #  (uint16_t, "item3"),
    #  (uint32_t, "item4"),
    #  (uint32_t, None),
    #  (uint64_t, "item5"),  # this word is split on two bus words
    #  (uint32_t, None),

    #  (uint64_t, None),
    #  (uint64_t, None),
    #  (uint64_t, None),
    #  (uint64_t, "item6"),
    #  (uint64_t, "item7"),
    #  (HStruct(
    #      (uint64_t, "item0"),
    #      (uint64_t, "item1"),
    #   ),
    #   "struct0")
    #  )
    #t = HUnion(
    #   (uint32_t, "a"),
    #   (uint32_t, "b")
    #   )

    # t = HUnion(
    #     (HStruct(
    #         (uint64_t, "itemA0"),
    #         (uint64_t, "itemA1")
    #     ), "frameA"),
    #     (HStruct(
    #         (uint32_t, "itemB0"),
    #         (uint32_t, "itemB1"),
    #         (uint32_t, "itemB2"),
    #         (uint32_t, "itemB3")
    #     ), "frameB")
    # )
    t = HStruct(
        (HStream(uint8_t), "frame0"),
        (uint16_t, "footer")
    )

    u = AxiS_frameParser(t)
    u.USE_STRB = True
    u.DATA_WIDTH = 32
    return u
Пример #9
0
    def test_const_size_stream(self, dataWidth, frame_len, randomize):
        T = HStruct(
            (HStream(Bits(8), frame_len=frame_len), "frame0"),
            (uint16_t, "footer"),
        )
        u = self.mySetUp(dataWidth, T, randomize, use_strb=True)
        u.dataIn._ag.data.extend(
            packAxiSFrame(dataWidth,
                          T.from_py({"frame0": [i + 1 for i in range(frame_len)],
                                     "footer": 2}),
                          withStrb=True,
                          )
            )
        t = 20
        if randomize:
            t *= 3

        self.runMatrixSim2(t, dataWidth, frame_len, randomize)
        off, f = axis_recieve_bytes(u.dataOut.frame0)
        self.assertEqual(off, 0)
        self.assertValSequenceEqual(f, [i + 1 for i in range(frame_len)])
        self.assertValSequenceEqual(u.dataOut.footer._ag.data, [2])
Пример #10
0
    def test_stream_and_footer(self, dataWidth, frame_len, prefix_suffix_as_padding, randomize):
        """
        :note: Footer separation is tested in AxiS_footerSplitTC
            and this test only check that the AxiS_frameParser can connect
            wires correctly
        """
        prefix_padding, suffix_padding = prefix_suffix_as_padding
        T = HStruct(
            (HStream(Bits(8)), "frame0"),
            (uint16_t, "footer"),
        )
        fieldsToUse = set()
        if not prefix_padding:
            fieldsToUse.add("frame0")
        if not suffix_padding:
            fieldsToUse.add("footer")
        _T = HdlType_select(T, fieldsToUse)
        u = self.mySetUp(dataWidth, _T, randomize, use_strb=True)
        v = T.from_py({
            "frame0": [i + 1 for i in range(frame_len)],
            "footer": frame_len + 1
        })
        u.dataIn._ag.data.extend(
            packAxiSFrame(dataWidth, v, withStrb=True)
        )
        t = 20
        if randomize:
            t *= 3

        self.runMatrixSim2(t, dataWidth, frame_len, randomize)

        if not prefix_padding:
            off, f = axis_recieve_bytes(u.dataOut.frame0)
            self.assertEqual(off, 0)
            self.assertValSequenceEqual(f, [i + 1 for i in range(frame_len)])
        if not suffix_padding:
            self.assertValSequenceEqual(u.dataOut.footer._ag.data, [frame_len + 1])
Пример #11
0
1    |<union>|
1    | a.a1  |
1    |   b   |
     ---------
>"""

union0_16b_str = """<FrameTmpl start:0, end:16
     15             0
     -----------------
0    |    <union>    |
0    | a.a1  | a.a0  |
0    |       b       |
     -----------------
>"""

stream0 = HStream(uint8_t, frame_len=2)

stream0_8bit_str = """\
<FrameTmpl start:0, end:16
     7      0
     ---------
0    |  [0]  |
1    |  [1]  |
     ---------
>"""

stream0_16bit_str = """<FrameTmpl start:0, end:16
     15             0
     -----------------
0    |  [1]  |  [0]  |
     -----------------
Пример #12
0
        ), "frameA"),
    (HStruct(
        (uint32_t, "itemB0"),
        (uint32_t, "itemB1"),
        (uint32_t, "itemB2"),
        (uint32_t, "itemB3")
        ), "frameB")
)

unionSimple = HUnion(
    (uint32_t, "a"),
    (int32_t, "b")
)

structStream64 = HStruct(
    (HStream(uint64_t), "streamIn")
)

structStream64before = HStruct(
    (HStream(uint64_t), "streamIn"),
    (uint64_t, "item0"),
)

structStream64after = HStruct(
    (uint64_t, "item0"),
    (HStream(uint64_t), "streamIn"),
)

struct2xStream64 = HStruct(
    (HStream(uint64_t), "streamIn0"),
    (HStream(uint64_t), "streamIn1")
Пример #13
0
    def _impl(self):
        regs = []
        keep_masks = []
        ready = []
        max_lookahead_for_input = self.state_trans_table.max_lookahead_for_input
        # lookahead specifies how many words from inputs has to be loaded
        # in order to resolve output word, it corresponds to a number of input registers-1
        for input_i, stage_cnt in enumerate(max_lookahead_for_input):
            _regs, _keep_masks, _ready = self.generate_input_register(
                                                input_i, stage_cnt + 1)
            regs.append(_regs)
            keep_masks.append(_keep_masks)
            ready.append(_ready)

        out_sel, out_mux_values = self.generate_output_byte_mux(regs)
        self.generate_fsm(regs, out_sel, out_mux_values, keep_masks, ready)
        propagateClkRstn(self)


if __name__ == "__main__":
    from hwt.synthesizer.utils import to_rtl_str
    u = AxiS_FrameJoin()
    D_B = 4
    u.DATA_WIDTH = 8 * D_B
    u.USE_STRB = True
    u.T = HStruct(
        (HStream(Bits(8*1), (1, inf), [0, 1, 2, 3]), "frame0"),
        (HStream(Bits(8*4), (1, 1), [0]), "frame1"),
    )
    print(to_rtl_str(u))
Пример #14
0
class AxiS_FrameJoin_1x_2B_TC(SimTestCase):
    D_B = 2
    FRAME_CNT = 1
    T = HStruct(
        (HStream(Bits(8 * D_B), (1, inf), [0]), "frame0"),
    )

    @classmethod
    def setUpClass(cls):
        u = cls.u = AxiS_FrameJoin()
        u.T = cls.T
        u.DATA_WIDTH = cls.D_W = cls.D_B * 8
        cls.compileSim(u)

    def send(self, input_i, data_B, offset):
        axis_send_bytes(self.u.dataIn[input_i], data_B, offset=offset)

    def recive(self):
        return axis_recieve_bytes(self.u.dataOut)

    def randomize_all(self):
        for din in self.u.dataIn:
            self.randomize(din)
        self.randomize(self.u.dataOut)

    def gen_data(self, data_cntr, size):
        return [(data_cntr + d) & 0xff for d in range(size)]

    def test_nop(self):
        self.randomize_all()
        self.runSim(CLK_PERIOD * 20)
        self.assertEmpty(self.u.dataOut._ag.data)

    def _test_pass_data(self, IN_FRAMES):
        OUT_FRAMES = []
        for f_i in range(len(IN_FRAMES[0])):
            offset = self.u.OUT_OFFSET
            data = []
            for in_frames in IN_FRAMES:
                fdata = in_frames[f_i][1]
                data.extend(fdata)
            OUT_FRAMES.append((offset, data))

        for i, frames in enumerate(IN_FRAMES):
            for f_offset, frame in frames:
                self.send(i, frame, offset=f_offset)

        self.runSim(CLK_PERIOD * (
            len(IN_FRAMES) * len(OUT_FRAMES[0]) * 20 + 100))
        for (ref_offset, ref_frame) in OUT_FRAMES:
            offset, frame = axis_recieve_bytes(self.u.dataOut)

            self.assertEqual(offset, ref_offset)
            self.assertSequenceEqual(frame, ref_frame)

        self.assertEmpty(self.u.dataOut._ag.data)

    def test_pass_data_min_len(self, repeat=10):
        self.randomize_all()
        # [offset, [data]]
        IN_FRAMES = [[] for _ in self.u.dataIn]
        data_cntr = 0
        for _ in range(repeat):
            for f, frames in zip(self.T.fields, IN_FRAMES):
                data_B = f.dtype.element_t.bit_length() // 8
                lmin = f.dtype.len_min
                # lmax = f.dtype.len_max
                # if len(f.dtype.start_offsets) != 1:
                #    raise NotImplementedError()
                for offset in f.dtype.start_offsets:
                    size = data_B * lmin
                    data = self.gen_data(data_cntr, size)
                    frames.append((offset, data))
                    data_cntr += size

        self._test_pass_data(IN_FRAMES)

    def test_pass_data_min_len_plus1(self, repeat=10):
        self.randomize_all()
        # [offset, [data]]
        IN_FRAMES = [[] for _ in self.u.dataIn]
        data_cntr = 0
        for _ in range(repeat):
            for f, frames in zip(self.T.fields, IN_FRAMES):
                data_B = f.dtype.element_t.bit_length() // 8
                lmin = f.dtype.len_min + 1
                lmax = f.dtype.len_max
                if lmin > lmax:
                    lmin = lmax

                # if len(f.dtype.start_offsets) != 1:
                #    raise NotImplementedError()
                for offset in f.dtype.start_offsets:
                    size = data_B * lmin
                    data = self.gen_data(data_cntr, size)
                    frames.append((offset, data))
                    data_cntr += size

        self._test_pass_data(IN_FRAMES)

    def test_pass_data_min_len_plus1_for_non_first(self, repeat=10):
        if len(self.u.dataIn) == 1:
            # test tested by test_pass_data_min_len
            return
        self.randomize_all()
        # [offset, [data]]
        IN_FRAMES = [[] for _ in self.u.dataIn]

        data_cntr = 0
        for _ in range(repeat):
            for i, (f, frames) in enumerate(zip(self.T.fields, IN_FRAMES)):
                data_B = f.dtype.element_t.bit_length() // 8
                lmax = f.dtype.len_max
                lmin = f.dtype.len_min
                if i > 0:
                    lmin += 1

                if lmin > lmax:
                    lmin = lmax

                # if len(f.dtype.start_offsets) != 1:
                #    raise NotImplementedError()
                for offset in f.dtype.start_offsets:
                    size = data_B * lmin
                    data = self.gen_data(data_cntr, size)
                    frames.append((offset, data))
                    data_cntr += size

        self._test_pass_data(IN_FRAMES)
Пример #15
0
class AxiS_FrameJoin_1x_2B_len1_TC(AxiS_FrameJoin_1x_2B_TC):
    D_B = 2
    T = HStruct(
        (HStream(Bits(8 * D_B), (1, 1), [0]), "frame0"),
    )
Пример #16
0
Файл: r.py Проект: mfkiwl/hwtLib
    def dataHandler(self, rErrFlag: RtlSignal, rmSizeOut: TransEndInfo):
        rIn = self.axi.r
        rOut = self.driver.r

        if self.axi.LEN_WIDTH:
            last = rIn.last
        else:
            last = BIT.from_py(1)

        rInLast = last

        if self.useTransSplitting():
            last = rmSizeOut.propagateLast & last

        if self.isAlwaysAligned():
            # without shift logic
            *([
                self.remSizeToStrb(rmSizeOut.rem, rOut.strb, False, rIn.valid
                                   & last),
            ] if self.USE_STRB else []),
            rOut.data(rIn.data)
            rOut.last(last)
            StreamNode(masters=[rIn, rmSizeOut],
                       slaves=[rOut],
                       extraConds={
                           rmSizeOut: rInLast,
                           rOut: ~rErrFlag
                       }).sync()

        else:
            # align shifted incoming read data and optionally merge frames
            aligner = AxiS_FrameJoin()
            aligner.T = HStruct((HStream(
                Bits(self.CHUNK_WIDTH),
                start_offsets=[i // 8 for i in self.getShiftOptions()],
                frame_len=(1, self.MAX_CHUNKS)), "f0"), )
            aligner.USE_STRB = False
            aligner.DATA_WIDTH = self.DATA_WIDTH
            self.aligner = aligner

            isSingleWordOnly = self.CHUNK_WIDTH * self.MAX_CHUNKS <= self.DATA_WIDTH and self.ALIGNAS % (
                self.CHUNK_WIDTH * self.MAX_CHUNKS) == 0
            if isSingleWordOnly:
                first = BIT.from_py(1)
            else:
                # first beat of output frame (not necessary input frame, as multiple input
                # frames could be merged in to a single output frame)
                first = self._reg(f"first", def_val=1)

                If(
                    StreamNode([rIn, rmSizeOut], [
                        aligner.dataIn[0],
                    ]).ack(),
                    first(last),
                )

            aligner.dataIn[0].data(rIn.data)
            aligner.dataIn[0].last(last)
            self.remSizeToStrb(rmSizeOut.rem, aligner.dataIn[0].keep, first,
                               last)

            StreamNode([rIn, rmSizeOut], [
                aligner.dataIn[0],
            ],
                       extraConds={
                           rmSizeOut: ~rErrFlag & rInLast,
                       }).sync()

            if self.USE_STRB:
                rOut.strb(aligner.dataOut.keep)
            rOut.data(aligner.dataOut.data)
            rOut.last(aligner.dataOut.last)

            StreamNode(masters=[
                aligner.dataOut,
            ],
                       slaves=[rOut],
                       extraConds={
                           rOut: ~rErrFlag
                       }).sync()
Пример #17
0
    def delegate_to_children(self):
        if self.SHARED_READY:
            raise NotImplementedError()
        assert len(self.sub_t) == len(self.children),\
            (self.sub_t, self.children)
        if self.OVERFLOW_SUPPORT:
            raise NotImplementedError()
        din = self.dataIn
        if len(self.children) == 2:
            c0, c1 = self.children
            t0, t1 = self.sub_t
            t0_is_padding, t1_is_padding = self.sub_t_is_padding
            t0_const_sized, t1_const_sized = self.sub_t_is_const_sized

            if not t0_const_sized and t1_const_sized:
                # suffix parser, split suffix and parse it in child sub component
                fs = AxiS_footerSplit()
                fs._updateParamsFrom(self)
                fs.FOOTER_WIDTH = t1.bit_length()
                self.footer_split = fs
                fs.dataIn(din)

                prefix_t, prefix = drill_down_in_HStruct_fields(t0, self.dataOut)
                if t0_is_padding:
                    # padding
                    fs.dataOut[0].ready(1)
                else:
                    assert isinstance(prefix_t, HStream), prefix_t
                    prefix(fs.dataOut[0])

                suffix = fs.dataOut[1]
                if t1_is_padding:
                    # ignore suffix entirely
                    suffix.ready(1)
                else:
                    # parse suffix in child component
                    suffix_offsets = next_frame_offsets(prefix_t, self.DATA_WIDTH)
                    if suffix_offsets != [0, ]:
                        # add aligment logic
                        align = AxiS_FrameJoin()
                        align._updateParamsFrom(
                            self,
                            exclude=({"T"}, {}))
                        align.USE_KEEP = True
                        align.USE_STRB = False
                        align.OUT_OFFSET = 0
                        align.T = HStruct(
                            (HStream(t1, frame_len=1,
                                     start_offsets=[x // 8 for x in suffix_offsets]),
                             "f0"))
                        self.suffix_align = align
                        align.dataIn[0](suffix, exclude=[suffix.strb, align.dataIn[0].keep])
                        align.dataIn[0].keep(suffix.strb)
                        suffix = align.dataOut
                        c1.dataIn(suffix, exclude=[suffix.keep,
                                                   c1.dataIn.strb])
                        c1.dataIn.strb(suffix.keep)
                    else:
                        c1.dataIn(suffix)

                if not t1_is_padding:
                    connect_optional(c1.dataOut, self.dataOut)
            elif t0_const_sized and not t1_const_sized:
                # prefix parser, parser prefix in subcomponent
                # and let rest to a suffix
                if not t0_is_padding:
                    connect_optional(c0.dataOut, self.dataOut)
                masters = [din]
                if t1_is_padding:
                    slaves = [c0.dataIn, ]
                    extraConds = {
                       c0.dataIn: ~c0.parsing_overflow,
                    }
                    skipWhen = {
                       c0.dataIn: ~c0.parsing_overflow,
                    }
                else:
                    suffix_t, suffix = drill_down_in_HStruct_fields(t1, self.dataOut)
                    assert isinstance(suffix_t, HStream), suffix_t
                    t1_offset = c0._structT.bit_length() % self.DATA_WIDTH
                    if t1_offset == 0:
                        # t1 is aligned on word boundary
                        # and does not require any first word mask modification
                        slaves = [c0.dataIn, suffix]
                        extraConds = {
                           c0.dataIn: ~c0.parsing_overflow,
                           suffix: c0.parsing_overflow,
                        }
                        skipWhen = {
                           c0.dataIn: ~c0.parsing_overflow,
                           suffix: c0.parsing_overflow,
                        }
                    else:
                        raise NotImplementedError("prefix parser- modify mask for suffix")

                StreamNode(masters, slaves,
                           extraConds=extraConds,
                           skipWhen=skipWhen).sync()
                c0.dataIn(din, exclude=[din.valid, din.ready])
            else:
                raise NotImplementedError("multiple con-constant size segments")
        else:
            raise NotImplementedError("multiple con-constant size segments")
        propagateClkRstn(self)
Пример #18
0
class AxiS_FrameJoin_2x_1B_TC(AxiS_FrameJoin_1x_2B_TC):
    D_B = 1
    T = HStruct(
        (HStream(Bits(8 * D_B), (1, inf), [0]), "frame0"),
        (HStream(Bits(8 * D_B), (1, inf), [0]), "frame1"),
    )
Пример #19
0
class AxiS_FrameJoin_1x_in_2B_offset_0__1_TC(AxiS_FrameJoin_1x_2B_TC):
    D_B = 2
    T = HStruct(
        (HStream(Bits(8 * D_B), (1, inf), [0]), "frame0"),
        (HStream(Bits(8 * D_B), (1, inf), [1]), "frame1"),
    )
Пример #20
0
class AxiS_FrameJoin_1x_3B_offset_0_1_TC(AxiS_FrameJoin_1x_2B_TC):
    D_B = 2
    T = HStruct(
        (HStream(Bits(8 * 3), (1, 1), [0, 1, ]), "frame0"),
    )
Пример #21
0
class AxiS_FrameJoin_2x_1B_on_2B_offset_1_1_TC(AxiS_FrameJoin_1x_2B_TC):
    D_B = 2
    T = HStruct(
        (HStream(Bits(8 * 1), (1, inf), [1]), "frame0"),
        (HStream(Bits(8 * 1), (1, inf), [1]), "frame1"),
    )
Пример #22
0
 def test_separate_streams_no_fotter(self):
     t = HStruct((HStream(Bits(8)), "data"), )
     sep = list(separate_streams(t))
     self.assertSequenceEqual(sep, [
         (True, t),
     ])
Пример #23
0
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