Exemplo n.º 1
0
    def _impl(self):
        self._parseTemplate()
        bus = self.bus

        def connectRegIntfAlways(regIntf, _addr):
            return (
                c(bus.din, regIntf.dout.data) +
                c(bus.we & bus.en & bus.addr._eq(_addr), regIntf.dout.vld)
            )

        ADDR_STEP = self._getAddrStep()
        if self._directlyMapped:
            readReg = self._reg("readReg", dtype=bus.dout._dtype)
            # tuples (condition, assign statements)
            readRegInputs = []
            for t in self._directlyMapped:
                port = self.getPort(t)
                _addr = t.bitAddr // ADDR_STEP
                connectRegIntfAlways(port, _addr)
                readRegInputs.append((bus.addr._eq(_addr),
                                      readReg(port.din)
                                      ))
            SwitchLogic(readRegInputs)
        else:
            readReg = None

        if self._bramPortMapped:
            BRAMS_CNT = len(self._bramPortMapped)
            bramIndxCases = []
            readBramIndx = self._reg("readBramIndx", Bits(
                log2ceil(BRAMS_CNT + 1), False))
            outputSwitch = Switch(readBramIndx)

            for i, t in enumerate(self._bramPortMapped):
                # if we can use prefix instead of addr comparing do it
                _addr = t.bitAddr // ADDR_STEP
                _addrEnd = t.bitAddrEnd // ADDR_STEP
                port = self.getPort(t)

                _addrVld, _ = self.propagateAddr(bus.addr,
                                                 ADDR_STEP,
                                                 port.addr,
                                                 port.dout._dtype.bit_length(),
                                                 t)

                port.we(bus.we & _addrVld & bus.en)
                port.en(bus.en & _addrVld & bus.en)
                port.din(bus.din)

                bramIndxCases.append((_addrVld, readBramIndx(i)))
                outputSwitch.Case(i, bus.dout(port.dout))

            outputSwitch.Default(bus.dout(readReg))
            SwitchLogic(bramIndxCases,
                        default=readBramIndx(BRAMS_CNT))
        else:
            bus.dout(readReg)
Exemplo n.º 2
0
    def _impl(self):
        self._parseTemplate()
        bus = self.bus

        ADDR_STEP = self._getAddrStep()
        if self._directly_mapped_words:
            readReg = self._reg("readReg", dtype=bus.dout._dtype)
            # tuples (condition, assign statements)
            If(bus.en,
               self.connect_directly_mapped_read(bus.addr, readReg, [])
            )
            self.connect_directly_mapped_write(bus.addr, bus.din, bus.en & bus.we)
        else:
            readReg = None

        if self._bramPortMapped:
            BRAMS_CNT = len(self._bramPortMapped)
            bramIndxCases = []
            readBramIndx = self._reg("readBramIndx", Bits(
                log2ceil(BRAMS_CNT + 1), False))
            outputSwitch = Switch(readBramIndx)

            for i, ((_, _), t) in enumerate(self._bramPortMapped):
                # if we can use prefix instead of addr comparing do it
                _addr = t.bitAddr // ADDR_STEP
                _addrEnd = t.bitAddrEnd // ADDR_STEP
                port = self.getPort(t)

                _addrVld, _ = self.propagateAddr(bus.addr,
                                                 ADDR_STEP,
                                                 port.addr,
                                                 port.dout._dtype.bit_length(),
                                                 t)

                port.we(bus.en & bus.we & _addrVld)
                port.en(bus.en & _addrVld)
                port.din(bus.din)

                bramIndxCases.append((_addrVld, readBramIndx(i)))
                outputSwitch.Case(i, bus.dout(port.dout))

            outputSwitch.Default(bus.dout(readReg))
            SwitchLogic(bramIndxCases,
                        default=readBramIndx(BRAMS_CNT))
        else:
            bus.dout(readReg)
Exemplo n.º 3
0
    def readPart(self, awAddr, w_hs):
        ADDR_STEP = self._getAddrStep()
        # build read data output mux
        r = self.bus.r
        ar = self.bus.ar
        rSt_t = HEnum('rSt_t', ['rdIdle', 'bramRd', 'rdData'])
        isBramAddr = self._sig("isBramAddr")

        rSt = FsmBuilder(self, rSt_t, stateRegName='rSt')\
        .Trans(rSt_t.rdIdle,
            (ar.valid & ~isBramAddr & ~w_hs, rSt_t.rdData),
            (ar.valid & isBramAddr & ~w_hs, rSt_t.bramRd)
        ).Trans(rSt_t.bramRd,
            (~w_hs, rSt_t.rdData)
        ).Trans(rSt_t.rdData,
            (r.ready, rSt_t.rdIdle)
        ).stateReg

        arRd = rSt._eq(rSt_t.rdIdle)
        ar.ready(arRd & ~w_hs)

        # save ar addr
        arAddr = self._reg('arAddr', ar.addr._dtype)
        If(ar.valid & arRd, arAddr(ar.addr))

        isInAddrRange = self.isInMyAddrRange(arAddr)
        r.valid(rSt._eq(rSt_t.rdData))
        self.driveResp(isInAddrRange, r.resp)
        if self._bramPortMapped:
            rdataReg = self._reg("rdataReg", r.data._dtype)
            _isInBramFlags = []
            # list of tuples (cond, rdataReg assignment)
            rregCases = []
            # index of bram from where we reads from
            bramRdIndx = self._reg("bramRdIndx",
                                   Bits(log2ceil(len(self._bramPortMapped))))
            bramRdIndxSwitch = Switch(bramRdIndx)
            for bramIndex, ((base, end), t) in enumerate(self._bramPortMapped):
                port = self.getPort(t)

                # map addr for bram ports
                dstAddrStep = port.dout._dtype.bit_length()
                (_isMyArAddr,
                 arAddrConnect) = self.propagateAddr(ar.addr, ADDR_STEP,
                                                     port.addr, dstAddrStep, t)
                (_,
                 ar2AddrConnect) = self.propagateAddr(arAddr, ADDR_STEP,
                                                      port.addr, dstAddrStep,
                                                      t)
                (_isMyAwAddr,
                 awAddrConnect) = self.propagateAddr(awAddr, ADDR_STEP,
                                                     port.addr, dstAddrStep, t)
                prioritizeWrite = w_hs & _isMyAwAddr

                If(prioritizeWrite,
                   awAddrConnect).Elif(rSt._eq(rSt_t.rdIdle),
                                       arAddrConnect).Else(ar2AddrConnect)
                _isInBramFlags.append(_isMyArAddr)

                port.en((ar.valid & _isMyArAddr) | prioritizeWrite)
                port.we(prioritizeWrite)

                rregCases.append((_isMyArAddr, bramRdIndx(bramIndex)))
                bramRdIndxSwitch.Case(bramIndex, rdataReg(port.dout))

            bramRdIndxSwitch.Default(rdataReg(rdataReg))
            If(arRd, SwitchLogic(rregCases))
            isBramAddr(Or(*_isInBramFlags))

        else:
            rdataReg = None
            isBramAddr(0)

        self.connect_directly_mapped_read(arAddr, r.data, r.data(rdataReg))
Exemplo n.º 4
0
    def _impl(self):
        """
        Purpose of this method
        In this method all public interfaces and configuration
        has been made and they can not be edited.
        """
        # create local variable to make code shorter
        a = self.a
        b = self.b

        # "call" is overloaded to do assignment
        # it means c = a + b in target HDL
        # type conversion is can be done by _auto_cast or _reinterpret_cast method call
        self.c(a + b._auto_cast(a._dtype))

        # width of signals is not same, this would raise TypeError on regular assignment,
        # this behavior can be overriden by calling connect with fit=True
        self.fitted(a, fit=True)

        # every signal/value has _dtype attribute which is parent type
        # most of the types have physical size, bit_lenght returns size of this type in bits
        assert self.a._dtype.bit_length() == 32

        # it is possible to create signal explicitly by calling ._sig method
        # result of every operator is signal
        const_private_signal = self._sig("const_private_signal",
                                         dtype=uint32_t, def_val=123)
        self.contOut(const_private_signal)

        # this signal will be optimized out because it has no effect on any output
        # self.d will remain because it is part of interface
        self._sig("optimizedOut", dtype=uint32_t, def_val=123)

        # by _reg function usual d-register can be instantiated
        # to be able to use this this unit has to have clock defined
        # (you can force any signal as clock if you call self._ctx._reg directly)
        # default type is BIT
        r = self._reg("r", def_val=0)

        # HDL If statement is object
        # ~ is negation operator
        If(~r,
           # you can directly assign to register and it will assign to its next value
           # (assigned value appears in it in second clk tick)
           r(self.e)
        )

        # again signals has to affect output or they will be optimized out
        self.f(r)

        # instead of and, or, xor use &, |, ^ because they are overridden to do the job
        tmp0 = a[1] & b[1]
        tmp1 = (a[0] ^ b[0]) | a[1]

        # bit concatenation is done by Concat function, python like slicing supported
        self.g(Concat(tmp0, tmp1, a[6:]))

        # results of comparison operators assigned to bits of cmp signal
        cmp = self.cmp
        cmp[0](a < 4)
        cmp[1](a > 4)
        cmp[2](b <= 4)
        cmp[3](b >= 4)
        cmp[4](b != 4)
        # _eq() is used as ==,
        # overriding == would have many unintended consequences in python
        # (it would make all signals unhashable)
        cmp[5](b._eq(4))

        h = self.h
        # all statements are just objects
        statements0 = h(0)
        statements1 = h(1)
        statements2 = h(2)
        statements3 = foo(r, statements0, a[1], statements1, statements2)
        assert isinstance(statements3, If)
        If(a[2],
            # also when there is not value specified in the branch of dataflow
            # (in this case there is missing else branch) this signal will become latched
            statements3
        )

        # all statements like If, Switch, For and others are in hwt.code

        # names of generated signals are patched to avoid collisions automatically
        r0 = self._reg("r", Bits(2), def_val=0)
        r1 = self._reg("r", Bits(2), def_val=0)

        r0(self.i)
        r1(r0)

        # type of signal can be array as well, this allow to create memories like BRAM...
        # ROM will be synchronous ROM in this case
        rom = self._sig("rom", uint8_t[4], def_val=[i for i in range(4)])

        If(self.clk._onRisingEdge(),
           self.j(rom[r1])
        )

        self.out(0)
        # None is converted to value with zero validity mask
        # same as self.output._dtype.from_py(0, vld_mask=0)
        self.output(None)

        # statements are code-generator frendly
        stm = \
        Switch(a).Case(1,
            self.sc_signal(0)
        ).Case(2,
           self.sc_signal(1)
        )
        compileTimeCondition = True

        if compileTimeCondition:
            stm.Case(3,
               self.sc_signal(3)
            ).Default(
               self.sc_signal(4)
            )

        # ram working on falling edge of clk
        # note that rams are usually working on rising edge
        fRam = self._sig("fallingEdgeRam", int8_t[4])
        If(self.clk._onFallingEdge(),
           # fit can extend signal and also shrink it
           fRam[r1](a, fit=True),
           self.k(fRam[r1]._unsigned(), fit=True)
        )
Exemplo n.º 5
0
    def readPart(self, awAddr, w_hs):
        ADDR_STEP = self._getAddrStep()
        DW = int(self.DATA_WIDTH)
        # build read data output mux
        r = self.bus.r
        ar = self.bus.ar
        rSt_t = HEnum('rSt_t', ['rdIdle', 'bramRd', 'rdData'])
        isBramAddr = self._sig("isBramAddr")

        rSt = FsmBuilder(self, rSt_t, stateRegName='rSt')\
        .Trans(rSt_t.rdIdle,
            (ar.valid & ~isBramAddr & ~w_hs, rSt_t.rdData),
            (ar.valid & isBramAddr & ~w_hs, rSt_t.bramRd)
        ).Trans(rSt_t.bramRd,
            (~w_hs, rSt_t.rdData)
        ).Trans(rSt_t.rdData,
            (r.ready, rSt_t.rdIdle)
        ).stateReg

        arRd = rSt._eq(rSt_t.rdIdle)
        ar.ready(arRd & ~w_hs)

        # save ar addr
        arAddr = self._reg('arAddr', ar.addr._dtype)
        If(ar.valid & arRd, arAddr(ar.addr))

        isInAddrRange = self.isInMyAddrRange(arAddr)
        r.valid(rSt._eq(rSt_t.rdData))
        If(isInAddrRange, r.resp(RESP_OKAY)).Else(r.resp(RESP_SLVERR))
        if self._bramPortMapped:
            rdataReg = self._reg("rdataReg", r.data._dtype)
            _isInBramFlags = []
            # list of tuples (cond, rdataReg assignment)
            rregCases = []
            # index of bram from where we reads from
            bramRdIndx = self._reg("bramRdIndx",
                                   Bits(log2ceil(len(self._bramPortMapped))))
            bramRdIndxSwitch = Switch(bramRdIndx)
            for bramIndex, t in enumerate(self._bramPortMapped):
                port = self.getPort(t)

                # map addr for bram ports
                dstAddrStep = port.dout._dtype.bit_length()
                (_isMyArAddr,
                 arAddrConnect) = self.propagateAddr(ar.addr, ADDR_STEP,
                                                     port.addr, dstAddrStep, t)
                (_,
                 ar2AddrConnect) = self.propagateAddr(arAddr, ADDR_STEP,
                                                      port.addr, dstAddrStep,
                                                      t)
                (_isMyAwAddr,
                 awAddrConnect) = self.propagateAddr(awAddr, ADDR_STEP,
                                                     port.addr, dstAddrStep, t)
                prioritizeWrite = _isMyAwAddr & w_hs

                If(prioritizeWrite,
                   awAddrConnect).Elif(rSt._eq(rSt_t.rdIdle),
                                       arAddrConnect).Else(ar2AddrConnect)
                _isInBramFlags.append(_isMyArAddr)

                port.en((_isMyArAddr & ar.valid) | prioritizeWrite)
                port.we(prioritizeWrite)

                rregCases.append((_isMyArAddr, bramRdIndx(bramIndex)))
                bramRdIndxSwitch.Case(bramIndex, rdataReg(port.dout))

            bramRdIndxSwitch.Default(rdataReg(rdataReg))
            If(arRd, SwitchLogic(rregCases))
            isBramAddr(Or(*_isInBramFlags))

        else:
            rdataReg = None
            isBramAddr(0)

        directlyMappedWors = []
        for w, items in sorted(groupedby(
                self._directlyMapped, lambda t: t.bitAddr // DW *
            (DW // ADDR_STEP)),
                               key=lambda x: x[0]):
            lastBit = 0
            res = []
            items.sort(key=lambda t: t.bitAddr)
            for t in items:
                b = t.bitAddr % DW
                if b > lastBit:
                    # add padding
                    pad_w = b - lastBit
                    pad = Bits(pad_w).fromPy(None)
                    res.append(pad)
                    lastBit += pad_w
                din = self.getPort(t).din
                res.append(din)
                lastBit += din._dtype.bit_length()

            if lastBit != DW:
                # add at end padding
                pad = Bits(DW - lastBit).fromPy(None)
                res.append(pad)

            directlyMappedWors.append((w, Concat(*reversed(res))))

        Switch(arAddr).addCases([
            (w[0], r.data(w[1])) for w in directlyMappedWors
        ]).Default(r.data(rdataReg))
Exemplo n.º 6
0
    def _create_frame_build_logic(self):
        self.byteOrderCare = get_byte_order_modifier(self.dataOut)

        STRB_ALL = mask(int(self.DATA_WIDTH // 8))
        words = list(self.chainFrameWords())
        dout = self.dataOut
        maxWordIndex = words[-1][0]
        multipleWords = maxWordIndex > 0
        if multipleWords:
            # multiple word frame
            wordCntr_inversed = self._reg("wordCntr_inversed",
                                          Bits(log2ceil(maxWordIndex + 1),
                                               False),
                                          def_val=maxWordIndex)
            wcntrSw = Switch(wordCntr_inversed)

        # inversed indexes of ends of frames
        endsOfFrames = []
        extra_strbs = []
        extra_keeps = []
        for i, transParts, isLast in words:
            inversedIndx = maxWordIndex - i

            # input ports for value of this output word
            inPorts = []
            # input ports which value should be consumed on this word
            lastInPorts = []
            if multipleWords:
                wordData = self._sig(f"word{i:d}", dout.data._dtype)
            else:
                wordData = self.dataOut.data

            sk_stash = StrbKeepStash()
            for tPart in transParts:
                strb, keep = self.connectPartsOfWord(wordData, tPart, inPorts,
                                                     lastInPorts)
                sk_stash.push(strb, keep)
            sk_stash.pop(inversedIndx, extra_strbs, extra_keeps, STRB_ALL)

            if multipleWords:
                en = wordCntr_inversed._eq(inversedIndx)
            else:
                en = True
            en = self.dataOut.ready & en

            ack = self.handshakeLogicForWord(inPorts, lastInPorts, en)

            inStreamLast = True
            for p in inPorts:
                if isinstance(p, AxiStream):
                    inStreamLast = p.last & inStreamLast

            if multipleWords:
                # word cntr next logic
                if i == maxWordIndex:
                    nextWordIndex = maxWordIndex
                else:
                    nextWordIndex = wordCntr_inversed - 1

                _ack = dout.ready & ack & inStreamLast

                a = [
                    If(_ack, wordCntr_inversed(nextWordIndex)),
                ]
            else:
                a = []

            a.append(dout.valid(ack))

            # frame with multiple words (using wordCntr_inversed)
            if multipleWords:
                # data out logic
                a.append(dout.data(wordData))
                wcntrSw.Case(inversedIndx, a)

            # is last word in frame
            if isLast:
                endsOfFrames.append((inversedIndx, inStreamLast))

        # to prevent latches
        if not multipleWords:
            pass
        elif not isPow2(maxWordIndex + 1):
            default = [
                wordCntr_inversed(maxWordIndex),
            ]
            default.append(dout.valid(0))
            default.append(dout.data(None))

            wcntrSw.Default(default)

        if multipleWords:
            last = False
            last_last = last
            for indexOrTuple in endsOfFrames:
                i, en = indexOrTuple
                last_last = wordCntr_inversed._eq(i) & en
                last = (last_last) | last

            selectRegLoad = last_last & dout.ready & ack
        else:
            last = endsOfFrames[0][1]
            selectRegLoad = dout.ready & ack

        for r in self._tmpRegsForSelect.values():
            r.rd(selectRegLoad)
        dout.last(last)

        if multipleWords:
            if self.USE_STRB:
                strb = dout.strb
                Switch(wordCntr_inversed).add_cases([
                    (i, strb(v)) for i, v in extra_strbs
                ]).Default(strb(STRB_ALL))
            if self.USE_KEEP:
                keep = dout.keep
                Switch(wordCntr_inversed).add_cases([
                    (i, keep(v)) for i, v in extra_keeps
                ]).Default(keep(STRB_ALL))
        else:
            if extra_strbs:
                m = extra_strbs[0][1]
            else:
                m = STRB_ALL
            if self.USE_STRB:
                dout.strb(m)

            if extra_keeps:
                m = extra_keeps[0][1]
            else:
                m = STRB_ALL

            if self.USE_KEEP:
                dout.keep(m)
Exemplo n.º 7
0
    def _impl(self) -> None:
        _string_rom, strings_offset_and_size, max_chars_per_format, max_bcd_digits = self.build_string_rom(
        )
        if self.DATA_WIDTH != 8:
            # it self.DATA_WIDTH != 1B we need to handle all possible alignments and shifts, precompute some strings
            # because number of string memory ports is limited etc.
            raise NotImplementedError()
        # instanciate bin_to_bcd if required
        if max_bcd_digits > 0:
            bin_to_bcd = BinToBcd()
            bin_to_bcd.INPUT_WIDTH = log2ceil(10**max_bcd_digits - 1)
            self.bin_to_bcd = bin_to_bcd
        # tuples (cond, input)
        to_bcd_inputs = []

        string_rom = self._sig("string_rom",
                               Bits(8)[len(_string_rom)],
                               def_val=[int(c) for c in _string_rom])
        char_i = self._reg("char_i",
                           Bits(log2ceil(max_chars_per_format), signed=False),
                           def_val=0)

        # create an iterator over all characters
        element_cnt = len(self.FORMAT)
        dout = self.data_out
        if element_cnt == 1:
            en = 1
            f_i = 0
            f = self.FORMAT[f_i]
            _, out_vld, out_last = self.connect_single_format_group(
                f_i, f, strings_offset_and_size, string_rom, char_i,
                to_bcd_inputs, en)
            char_i_rst = out_last
        else:
            main_st = self._reg("main_st",
                                Bits(log2ceil(element_cnt), signed=False),
                                def_val=0)
            char_i_rst = out_last = out_vld = BIT.from_py(0)
            main_st_fsm = Switch(main_st)
            for is_last_f, (f_i, f) in iter_with_last(enumerate(self.FORMAT)):
                en = main_st._eq(f_i)
                data_drive, in_vld, in_last = self.connect_single_format_group(
                    f_i, f, strings_offset_and_size, string_rom, char_i,
                    to_bcd_inputs, en)
                # build out vld from all input valids
                out_vld = out_vld | (en & in_vld)
                # keep only last of the last part
                out_last = en & in_last
                char_i_rst = char_i_rst | out_last
                main_st_fsm.Case(
                    f_i,
                    If(dout.ready & in_vld & in_last,
                       main_st(0) if is_last_f else main_st(main_st + 1)),
                    *data_drive)
            main_st_fsm.Default(main_st(None), dout.data(None))

        dout.valid(out_vld)
        dout.last(out_last)
        If(dout.ready & out_vld,
           If(char_i_rst, char_i(0)).Else(char_i(char_i + 1)))

        if to_bcd_inputs:
            in_ = bin_to_bcd.din
            SwitchLogic(
                # actual value may be smaller, because bcd is shared among
                # multiple input formats
                [(c, in_.data(fitTo(v, in_.data, shrink=False)))
                 for c, v in to_bcd_inputs],
                default=in_.data(None))
            in_.vld(char_i._eq(0) & Or(*(c for c, _ in to_bcd_inputs)))
            propagateClkRstn(self)
Exemplo n.º 8
0
    def _impl(self):
        """
        Iterate over words in template and create stream output mux and fsm.
        Frame specifier can contains unions/streams/padding/unaligned items and other
        features which makes code below complex.
        Frame specifier can also describe multiple frames.
        """
        if self.IS_BIGENDIAN:
            byteOrderCare = reverseByteOrder
        else:

            def byteOrderCare(sig):
                return sig

        self.byteOrderCare = byteOrderCare

        words = list(self.chainFrameWords())
        dout = self.dataOut
        self.parseTemplate()
        maxWordIndex = words[-1][0]
        multipleWords = maxWordIndex > 0
        if multipleWords:
            # multiple word frame
            wordCntr_inversed = self._reg("wordCntr_inversed",
                                          Bits(log2ceil(maxWordIndex + 1),
                                               False),
                                          defVal=maxWordIndex)
            wcntrSw = Switch(wordCntr_inversed)

        # inversed indexes of ends of frames
        endsOfFrames = []
        extra_strbs = []
        for i, transParts, isLast in words:
            inversedIndx = maxWordIndex - i

            # input ports for value of this output word
            inPorts = []
            # input ports witch value should be consumed on this word
            lastInPorts = []
            if multipleWords:
                wordData = self._sig("word%d" % i, dout.data._dtype)
            else:
                wordData = self.dataOut.data

            for tPart in transParts:
                extra_strb = self.connectPartsOfWord(wordData, tPart, inPorts,
                                                     lastInPorts)
                if extra_strb is not None:
                    if len(transParts) > 1:
                        raise NotImplementedError(
                            "Construct rest of the strb signal")
                    extra_strbs.append((inversedIndx, extra_strb))

            if multipleWords:
                en = wordCntr_inversed._eq(inversedIndx)
            else:
                en = True
            en = self.dataOut.ready & en

            ack = self.handshakeLogicForWord(inPorts, lastInPorts, en)

            inStreamLast = True
            for p in inPorts:
                if isinstance(p, AxiStream):
                    inStreamLast = p.last & inStreamLast

            if multipleWords:
                # word cntr next logic
                if i == maxWordIndex:
                    nextWordIndex = maxWordIndex
                else:
                    nextWordIndex = wordCntr_inversed - 1

                _ack = dout.ready & ack & inStreamLast

                a = [
                    If(_ack, wordCntr_inversed(nextWordIndex)),
                ]
            else:
                a = []

            a.append(dout.valid(ack))

            # frame with multiple words (using wordCntr_inversed)
            if multipleWords:
                # data out logic
                a.append(dout.data(wordData))
                wcntrSw.Case(inversedIndx, a)

            # is last word in frame
            if isLast:
                endsOfFrames.append((inversedIndx, inStreamLast))

        # to prevent latches
        if not multipleWords:
            pass
        elif not isPow2(maxWordIndex + 1):
            default = wordCntr_inversed(maxWordIndex)
            default.append(dout.valid(0))
            default.append(dout.data(None))

            wcntrSw.Default(default)

        if multipleWords:
            last = False
            last_last = last
            for indexOrTuple in endsOfFrames:
                i, en = indexOrTuple
                last_last = wordCntr_inversed._eq(i) & en
                last = (last_last) | last

            selectRegLoad = last_last & dout.ready & ack
        else:
            last = endsOfFrames[0][1]
            selectRegLoad = dout.ready & ack

        for r in self._tmpRegsForSelect.values():
            r.rd(selectRegLoad)
        dout.last(last)

        strb = dout.strb
        STRB_ALL = mask(int(self.DATA_WIDTH // 8))
        if multipleWords:

            Switch(wordCntr_inversed).addCases([
                (i, strb(v)) for i, v in extra_strbs
            ]).Default(strb(STRB_ALL))
        else:
            if extra_strbs:
                strb(extra_strbs[0][1])
            else:
                strb(STRB_ALL)