Example #1
0
    def _impl(self):
        c = self.c
        a = fitTo(self.a, c)
        b = fitTo(self.b, c)

        for dst in [c, self.d]:
            dst(a + b, fit=True)
Example #2
0
    def wReqDriver(self, en, baseIndex, lenByPtrs, inBlockRemain):
        s = self._sig
        wReq = self.wDatapump.req
        BURST_LEN = self.BUFFER_CAPACITY // 2 - 1
        inBlockRemain_asPtrSize = fitTo(inBlockRemain, lenByPtrs)

        # wReq driver
        ringSpace_t = Bits(self.PTR_WIDTH)
        constraingLen = s("constraingSpace", ringSpace_t)

        If(inBlockRemain_asPtrSize < lenByPtrs,
          constraingLen(inBlockRemain_asPtrSize)
        ).Else(
          constraingLen(lenByPtrs)
        )
        reqLen = s("reqLen", wReq.len._dtype)
        If(constraingLen > BURST_LEN,
           reqLen(BURST_LEN)
        ).Else(
           connect(constraingLen, reqLen, fit=True)
        )

        wReq.id(self.ID)
        wReq.addr(self.indexToAddr(baseIndex))
        wReq.rem(0)
        wReq.len(reqLen)
        wReq.vld(en)

        return reqLen
Example #3
0
    def _connectToIter(self, master, exclude=None, fit=False):
        # [todo] implementatino for RtlSignals of HStruct type
        if exclude and (self in exclude or master in exclude):
            return

        if self._interfaces:
            for ifc in self._interfaces:
                if exclude and ifc in exclude:
                    continue

                mIfc = getattr(master, ifc._name)
                if exclude and mIfc in exclude:
                    continue

                if mIfc._masterDir == DIRECTION.OUT:
                    if ifc._masterDir != mIfc._masterDir:
                        raise IntfLvlConfErr("Invalid connection", ifc, "<=",
                                             mIfc)

                    yield from ifc._connectTo(mIfc, exclude=exclude, fit=fit)
                else:
                    if ifc._masterDir != mIfc._masterDir:
                        raise IntfLvlConfErr("Invalid connection", mIfc, "<=",
                                             ifc)

                    yield from mIfc._connectTo(ifc, exclude=exclude, fit=fit)
        else:
            dstSig = toHVal(self)
            srcSig = toHVal(master)

            if fit:
                srcSig = fitTo(srcSig, dstSig)

            yield dstSig(srcSig)
Example #4
0
    def uploadedCntrHandler(self, st, reqAckHasCome, sizeOfitems):
        uploadedCntr = self._reg(
            "uploadedCntr", self.uploaded._dtype, defVal=0)
        self.uploaded(uploadedCntr)

        If(st._eq(stT.waitOnAck) & reqAckHasCome,
           uploadedCntr(uploadedCntr + fitTo(sizeOfitems, uploadedCntr))
        )
Example #5
0
    def uploadedCntrHandler(self, st, reqAckHasCome, sizeOfitems):
        uploadedCntr = self._reg(
            "uploadedCntr", self.uploaded._dtype, def_val=0)
        self.uploaded(uploadedCntr)

        If(st._eq(stT.waitOnAck) & reqAckHasCome,
           uploadedCntr(uploadedCntr + fitTo(sizeOfitems, uploadedCntr))
        )
Example #6
0
    def _connectToIter(self, master, exclude, fit):
        # [todo] implementation for RtlSignals of HStruct type
        if exclude and (self in exclude or master in exclude):
            return

        if self._interfaces:
            seen_master_intfs = []
            for ifc in self._interfaces:
                if exclude and ifc in exclude:
                    mIfc = getattr(master, ifc._name, None)
                    if mIfc is not None:
                        seen_master_intfs.append(mIfc)
                    continue

                mIfc = getattr(master, ifc._name)
                seen_master_intfs.append(mIfc)
                if exclude and mIfc in exclude:
                    continue

                if mIfc._masterDir == DIRECTION.OUT:
                    if ifc._masterDir != mIfc._masterDir:
                        raise IntfLvlConfErr("Invalid connection", ifc, "<=",
                                             mIfc)

                    yield from ifc._connectToIter(mIfc, exclude, fit)
                else:
                    if ifc._masterDir != mIfc._masterDir:
                        raise IntfLvlConfErr("Invalid connection", mIfc, "<=",
                                             ifc)

                    yield from mIfc._connectToIter(ifc, exclude, fit)

            if len(seen_master_intfs) != len(master._interfaces):
                if exclude:
                    # there is a possiblity that the master interface was excluded,
                    # but we did not see it as the interface of the same name was not present on self
                    for ifc in self._interfaces:
                        if ifc in exclude or ifc not in seen_master_intfs:
                            continue
                        else:
                            # ifc is an interface which is extra on master and is missing an equivalent on slave
                            raise InterfaceStructureErr(self, master, exclude)
                else:
                    raise InterfaceStructureErr(self, master, exclude)
        else:
            if master._interfaces:
                raise InterfaceStructureErr(self, master, exclude)

            dstSig = toHVal(self)
            srcSig = toHVal(master)

            if fit:
                srcSig = fitTo(srcSig, dstSig)

            yield dstSig(srcSig)
Example #7
0
    def _impl(self):
        propagateClkRstn(self)
        ITEM_WIDTH = int(self.ITEM_WIDTH)
        DATA_WIDTH = int(self.DATA_WIDTH)
        ITEMS_IN_DATA_WORD = self.ITEMS_IN_DATA_WORD
        ITEM_SIZE_IN_WORDS = 1

        if ITEM_WIDTH % 8 != 0 or ITEM_SIZE_IN_WORDS * DATA_WIDTH != ITEMS_IN_DATA_WORD * ITEM_WIDTH:
            raise NotImplementedError(ITEM_WIDTH)

        req = self.rDatapump.req
        req.id(self.ID)
        req.len(ITEM_SIZE_IN_WORDS - 1)
        req.rem(0)

        if ITEMS_IN_DATA_WORD == 1:
            addr = Concat(self.index.data, vec(0, log2ceil(ITEM_WIDTH // 8)))
            req.addr(self.base + fitTo(addr, req.addr))
            StreamNode(masters=[self.index], slaves=[req]).sync()

            self.item.data(self.rDatapump.r.data)
            StreamNode(masters=[self.rDatapump.r], slaves=[self.item]).sync()

        else:
            r = self.rDatapump.r.data
            f = self.itemSubIndexFifo
            subIndexBits = f.dataIn.data._dtype.bit_length()
            itemAlignBits = log2ceil(ITEM_WIDTH // 8)
            addr = Concat(self.index.data[:subIndexBits],
                          vec(0, itemAlignBits + subIndexBits))

            req.addr(self.base + fitTo(addr, req.addr))
            f.dataIn.data(self.index.data[subIndexBits:])
            StreamNode(masters=[self.index],
                       slaves=[req, f.dataIn]).sync()

            Switch(f.dataOut.data).addCases([
                (ITEMS_IN_DATA_WORD - i - 1, self.item.data(r[(ITEM_WIDTH * (i + 1)): (ITEM_WIDTH * i)]))
                for i in range(ITEMS_IN_DATA_WORD)
                ])
            StreamNode(masters=[self.rDatapump.r, f.dataOut],
                       slaves=[self.item]).sync()
Example #8
0
    def _impl(self):
        propagateClkRstn(self)
        ITEM_WIDTH = int(self.ITEM_WIDTH)
        DATA_WIDTH = int(self.DATA_WIDTH)
        ITEMS_IN_DATA_WORD = self.ITEMS_IN_DATA_WORD
        ITEM_SIZE_IN_WORDS = 1

        if ITEM_WIDTH % 8 != 0 or ITEM_SIZE_IN_WORDS * DATA_WIDTH != ITEMS_IN_DATA_WORD * ITEM_WIDTH:
            raise NotImplementedError(ITEM_WIDTH)

        req = self.rDatapump.req
        req.id(self.ID)
        req.len(ITEM_SIZE_IN_WORDS - 1)
        req.rem(0)

        if ITEMS_IN_DATA_WORD == 1:
            addr = Concat(self.index.data, vec(0, log2ceil(ITEM_WIDTH // 8)))
            req.addr(self.base + fitTo(addr, req.addr))
            StreamNode(masters=[self.index], slaves=[req]).sync()

            self.item.data(self.rDatapump.r.data)
            StreamNode(masters=[self.rDatapump.r], slaves=[self.item]).sync()

        else:
            r = self.rDatapump.r.data
            f = self.itemSubIndexFifo
            subIndexBits = f.dataIn.data._dtype.bit_length()
            itemAlignBits = log2ceil(ITEM_WIDTH // 8)
            addr = Concat(self.index.data[:subIndexBits],
                          vec(0, itemAlignBits + subIndexBits))

            req.addr(self.base + fitTo(addr, req.addr))
            f.dataIn.data(self.index.data[subIndexBits:])
            StreamNode(masters=[self.index], slaves=[req, f.dataIn]).sync()

            Switch(f.dataOut.data).addCases([
                (ITEMS_IN_DATA_WORD - i - 1,
                 self.item.data(r[(ITEM_WIDTH * (i + 1)):(ITEM_WIDTH * i)]))
                for i in range(ITEMS_IN_DATA_WORD)
            ])
            StreamNode(masters=[self.rDatapump.r, f.dataOut],
                       slaves=[self.item]).sync()
Example #9
0
    def _connectToIter(self,
                       master,
                       masterIndex=None,
                       slaveIndex=None,
                       exclude=None,
                       fit=False):
        if exclude and (self in exclude or master in exclude):
            return

        if self._interfaces:
            for ifc in self._interfaces:
                if exclude and ifc in exclude:
                    continue
                mIfc = getattr(master, ifc._name)

                if exclude and mIfc in exclude:
                    continue

                if mIfc._masterDir == DIRECTION.OUT:
                    if ifc._masterDir != mIfc._masterDir:
                        raise IntfLvlConfErr("Invalid connection %s <= %s" %
                                             (repr(ifc), repr(mIfc)))

                    yield from ifc._connectTo(mIfc,
                                              masterIndex=masterIndex,
                                              slaveIndex=slaveIndex,
                                              exclude=exclude,
                                              fit=fit)
                else:
                    if ifc._masterDir != mIfc._masterDir:
                        raise IntfLvlConfErr("Invalid connection %s <= %s" %
                                             (repr(mIfc), repr(ifc)))

                    yield from mIfc._connectTo(ifc,
                                               masterIndex=slaveIndex,
                                               slaveIndex=masterIndex,
                                               exclude=exclude,
                                               fit=fit)
        else:
            dstSig = toHVal(self)
            srcSig = toHVal(master)

            if masterIndex is not None:
                srcSig = aplyIndexOnSignal(srcSig, dstSig._dtype, masterIndex)

            if slaveIndex is not None:
                dstSig = aplyIndexOnSignal(dstSig, srcSig._dtype, slaveIndex)

            if fit:
                srcSig = fitTo(srcSig, dstSig)

            yield dstSig.__pow__(srcSig)
Example #10
0
 def mvDataToW(self, prepareEn, dataMoveEn, reqLen, inBlockRemain,
               nextBlockTransition_out, dataCntr_out):
     f = self.dataFifo.dataOut
     w = self.wDatapump.w
     nextBlockTransition = self._sig("mvDataToW_nextBlockTransition")
     nextBlockTransition(inBlockRemain <= fitTo(reqLen, inBlockRemain) + 1)
     If(
         prepareEn, dataCntr_out(fitTo(reqLen, dataCntr_out)),
         If(nextBlockTransition_out,
            inBlockRemain(self.ITEMS_IN_BLOCK)).Else(
                inBlockRemain(inBlockRemain -
                              (fitTo(reqLen, inBlockRemain) + 1)))).Elif(
                                  dataMoveEn,
                                  If(
                                      StreamNode(masters=[f],
                                                 slaves=[w]).ack(),
                                      dataCntr_out(dataCntr_out - 1)))
     StreamNode(masters=[f], slaves=[w]).sync(dataMoveEn)
     w.data(f.data)
     w.last(dataCntr_out._eq(0))
     w.strb(mask(w.strb._dtype.bit_length()))
     self.dataFifo.dataIn(self.dataIn)
     nextBlockTransition_out(nextBlockTransition & prepareEn)
Example #11
0
    def mvDataToW(self, prepareEn, dataMoveEn, reqLen, inBlockRemain, nextBlockTransition_out, dataCntr_out):
        f = self.dataFifo.dataOut
        w = self.wDatapump.w
        nextBlockTransition = self._sig("mvDataToW_nextBlockTransition")
        nextBlockTransition(inBlockRemain <= fitTo(reqLen, inBlockRemain) + 1)
        If(prepareEn,
            dataCntr_out(fitTo(reqLen, dataCntr_out)),

            If(nextBlockTransition_out,
                inBlockRemain(self.ITEMS_IN_BLOCK)
            ).Else(
                inBlockRemain(inBlockRemain - (fitTo(reqLen, inBlockRemain) + 1))
            )
        ).Elif(dataMoveEn,
            If(StreamNode(masters=[f], slaves=[w]).ack(),
               dataCntr_out(dataCntr_out - 1)
            )
        )
        StreamNode(masters=[f], slaves=[w]).sync(dataMoveEn)
        w.data(f.data)
        w.last(dataCntr_out._eq(0))
        w.strb(mask(w.strb._dtype.bit_length()))
        self.dataFifo.dataIn(self.dataIn)
        nextBlockTransition_out(nextBlockTransition & prepareEn)
Example #12
0
    def baseAddrLogic(self, nextBlockTransition_in):
        """
        Logic for downloading address of next block

        :param nextBlockTransition_in: signal which means that baseIndex should be changed to nextBaseIndex
            if nextBaseAddrReady is not high this signal has no effect (= regular handshake)
        :return: (baseIndex, nextBaseIndex, nextBaseReady is ready and nextBlockTransition_in can be used)
        """
        r = self._reg
        rIn = self.rDatapump.r
        rReq = self.rDatapump.req

        addr_index_t = Bits(self.ADDR_WIDTH - self.ALIGN_BITS)
        baseIndex = r("baseIndex_backup", addr_index_t)
        nextBaseIndex = r("nextBaseIndex", addr_index_t)
        t = HEnum("nextBaseFsm_t", ["uninitialized",
                                   "required",
                                   "pending",
                                   "prepared"])
        isNextBaseAddr = rIn.valid & rIn.id._eq(self.ID)
        nextBaseFsm = FsmBuilder(self, t, "baseAddrLogic_fsm")\
        .Trans(t.uninitialized,
            (self.baseAddr.dout.vld, t.required)
        ).Trans(t.required,
            (rReq.rd, t.pending)
        ).Trans(t.pending,
            (isNextBaseAddr, t.prepared)
        ).Trans(t.prepared,
            (nextBlockTransition_in, t.required)
        ).stateReg

        If(self.baseAddr.dout.vld,
           baseIndex(self.addrToIndex(self.baseAddr.dout.data)),
        ).Elif(nextBlockTransition_in,
           baseIndex(nextBaseIndex)
        )
        self.baseAddr.din(self.indexToAddr(baseIndex))

        If(isNextBaseAddr,
           nextBaseIndex(self.addrToIndex(fitTo(rIn.data, rReq.addr)))
        )
        rIn.ready(1)

        self.rReqHandler(baseIndex, nextBaseFsm._eq(t.required))

        nextBaseReady = nextBaseFsm._eq(t.prepared)
        return baseIndex, nextBaseIndex, nextBaseReady 
Example #13
0
    def baseAddrLogic(self, nextBlockTransition_in):
        """
        Logic for downloading address of next block

        :param nextBlockTransition_in: signal which means that baseIndex
               should be changed to nextBaseIndex if nextBaseAddrReady
               is not high this signal has no effect (= regular handshake)
        :return: (baseIndex, nextBaseIndex, nextBaseReady is ready
                 and nextBlockTransition_in can be used)
        """
        r = self._reg
        rIn = self.rDatapump.r
        rReq = self.rDatapump.req

        addr_index_t = Bits(self.ADDR_WIDTH - self.ALIGN_BITS)
        baseIndex = r("baseIndex_backup", addr_index_t)
        nextBaseIndex = r("nextBaseIndex", addr_index_t)
        t = HEnum("nextBaseFsm_t",
                  ["uninitialized", "required", "pending", "prepared"])
        isNextBaseAddr = rIn.valid & rIn.id._eq(self.ID)
        nextBaseFsm = FsmBuilder(self, t, "baseAddrLogic_fsm")\
        .Trans(t.uninitialized,
            (self.baseAddr.dout.vld, t.required)
        ).Trans(t.required,
            (rReq.rd, t.pending)
        ).Trans(t.pending,
            (isNextBaseAddr, t.prepared)
        ).Trans(t.prepared,
            (nextBlockTransition_in, t.required)
        ).stateReg

        If(
            self.baseAddr.dout.vld,
            baseIndex(self.addrToIndex(self.baseAddr.dout.data)),
        ).Elif(nextBlockTransition_in, baseIndex(nextBaseIndex))
        self.baseAddr.din(self.indexToAddr(baseIndex))

        If(isNextBaseAddr,
           nextBaseIndex(self.addrToIndex(fitTo(rIn.data, rReq.addr))))
        rIn.ready(1)

        self.rReqHandler(baseIndex, nextBaseFsm._eq(t.required))

        nextBaseReady = nextBaseFsm._eq(t.prepared)
        return baseIndex, nextBaseIndex, nextBaseReady
Example #14
0
def _connect(src, dst, exclude, fit):
    if isinstance(src, InterfaceBase):
        if isinstance(dst, InterfaceBase):
            return dst._connectTo(src, exclude=exclude, fit=fit)
        src = src._sig

    assert not exclude, "this intf. is just a signal"
    if src is None:
        src = dst._dtype.fromPy(None)
    else:
        src = toHVal(src)

    if fit:
        src = fitTo(src, dst)

    src = src._auto_cast(dst._dtype)

    return dst(src)
Example #15
0
def _connect(src, dst, exclude, fit):
    # [TODO]: support for RtlSignals of struct type + interface with same signal structure
    if isinstance(src, InterfaceBase):
        if isinstance(dst, InterfaceBase):
            return dst._connectTo(src, exclude=exclude, fit=fit)

    assert not exclude, ("dst does not contain subinterfaces,"
                         " excluded should be already processed in this state",
                         src, dst, exclude)
    if src is None:
        src = dst._dtype.from_py(None)
    else:
        src = toHVal(src)

    if fit:
        src = fitTo(src, dst)

    src = src._auto_cast(dst._dtype)

    return dst(src)
Example #16
0
    def axiWAddrHandler(self, st, baseAddr, actualAddr, lenRem):
        """
        AXI write addr logic
        """
        axi = self.axi
        st_t = st._dtype

        axi.aw.valid(st._eq(st_t.writeAddr))
        axi.aw.addr(actualAddr)
        axi.aw.id(0)
        axi.aw.burst(BURST_INCR)
        axi.aw.cache(CACHE_DEFAULT)

        If(lenRem > self.MAX_BUTST_LEN,
            axi.aw.len(self.MAX_BUTST_LEN - 1)
        ).Else(
            connect(lenRem - 1, axi.aw.len, fit=True)
        )
        axi.aw.lock(LOCK_DEFAULT)
        axi.aw.prot(PROT_DEFAULT)
        axi.aw.size(BYTES_IN_TRANS(self.DATA_WIDTH // 8))
        axi.aw.qos(QOS_DEFAULT)

        # lenRem, actualAddr logic
        Switch(st)\
        .Case(st_t.fullIdle,
            lenRem(self.DATA_LEN),
            actualAddr(baseAddr) 
        ).Case(st_t.writeAddr,
            If(axi.aw.ready,
                If(lenRem > self.MAX_BUTST_LEN,
                   actualAddr(actualAddr + (self.MAX_BUTST_LEN * self.DATA_WIDTH // 8)),
                   lenRem(lenRem - self.MAX_BUTST_LEN)
                ).Else(
                   actualAddr(actualAddr + fitTo(lenRem, actualAddr)),
                   lenRem(0)
                )
            )
        )
Example #17
0
    def axiWAddrHandler(self, st, baseAddr, actualAddr, lenRem):
        """
        AXI write addr logic
        """
        axi = self.axi
        st_t = st._dtype

        axi.aw.valid(st._eq(st_t.writeAddr))
        axi.aw.addr(actualAddr)
        axi.aw.id(0)
        axi.aw.burst(BURST_INCR)
        axi.aw.cache(CACHE_DEFAULT)

        If(lenRem > self.MAX_BUTST_LEN,
            axi.aw.len(self.MAX_BUTST_LEN - 1)
        ).Else(
            axi.aw.len(lenRem - 1, fit=True)
        )
        axi.aw.lock(LOCK_DEFAULT)
        axi.aw.prot(PROT_DEFAULT)
        axi.aw.size(BYTES_IN_TRANS(self.DATA_WIDTH // 8))
        axi.aw.qos(QOS_DEFAULT)

        # lenRem, actualAddr logic
        Switch(st)\
        .Case(st_t.fullIdle,
            lenRem(self.DATA_LEN),
            actualAddr(baseAddr)
        ).Case(st_t.writeAddr,
            If(axi.aw.ready,
                If(lenRem > self.MAX_BUTST_LEN,
                   actualAddr(actualAddr + (self.MAX_BUTST_LEN * self.DATA_WIDTH // 8)),
                   lenRem(lenRem - self.MAX_BUTST_LEN)
                ).Else(
                   actualAddr(actualAddr + fitTo(lenRem, actualAddr)),
                   lenRem(0)
                )
            )
        )
Example #18
0
 def create_char_mux(self, in_, out_, char_i, digits, bits_per_digit):
     """
     Create a MUX which select the degit from input vector.
     Also perform necessary type casting for corner cases.
     """
     in_w = in_._dtype.bit_length()
     Switch(char_i)\
     .add_cases([
         (digits - i - 1,
          out_(
                 fitTo(
                     in_[min((i + 1) * bits_per_digit, in_w): i * bits_per_digit],
                     out_,
                     # moast significant digits may overlap the input size
                     extend=True,
                 )
             )
             if i * bits_per_digit < in_w else
             # case where there are more digits than in the input domain
             out_(0)
         )
         for i in range(digits)])\
     .Default(out_(None))
Example #19
0
    def wReqDriver(self, en, baseIndex, lenByPtrs, inBlockRemain):
        s = self._sig
        wReq = self.wDatapump.req
        BURST_LEN = self.BUFFER_CAPACITY // 2 - 1
        inBlockRemain_asPtrSize = fitTo(inBlockRemain, lenByPtrs)

        # wReq driver
        ringSpace_t = Bits(self.PTR_WIDTH)
        constraingLen = s("constraingSpace", ringSpace_t)

        If(inBlockRemain_asPtrSize < lenByPtrs,
           constraingLen(inBlockRemain_asPtrSize)).Else(
               constraingLen(lenByPtrs))
        reqLen = s("reqLen", wReq.len._dtype)
        If(constraingLen > BURST_LEN,
           reqLen(BURST_LEN)).Else(reqLen(constraingLen, fit=True))

        wReq.id(self.ID)
        wReq.addr(self.indexToAddr(baseIndex))
        wReq.rem(0)
        wReq.len(reqLen)
        wReq.vld(en)

        return reqLen
Example #20
0
    def _impl(self):
        ALIGN_BITS = log2ceil(self.DATA_WIDTH // 8 - 1)
        TIMEOUT_MAX = self.TIMEOUT - 1
        ITEMS = self.ITEMS
        buff = self.buff
        reqAck = self.wDatapump.ack
        req = self.wDatapump.req
        w = self.wDatapump.w

        propagateClkRstn(self)

        sizeOfitems = self._reg("sizeOfItems", Bits(
            buff.size._dtype.bit_length()))

        # aligned base addr
        baseAddr = self._reg("baseAddrReg", Bits(self.ADDR_WIDTH - ALIGN_BITS))
        If(self.baseAddr.dout.vld,
           baseAddr(self.baseAddr.dout.data[:ALIGN_BITS])
        )
        self.baseAddr.din(Concat(baseAddr, Bits(ALIGN_BITS).from_py(0)))

        # offset in buffer and its complement
        offset_t = Bits(log2ceil(ITEMS + 1), signed=False)
        offset = self._reg("offset", offset_t, def_val=0)
        remaining = self._reg("remaining", Bits(
            log2ceil(ITEMS + 1), signed=False), def_val=ITEMS)
        self.buff_remain(remaining, fit=True)

        addrTmp = self._sig("baseAddrTmp", baseAddr._dtype)
        addrTmp(baseAddr + fitTo(offset, baseAddr))

        # req values logic
        req.id(self.ID)
        req.addr(Concat(addrTmp, Bits(ALIGN_BITS).from_py(0)))
        req.rem(0)

        sizeTmp = self._sig("sizeTmp", buff.size._dtype)

        assert (req.len._dtype.bit_length()
                == buff.size._dtype.bit_length() - 1), (
            req.len._dtype.bit_length(), buff.size._dtype.bit_length())

        buffSizeAsLen = self._sig("buffSizeAsLen", buff.size._dtype)
        buffSizeAsLen(buff.size - 1)
        buffSize_tmp = self._sig("buffSize_tmp", remaining._dtype)
        buffSize_tmp(buff.size, fit=True)

        endOfLenBlock = (remaining - 1) < buffSize_tmp

        remainingAsLen = self._sig("remainingAsLen", remaining._dtype)
        remainingAsLen(remaining - 1)

        If(endOfLenBlock,
            req.len(remainingAsLen, fit=True),
            sizeTmp(remaining, fit=True)
        ).Else(
            req.len(buffSizeAsLen, fit=True),
            sizeTmp(buff.size)
        )

        lastWordCntr = self._reg("lastWordCntr", buff.size._dtype, 0)
        w_last = lastWordCntr._eq(1)
        w_ack = w.ready & buff.dataOut.vld

        # timeout logic
        timeoutCntr = self._reg("timeoutCntr", Bits(log2ceil(self.TIMEOUT), False),
                                def_val=TIMEOUT_MAX)
        # buffer is full or timeout
        beginReq = buff.size._eq(self.BUFF_DEPTH) | timeoutCntr._eq(0)
        reqAckHasCome = self._sig("reqAckHasCome")
        reqAckHasCome(reqAck.vld & reqAck.data._eq(self.ID))
        st = FsmBuilder(self, stT)\
            .Trans(stT.waitOnInput,
                (beginReq & req.rd, stT.waitOnDataTx)
            ).Trans(stT.waitOnDataTx,
                    (w_last & w_ack, stT.waitOnAck)
            ).Trans(stT.waitOnAck,
                    (reqAckHasCome, stT.waitOnInput)
            ).stateReg

        If(st._eq(stT.waitOnInput) & beginReq,  # timeout is counting only when there is pending data
            # start new request
            req.vld(1),
            If(req.rd,
                If(endOfLenBlock,
                   offset(0),
                   remaining(ITEMS)
                ).Else(
                    offset(offset + fitTo(buff.size, offset)),
                    remaining(remaining - fitTo(buff.size, remaining))
                ),
                sizeOfitems(sizeTmp),
                timeoutCntr(TIMEOUT_MAX)
            )
        ).Else(
            req.vld(0),
            If(buff.dataOut.vld & st._eq(stT.waitOnInput) & (timeoutCntr != 0),
               timeoutCntr(timeoutCntr - 1)
            )
        )

        reqAck.rd(st._eq(stT.waitOnAck))

        self.uploadedCntrHandler(st, reqAckHasCome, sizeOfitems)

        # it does not matter when lastWordCntr is changing when there is no
        # request
        startSendingData = st._eq(stT.waitOnInput) & beginReq & req.rd
        If(startSendingData,
            lastWordCntr(sizeTmp)
        ).Elif((lastWordCntr != 0) & w_ack,
            lastWordCntr(lastWordCntr - 1)
        )

        buff.dataIn(self.items)

        w.data(buff.dataOut.data, fit=True)

        StreamNode(
            masters=[buff.dataOut],
            slaves=[w]
        ).sync(st._eq(stT.waitOnDataTx))
        w.strb(mask(w.strb._dtype.bit_length()))
        w.last(w_last)
Example #21
0
    def itemUploadLogic(self, baseIndex, nextBaseIndex, nextBaseReady,
                        nextBlockTransition_out):
        r, s = self._reg, self._sig
        f = self.dataFifo
        w = self.wDatapump

        BURST_LEN = self.BUFFER_CAPACITY // 2
        bufferHasData = s("bufferHasData")
        bufferHasData(f.size > (BURST_LEN - 1))
        # we are counting base next addr as item as well
        addr_index_t = Bits(self.ADDR_WIDTH - self.ALIGN_BITS)
        baseIndex = r("baseIndex", addr_index_t)

        dataCntr_t = Bits(log2ceil(BURST_LEN + 1), signed=False)
        # counter of uploading data
        dataCntr = r("dataCntr", dataCntr_t, def_val=0)
        reqLen_backup = r("reqLen_backup", w.req.len._dtype, def_val=0)

        gotWriteAck = w.ack.vld & w.ack.data._eq(self.ID)
        queueHasSpace, lenByPtrs = self.queuePtrLogic(
            fitTo(reqLen_backup, self.wrPtr.din) + 1, gotWriteAck)

        timeout = s("timeout")
        fsm_t = HEnum("itemUploadingFsm_t", [
            "idle", "reqPending", "dataPending_prepare", "dataPending_send",
            "waitForAck"
        ])
        fsm = FsmBuilder(self, fsm_t, "itemUploadLogic_fsm")\
        .Trans(fsm_t.idle,
            (timeout | (bufferHasData & queueHasSpace), fsm_t.reqPending)

        ).Trans(fsm_t.reqPending,
            (w.req.rd, fsm_t.dataPending_prepare)

        ).Trans(fsm_t.dataPending_prepare,
            fsm_t.dataPending_send
        ).Trans(fsm_t.dataPending_send,
            ((~nextBlockTransition_out | nextBaseReady) & dataCntr._eq(0), fsm_t.waitForAck)
        ).Trans(fsm_t.waitForAck,
            (gotWriteAck, fsm_t.idle)
        ).stateReg

        timeout(
            self.timeoutHandler(fsm != fsm_t.idle,
                                (f.size != 0) & queueHasSpace))

        inBlock_t = Bits(log2ceil(self.ITEMS_IN_BLOCK + 1))
        inBlockRemain = r("inBlockRemain_reg",
                          inBlock_t,
                          def_val=self.ITEMS_IN_BLOCK)

        wReqEn = fsm._eq(fsm_t.reqPending)
        reqLen = self.wReqDriver(wReqEn, baseIndex, lenByPtrs, inBlockRemain)

        If(wReqEn & w.req.rd, reqLen_backup(reqLen))

        dataMoveEn = fsm._eq(fsm_t.dataPending_send)
        prepareEn = fsm._eq(fsm_t.dataPending_prepare)
        self.mvDataToW(prepareEn, dataMoveEn, reqLen_backup, inBlockRemain,
                       nextBlockTransition_out, dataCntr)

        If(
            self.baseAddr.dout.vld,
            baseIndex(self.addrToIndex(self.baseAddr.dout.data)),
        ).Elif(prepareEn,
               baseIndex(baseIndex + fitTo(reqLen_backup, baseIndex) +
                         1)).Elif(nextBlockTransition_out,
                                  baseIndex(nextBaseIndex))

        w.ack.rd(fsm._eq(fsm_t.waitForAck))
Example #22
0
    def _impl(self):
        propagateClkRstn(self)
        r, s = self._reg, self._sig
        req = self.rDatapump.req
        f = self.dataFifo
        dIn = self.rDatapump.r
        dBuffIn = f.dataIn

        ALIGN_BITS = self.addrAlignBits()
        ID = self.ID
        BUFFER_CAPACITY = self.BUFFER_CAPACITY
        BURST_LEN = BUFFER_CAPACITY // 2
        ID_LAST = self.ID_LAST
        bufferHasSpace = s("bufferHasSpace")
        bufferHasSpace(f.size < (BURST_LEN + 1))
        # we are counting base next addr as item as well
        inBlock_t = Bits(log2ceil(self.ITEMS_IN_BLOCK + 1))
        ringSpace_t = Bits(self.PTR_WIDTH)

        downloadPending = r("downloadPending", defVal=0)

        baseIndex = r("baseIndex", Bits(self.ADDR_WIDTH - ALIGN_BITS))
        inBlockRemain = r("inBlockRemain_reg", inBlock_t, defVal=self.ITEMS_IN_BLOCK)
        self.inBlockRemain(inBlockRemain)

        # Logic of tail/head
        rdPtr = r("rdPtr", ringSpace_t, defVal=0)
        wrPtr = r("wrPtr", ringSpace_t, defVal=0)
        If(self.wrPtr.dout.vld,
            wrPtr(self.wrPtr.dout.data)
        )
        self.wrPtr.din(wrPtr)
        self.rdPtr.din(rdPtr)

        # this means items are present in memory
        hasSpace = s("hasSpace")
        hasSpace(wrPtr != rdPtr)
        doReq = s("doReq")
        doReq(bufferHasSpace & hasSpace & ~downloadPending & req.rd)
        req.rem(0)
        self.dataOut(f.dataOut)

        # logic of baseAddr and baseIndex
        baseAddr = Concat(baseIndex, vec(0, ALIGN_BITS))
        req.addr(baseAddr)
        self.baseAddr.din(baseAddr)
        dataAck = dIn.valid & In(dIn.id, [ID, ID_LAST]) & dBuffIn.rd

        If(self.baseAddr.dout.vld,
            baseIndex(self.baseAddr.dout.data[:ALIGN_BITS])
        ).Elif(dataAck & downloadPending,
            If(dIn.last & dIn.id._eq(ID_LAST),
               baseIndex(dIn.data[self.ADDR_WIDTH:ALIGN_BITS])
            ).Else(
               baseIndex(baseIndex + 1) 
            )
        )

        sizeByPtrs = s("sizeByPtrs", ringSpace_t)
        sizeByPtrs(wrPtr - rdPtr)

        inBlockRemain_asPtrSize = fitTo(inBlockRemain, sizeByPtrs)
        constraingSpace = s("constraingSpace", ringSpace_t)
        If(inBlockRemain_asPtrSize < sizeByPtrs,
           constraingSpace(inBlockRemain_asPtrSize)
        ).Else(
           constraingSpace(sizeByPtrs)
        )

        constrainedByInBlockRemain = s("constrainedByInBlockRemain")
        constrainedByInBlockRemain(fitTo(sizeByPtrs, inBlockRemain) >= inBlockRemain)

        If(constraingSpace > BURST_LEN,
            # download full burst
            req.id(ID),
            req.len(BURST_LEN - 1),
            If(doReq,
               inBlockRemain(inBlockRemain - BURST_LEN)
            )
        ).Elif(constrainedByInBlockRemain & (inBlockRemain < BURST_LEN),
            # we know that sizeByPtrs <= inBlockRemain thats why we can resize it
            # we will download next* as well
            req.id(ID_LAST),
            connect(constraingSpace, req.len, fit=True),
            If(doReq,
               inBlockRemain(self.ITEMS_IN_BLOCK)
            )
        ).Else(
            # download data leftover
            req.id(ID),
            connect(constraingSpace - 1, req.len, fit=True),
            If(doReq,
               inBlockRemain(inBlockRemain - fitTo(constraingSpace, inBlockRemain))
            )
        )

        # logic of req dispatching
        If(downloadPending,
            req.vld(0),
            If(dataAck & dIn.last,
                downloadPending(0)
            )
        ).Else(
            req.vld(bufferHasSpace & hasSpace),
            If(req.rd & bufferHasSpace & hasSpace,
               downloadPending(1)
            )
        )

        # into buffer pushing logic
        dBuffIn.data(dIn.data)

        isMyData = s("isMyData")
        isMyData(dIn.id._eq(ID) | (~dIn.last & dIn.id._eq(ID_LAST)))
        If(self.rdPtr.dout.vld,
            rdPtr(self.rdPtr.dout.data)
        ).Else(
            If(dIn.valid & downloadPending & dBuffIn.rd & isMyData,
               rdPtr(rdPtr + 1)
            )
        )
        # push data into buffer and increment rdPtr
        StreamNode(masters=[dIn],
                   slaves=[dBuffIn],
                   extraConds={dIn: downloadPending,
                               dBuffIn: (dIn.id._eq(ID) | (dIn.id._eq(ID_LAST) & ~dIn.last)) & downloadPending
                               }).sync()
Example #23
0
    def _impl(self) -> None:
        avalon: AvalonMM = self.m
        axi = self.s

        addr_tmp = self._reg(
            "addr_tmp",
            HStruct(
                (axi.ar.addr._dtype, "addr"),
                (axi.ar.id._dtype, "id"),
                (axi.ar.len._dtype, "len"),
                (BIT, "vld"),
                (BIT, "is_w"),
            ),
            def_val={"vld": 0}
        )
        r_data_ack = self.connect_r_fifo(avalon, axi)

        # contains the available space in read data fifo
        # used to prevent the dispatch of the reads which would
        # cause overflow of read data fifo
        r_data_fifo_capacity = self._reg(
            "r_data_fifo_capacity",
            Bits(log2ceil(self.R_DATA_FIFO_DEPTH + 1)),
            def_val=self.R_DATA_FIFO_DEPTH)

        will_be_idle = ~addr_tmp.vld | \
                       ~addr_tmp.is_w | \
                            (addr_tmp.vld &
                             addr_tmp.is_w &
                             ~avalon.waitRequest &
                             addr_tmp.len._eq(0) &
                             axi.w.valid &
                             axi.b.ready)
        will_be_idle = rename_signal(self, will_be_idle, "will_be_idle")
        r_size_in = self.r_size_fifo.dataIn
        ar_en = will_be_idle & \
                axi.ar.valid & (r_data_fifo_capacity > fitTo(axi.ar.len, r_data_fifo_capacity)) & \
                r_size_in.rd

        is_w = addr_tmp.vld & addr_tmp.is_w
        ready_for_addr = ~addr_tmp.vld | ~avalon.waitRequest
        addr_tmp_ack = rename_signal(self, ~avalon.waitRequest &
                                           ~(
                                               is_w & ~(axi.w.valid & ((addr_tmp.len != 0) | axi.b.ready))
                                            ), "addr_tmp_ack")
        aw_en = ready_for_addr & axi.w.valid & (~addr_tmp.vld | ~addr_tmp.is_w | (addr_tmp.len != 0) | axi.b.ready)
        is_not_last_w = rename_signal(self, is_w & (addr_tmp.len != 0), "is_not_last_w")
        if self.RW_PRIORITY == READ:
            aw_en = ~axi.ar.valid & aw_en
            ar_en = rename_signal(self, ar_en, "ar_en")
            aw_en = rename_signal(self, aw_en, "aw_en")
            If(ar_en,
                # start new read transaction
                self.load_addr_tmp(addr_tmp, axi.ar)
            ).Elif(~avalon.waitRequest & is_not_last_w & axi.w.valid,
                # finishing write transaction (except last word)
                addr_tmp.len(addr_tmp.len - 1),
            ).Elif(will_be_idle & axi.aw.valid & axi.w.valid,
                # start new write transaction
                self.load_addr_tmp(addr_tmp, axi.aw)
            ).Elif(addr_tmp_ack,
                # all transaction finished, clear addr_tmp register
                self.load_addr_tmp(addr_tmp, None)
            )
        else:
            ar_en = ar_en & \
                ~(is_not_last_w) & \
                ~(axi.aw.valid & axi.w.valid)
            ar_en = rename_signal(self, ar_en, "ar_en")
            aw_en = rename_signal(self, aw_en, "aw_en")
            If(~avalon.waitRequest & is_not_last_w & axi.w.valid,
                # finishing write transaction (except last word)
                addr_tmp.len(addr_tmp.len - 1),
            ).Elif(will_be_idle & axi.aw.valid & axi.w.valid,
                # start new write transaction
                self.load_addr_tmp(addr_tmp, axi.aw)
            ).Elif(ar_en,
                # start new read transaction
                self.load_addr_tmp(addr_tmp, axi.ar)
            ).Elif(addr_tmp_ack,
                # all transaction finished, clear addr_tmp register
                self.load_addr_tmp(addr_tmp, None)
            )

        r_size_in.id(axi.ar.id)
        r_size_in.len(axi.ar.len)
        r_size_in.vld(ar_en)

        If(r_data_ack & ar_en,
            r_data_fifo_capacity(r_data_fifo_capacity - fitTo(axi.ar.len, r_data_fifo_capacity))
        ).Elif(r_data_ack,
            r_data_fifo_capacity(r_data_fifo_capacity + 1)
        ).Elif(ar_en,
            r_data_fifo_capacity(r_data_fifo_capacity - 1 - fitTo(axi.ar.len, r_data_fifo_capacity))
        )
        axi.aw.ready(will_be_idle & aw_en)
        axi.ar.ready(will_be_idle & ar_en)

        avalon.address(addr_tmp.addr)
        avalon.burstCount(fitTo(addr_tmp.len, avalon.burstCount) + 1)
        avalon.read(addr_tmp.vld & ~addr_tmp.is_w)
        avalon.write(is_w & axi.w.valid & ((addr_tmp.len != 0) | axi.b.ready))

        avalon.writeData(axi.w.data)
        avalon.byteEnable(axi.w.strb)

        axi.w.ready(
            addr_tmp.vld &
            addr_tmp.is_w &
            ~avalon.waitRequest &
            ((addr_tmp.len != 0) | axi.b.ready)
        )

        axi.b.id(addr_tmp.id)
        axi.b.resp(RESP_OKAY)
        axi.b.valid(addr_tmp.vld &
                    addr_tmp.is_w &
                    ~avalon.waitRequest &
                    axi.w.ready &
                    axi.w.valid &
                    axi.w.last)

        propagateClkRstn(self)
Example #24
0
    def addrHandler(self, req: AddrSizeHs,
                    axiA: Union[Axi3_addr, Axi3Lite_addr, Axi4_addr,
                                Axi4Lite_addr], transInfo: HandshakeSync,
                    errFlag: RtlSignal):
        """
        Propagate read/write requests from req to axi address channel
        and store extra info using transInfo interface.
        """
        r, s = self._reg, self._sig

        self.axiAddrDefaults(axiA)
        if self.ID_WIDTH:
            axiA.id(self.ID_VAL)

        alignmentError = self.hasAlignmentError(req.addr)

        HAS_LEN = self._axiCls.LEN_WIDTH > 0
        if self.useTransSplitting():
            # if axi len is smaller we have to use transaction splitting
            # that means we need to split requests from driver.req to multiple axi requests
            transPartPending = r("transPartPending", def_val=0)
            addrTmp = r("addrTmp", req.addr._dtype)

            dispatchNode = StreamNode([
                req,
            ], [axiA, transInfo],
                                      skipWhen={req: transPartPending.next},
                                      extraConds={
                                          req: ~transPartPending.next,
                                          axiA: req.vld & ~alignmentError,
                                          transInfo: req.vld & ~alignmentError
                                      })
            dispatchNode.sync(~errFlag)
            ack = s("ar_ack")
            ack(dispatchNode.ack() & ~errFlag)

            LEN_MAX = max(mask(self._axiCls.LEN_WIDTH), 0)
            reqLen = s("reqLen", self.getLen_t())
            reqLenRemaining = r("reqLenRemaining", reqLen._dtype)

            If(reqLen > LEN_MAX, *([axiA.len(LEN_MAX)] if HAS_LEN else []),
               self.storeTransInfo(transInfo, 0)).Else(
                   # connect only lower bits of len
                   *([axiA.len(reqLen, fit=True)] if HAS_LEN else []),
                   self.storeTransInfo(transInfo, 1))

            # dispatchNode not used because of combinational loop
            If(
                StreamNode([
                    req,
                ], [axiA, transInfo]).ack() & ~errFlag,
                If(reqLen > LEN_MAX, reqLenRemaining(reqLen - (LEN_MAX + 1)),
                   transPartPending(1)).Else(transPartPending(0)))
            reqLenSwitch = If(
                ~req.vld,
                reqLen(None),
            )
            if not self.isAlwaysAligned():
                crossesWordBoundary = self.isCrossingWordBoundary(
                    req.addr, req.rem)
                reqLenSwitch.Elif(
                    ~self.addrIsAligned(req.addr) & crossesWordBoundary,
                    reqLen(fitTo(req.len, reqLen, shrink=False) + 1),
                )
            reqLenSwitch.Else(reqLen(fitTo(req.len, reqLen, shrink=False)), )

            ADDR_STEP = self.getBurstAddrOffset()
            If(
                transPartPending,
                axiA.addr(self.addrAlign(addrTmp)),
                If(ack, addrTmp(addrTmp + ADDR_STEP)),
                reqLen(reqLenRemaining),
            ).Else(
                axiA.addr(self.addrAlign(req.addr)),
                addrTmp(req.addr + ADDR_STEP),
                reqLenSwitch,
            )

        else:
            # if axi len is wider we can directly translate requests to axi
            axiA.addr(self.addrAlign(req.addr))
            if req.MAX_LEN > 0:
                lenDrive = axiA.len(fitTo(req.len, axiA.len, shrink=False))

                if not self.isAlwaysAligned():
                    crossesWordBoundary = self.isCrossingWordBoundary(
                        req.addr, req.rem)
                    If(
                        ~self.addrIsAligned(req.addr) & crossesWordBoundary,
                        axiA.len(fitTo(req.len, axiA.len) + 1),
                    ).Else(lenDrive, )
            else:
                if HAS_LEN:
                    axiA.len(0)

            self.storeTransInfo(transInfo, 1)
            StreamNode(masters=[req],
                       slaves=[axiA, transInfo],
                       extraConds={
                           axiA: ~alignmentError,
                           transInfo: ~alignmentError,
                       }).sync(~errFlag)
Example #25
0
    def itemUploadLogic(self, baseIndex, nextBaseIndex, nextBaseReady, nextBlockTransition_out):
        r, s = self._reg, self._sig
        f = self.dataFifo
        w = self.wDatapump

        BURST_LEN = self.BUFFER_CAPACITY // 2
        bufferHasData = s("bufferHasData")
        bufferHasData(f.size > (BURST_LEN - 1))
        # we are counting base next addr as item as well
        addr_index_t = Bits(self.ADDR_WIDTH - self.ALIGN_BITS)
        baseIndex = r("baseIndex", addr_index_t)

        dataCntr_t = Bits(log2ceil(BURST_LEN + 1), signed=False)
        dataCntr = r("dataCntr", dataCntr_t, defVal=0)  # counter of uploading data
        reqLen_backup = r("reqLen_backup", w.req.len._dtype, defVal=0)

        gotWriteAck = w.ack.vld & w.ack.data._eq(self.ID)
        queueHasSpace, lenByPtrs = self.queuePtrLogic(fitTo(reqLen_backup, self.wrPtr.din) + 1, gotWriteAck)

        timeout = s("timeout")
        fsm_t = HEnum("itemUploadingFsm_t", ["idle",
                                            "reqPending",
                                            "dataPending_prepare",
                                            "dataPending_send",
                                            "waitForAck"])
        fsm = FsmBuilder(self, fsm_t, "itemUploadLogic_fsm")\
        .Trans(fsm_t.idle,
            (timeout | (bufferHasData & queueHasSpace), fsm_t.reqPending)

        ).Trans(fsm_t.reqPending,
            (w.req.rd, fsm_t.dataPending_prepare)

        ).Trans(fsm_t.dataPending_prepare,
            fsm_t.dataPending_send
        ).Trans(fsm_t.dataPending_send,
            ((~nextBlockTransition_out | nextBaseReady) & dataCntr._eq(0), fsm_t.waitForAck)
        ).Trans(fsm_t.waitForAck,
            (gotWriteAck, fsm_t.idle)    
        ).stateReg

        timeout(self.timeoutHandler(fsm != fsm_t.idle,
                                    (f.size != 0) & queueHasSpace))

        inBlock_t = Bits(log2ceil(self.ITEMS_IN_BLOCK + 1))
        inBlockRemain = r("inBlockRemain_reg", inBlock_t, defVal=self.ITEMS_IN_BLOCK)

        wReqEn = fsm._eq(fsm_t.reqPending)
        reqLen = self.wReqDriver(wReqEn, baseIndex, lenByPtrs, inBlockRemain)

        If(wReqEn & w.req.rd,
           reqLen_backup(reqLen)
        )

        dataMoveEn = fsm._eq(fsm_t.dataPending_send)
        prepareEn = fsm._eq(fsm_t.dataPending_prepare)
        self.mvDataToW(prepareEn, dataMoveEn, reqLen_backup,
                               inBlockRemain, nextBlockTransition_out, dataCntr)

        If(self.baseAddr.dout.vld,
           baseIndex(self.addrToIndex(self.baseAddr.dout.data)),
        ).Elif(prepareEn,
           baseIndex(baseIndex + fitTo(reqLen_backup, baseIndex) + 1)    
        ).Elif(nextBlockTransition_out,
           baseIndex(nextBaseIndex)
        )

        w.ack.rd(fsm._eq(fsm_t.waitForAck))
Example #26
0
    def connect_single_format_group(self, f_i: int,
                                    f: Union[str, AxiS_strFormatItem],
                                    strings_offset_and_size: Dict[Union[int,
                                                                        str],
                                                                  Tuple[int,
                                                                        int]],
                                    string_rom: RtlSignal, char_i: RtlSignal,
                                    to_bcd_inputs: List[Tuple[RtlSignal,
                                                              HdlStatement]],
                                    en: RtlSignal):
        """
        Connect a single formating group or string chunk to output.
        Depending on item type this may involve:

        * iterate the string characters stored in string_rom
        * iterate and translate bin/oct/hex characters
        * register bcd input for later connection
        * connect an input string from an input AxiStream
        """
        dout = self.data_out
        in_vld = BIT.from_py(1)
        res = []
        in_last = None
        string_rom_index_t = Bits(log2ceil(string_rom._dtype.size),
                                  signed=False)
        if isinstance(f, str):
            str_offset, str_size = strings_offset_and_size[f_i]
            str_offset = string_rom_index_t.from_py(str_offset)
            res.append(
                # read char of the string from string_rom
                dout.data(string_rom[str_offset +
                                     fitTo(char_i, str_offset, shrink=False)]))
        else:
            assert isinstance(f, AxiS_strFormatItem), f
            in_ = self.data_in._fieldsToInterfaces[f.member_path]

            if f.format_type in ('d', 'b', 'o', 'x', 'X'):
                if f.format_type == 'd':
                    # first use BCD convertor to convert to BCD
                    to_bcd_inputs.append((en, in_))
                    bcd = self.bin_to_bcd.dout
                    in_vld = bcd.vld
                    bcd.rd(dout.ready & en & char_i._eq(f.digits - 1))
                    in_ = bcd.data

                bits_per_char = AxiS_strFormatItem.BITS_PER_CHAR[f.format_type]
                actual_digit = self._sig(f"f_{f_i}_actual_digit",
                                         Bits(bits_per_char))
                to_str_table_offset, _ = strings_offset_and_size[f.format_type]
                to_str_table_offset = string_rom_index_t.from_py(
                    to_str_table_offset)
                # iterate output digits using char_i
                self.create_char_mux(in_, actual_digit, char_i, f.digits,
                                     bits_per_char)

                res.append(
                    # use char translation table from string_rom to translate digit in to a char
                    dout.data(string_rom[
                        to_str_table_offset +
                        fitTo(actual_digit, to_str_table_offset, shrink=False)]
                              ))

                str_size = f.digits

            else:
                # connect a string from an input AxiStream
                assert f.format_type == 's', f.format_type
                assert in_.DATA_WIDTH == 8, in_.DATA_WIDTH
                assert in_.USE_STRB == False, in_.USE_STRB
                assert in_.USE_KEEP == False, in_.USE_KEEP

                in_vld = in_.valid
                in_.ready(dout.ready & en)
                res.append(dout.data(in_.data))
                in_last = in_.last

        if in_last is None:
            # if signal to detect last character is not overriden use conter to resolve it
            in_last = char_i._eq(str_size - 1)

        return res, in_vld, in_last,
Example #27
0
    def _impl(self):
        c = self.c
        a = fitTo(self.a, c)
        b = fitTo(self.b, c)

        connect(a + b, c, self.d, fit=True)
Example #28
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)
Example #29
0
    def _impl(self):
        REG_IN = self.REG_IN
        REQUIRES_CASCADE = self.REG_OUT and self.DATA_WIDTH > 48

        dsps = HObjList()
        for i in range(ceil(self.DATA_WIDTH / 48)):
            dsp = DSP48E1()
            dsp.A_INPUT = "DIRECT"
            dsp.B_INPUT = "DIRECT"
            dsp.USE_DPORT = "FALSE"

            dsp.ACASCREG = \
            dsp.ALUMODEREG = \
            dsp.AREG = \
            dsp.BCASCREG = \
            dsp.BREG = \
            dsp.CARRYINSELREG = \
            dsp.CREG = int(REG_IN or (REQUIRES_CASCADE and i > 0))

            dsp.ADREG = 0
            dsp.CARRYINSELREG = 0
            dsp.DREG = 0
            dsp.INMODEREG = 0
            dsp.MREG = 0
            dsp.OPMODEREG = 1
            dsp.PREG = int(self.REG_OUT)
            dsp.USE_MULT = "NONE"
            dsp.USE_SIMD = "ONE48"
            dsps.append(dsp)

        self.dsp = dsps

        carry = 0
        carry_column = 0
        dsp_outputs = []
        din = self.data_in
        dout = self.data_out
        dsp_clock_enables = []
        dsp_inputs = []
        for i, dsp in enumerate(dsps):
            offset = i * 48
            width = min(48, self.DATA_WIDTH - offset)
            if width <= 18:
                a = 0
                b = din.b[offset + width:offset]
            else:
                a = din.b[offset + width:18 + offset]
                b = din.b[offset + 18:offset]

            c = din.a[offset + width:offset]
            dsp_inputs.append((a, b, c))

        # register to wait 1 clock before 1st operation to load operation and operand selection registers
        mode_preload = self._reg("mode_preload", def_val=1)
        mode_preload(0)
        if REQUIRES_CASCADE:
            # cascade is required because carry out signal has register and thus the input data
            # to a next DSP has to be delayed
            assert self.REG_OUT
            stage_cnt = int(self.REG_IN) + int(self.REG_OUT) + ceil(self.DATA_WIDTH / 48) - 1
            clock_enables, _, in_ready, out_valid = generate_handshake_pipe_cntrl(
                self, stage_cnt, "pipe_reg", din.vld & ~mode_preload, dout.rd)

            delayed_dsp_inputs = []
            for i, (dsp, (a, b, c)) in enumerate(zip(dsps, dsp_inputs)):
                if self.REG_IN:
                    input_ces = clock_enables[:i]
                    ce_0 = clock_enables[i]
                    ce_1 = clock_enables[i + 1]
                else:
                    if i == 0:
                        # :note: only first does not have in registers
                        ce_0 = 1
                        ce_1 = clock_enables[i]
                        input_ces = []
                    else:
                        ce_0 = clock_enables[i - 1]
                        ce_1 = clock_enables[i]
                        input_ces = clock_enables[:i - 1] # because the last register is a part of DPS

                dsp_clock_enables.append((ce_0, ce_1))

                a_delayed = self.postpone_val(a, input_ces, f"a{i:d}_")
                b_delayed = self.postpone_val(b, input_ces, f"b{i:d}_")
                c_delayed = self.postpone_val(c, input_ces, f"c{i:d}_")
                delayed_dsp_inputs.append((a_delayed, b_delayed, c_delayed))

            dsp_inputs = delayed_dsp_inputs
        else:
            stage_cnt = int(self.REG_IN) + int(self.REG_OUT)
            clock_enables, _, in_ready, out_valid = generate_handshake_pipe_cntrl(
                self, stage_cnt, "pipe_reg", din.vld & ~mode_preload, dout.rd)

            if self.REG_IN:
                ce_0 = clock_enables[0]
            else:
                ce_0 = 1

            if self.REG_OUT:
                if self.REG_IN:
                    ce_1 = clock_enables[1]
                else:
                    ce_1 = clock_enables[0]
            else:
                ce_1 = 1

            for i, dsp in enumerate(dsps):
                dsp_clock_enables.append((mode_preload | ce_0, mode_preload | ce_1))

        dout.vld(out_valid & ~mode_preload)
        din.rd(in_ready & ~mode_preload)

        for i, (dsp, (ce_0, ce_1), (a, b, c)) in enumerate(zip(dsps, dsp_clock_enables, dsp_inputs)):
            offset = i * 48
            width = min(48, self.DATA_WIDTH - offset)

            dsp.CLK(self.clk)
            dsp.ACIN(0)
            dsp.BCIN(0)
            dsp.MULTSIGNIN(1)
            dsp.PCIN(0)
            dsp.CEINMODE(1)
            self.set_mode(dsp)
            dsp.RSTINMODE(0)

            if i == 0:
                dsp.CARRYINSEL(CARRYIN_SEL.CARRYIN.value)
                dsp.CARRYIN(carry)
                dsp.CARRYCASCIN(carry_column)
                carry = dsp.CARRYOUT[3]
                carry_column = dsp.CARRYCASCOUT
            else:
                dsp.CARRYINSEL(CARRYIN_SEL.CARRYCASCIN.value)
                dsp.CARRYIN(0)
                dsp.CARRYCASCIN(carry_column)
                carry_column = dsp.CARRYCASCOUT

            if width <= 18:
                assert isinstance(a, int) and a == 0, a
                dsp.A(a)
                dsp.B(fitTo(b, dsp.B, shrink=False))
                dsp.C(fitTo(c, dsp.C, shrink=False))
            elif width < 48:
                dsp.A(fitTo(a, dsp.A, shrink=False))
                dsp.B(b)
                dsp.C(fitTo(c, dsp.C, shrink=False))
            else:
                dsp.A(a)
                dsp.B(b)
                dsp.C(c)

            dsp.D(0)
            dsp_outputs.append(dsp.P[width:])

            for _ce in [
                    dsp.CEA1,
                    dsp.CEA2,
                    dsp.CEALUMODE,
                    dsp.CEB2,
                    dsp.CEB1,
                    dsp.CEC,
                    dsp.CECARRYIN,
                    dsp.CECTRL,
                ]:
                _ce(ce_0)
            for _ce in [dsp.CEAD, dsp.CED, dsp.CEM]:
                _ce(1)

            dsp.CEP(ce_1)

            for _rst in [dsp.RSTA,
                dsp.RSTALLCARRYIN,
                dsp.RSTALUMODE,
                dsp.RSTB,
                dsp.RSTC,
                dsp.RSTCTRL,
                dsp.RSTD,
                dsp.RSTM,
                dsp.RSTP,]:
                _rst(~self.rst_n)

        if REQUIRES_CASCADE:
            delayed_dsp_outputs = []
            max_delay = len(dsp_outputs) - 1
            for i, out in enumerate(dsp_outputs):
                delay = max_delay - i
                if delay > 0:
                    # select n last
                    ces = clock_enables[-delay:]
                    delayed_out = self.postpone_val(out, ces, f"out_delay_{i:d}")
                else:
                    delayed_out = out
                delayed_dsp_outputs.append(delayed_out)
            dsp_outputs = delayed_dsp_outputs
        dout.data(Concat(*reversed(dsp_outputs)))
Example #30
0
    def _impl(self):
        propagateClkRstn(self)
        r, s = self._reg, self._sig
        req = self.rDatapump.req
        f = self.dataFifo
        dIn = self.rDatapump.r
        dBuffIn = f.dataIn

        ALIGN_BITS = self.addrAlignBits()
        ID = self.ID
        BUFFER_CAPACITY = self.BUFFER_CAPACITY
        BURST_LEN = BUFFER_CAPACITY // 2
        ID_LAST = self.ID_LAST
        bufferHasSpace = s("bufferHasSpace")
        bufferHasSpace(f.size < (BURST_LEN + 1))
        # we are counting base next addr as item as well
        inBlock_t = Bits(log2ceil(self.ITEMS_IN_BLOCK + 1))
        ringSpace_t = Bits(self.PTR_WIDTH)

        downloadPending = r("downloadPending", def_val=0)

        baseIndex = r("baseIndex", Bits(self.ADDR_WIDTH - ALIGN_BITS))
        inBlockRemain = r("inBlockRemain_reg",
                          inBlock_t,
                          def_val=self.ITEMS_IN_BLOCK)
        self.inBlockRemain(inBlockRemain)

        # Logic of tail/head
        rdPtr = r("rdPtr", ringSpace_t, def_val=0)
        wrPtr = r("wrPtr", ringSpace_t, def_val=0)
        If(self.wrPtr.dout.vld, wrPtr(self.wrPtr.dout.data))
        self.wrPtr.din(wrPtr)
        self.rdPtr.din(rdPtr)

        # this means items are present in memory
        hasSpace = s("hasSpace")
        hasSpace(wrPtr != rdPtr)
        doReq = s("doReq")
        doReq(bufferHasSpace & hasSpace & ~downloadPending & req.rd)
        req.rem(0)
        self.dataOut(f.dataOut)

        # logic of baseAddr and baseIndex
        baseAddr = Concat(baseIndex, Bits(ALIGN_BITS).from_py(0))
        req.addr(baseAddr)
        self.baseAddr.din(baseAddr)
        dataAck = dIn.valid & In(dIn.id, [ID, ID_LAST]) & dBuffIn.rd

        If(self.baseAddr.dout.vld,
           baseIndex(self.baseAddr.dout.data[:ALIGN_BITS])).Elif(
               dataAck & downloadPending,
               If(dIn.last & dIn.id._eq(ID_LAST),
                  baseIndex(dIn.data[self.ADDR_WIDTH:ALIGN_BITS])).Else(
                      baseIndex(baseIndex + 1)))

        sizeByPtrs = s("sizeByPtrs", ringSpace_t)
        sizeByPtrs(wrPtr - rdPtr)

        inBlockRemain_asPtrSize = fitTo(inBlockRemain, sizeByPtrs)
        constraingSpace = s("constraingSpace", ringSpace_t)
        If(inBlockRemain_asPtrSize < sizeByPtrs,
           constraingSpace(inBlockRemain_asPtrSize)).Else(
               constraingSpace(sizeByPtrs))

        constrainedByInBlockRemain = s("constrainedByInBlockRemain")
        constrainedByInBlockRemain(
            fitTo(sizeByPtrs, inBlockRemain) >= inBlockRemain)

        If(
            constraingSpace > BURST_LEN,
            # download full burst
            req.id(ID),
            req.len(BURST_LEN - 1),
            If(doReq, inBlockRemain(inBlockRemain - BURST_LEN))
        ).Elif(
            constrainedByInBlockRemain & (inBlockRemain < BURST_LEN),
            # we know that sizeByPtrs <= inBlockRemain thats why we can resize it
            # we will download next* as well
            req.id(ID_LAST),
            req.len(constraingSpace, fit=True),
            If(doReq, inBlockRemain(self.ITEMS_IN_BLOCK))).Else(
                # download data leftover
                req.id(ID),
                req.len(constraingSpace - 1, fit=True),
                If(
                    doReq,
                    inBlockRemain(inBlockRemain -
                                  fitTo(constraingSpace, inBlockRemain))))

        # logic of req dispatching
        If(downloadPending, req.vld(0),
           If(dataAck & dIn.last, downloadPending(0))).Else(
               req.vld(bufferHasSpace & hasSpace),
               If(req.rd & bufferHasSpace & hasSpace, downloadPending(1)))

        # into buffer pushing logic
        dBuffIn.data(dIn.data)

        isMyData = s("isMyData")
        isMyData(dIn.id._eq(ID) | (~dIn.last & dIn.id._eq(ID_LAST)))
        If(self.rdPtr.dout.vld, rdPtr(self.rdPtr.dout.data)).Else(
            If(dIn.valid & downloadPending & dBuffIn.rd & isMyData,
               rdPtr(rdPtr + 1)))
        # push data into buffer and increment rdPtr
        StreamNode(masters=[dIn],
                   slaves=[dBuffIn],
                   extraConds={
                       dIn:
                       downloadPending,
                       dBuffIn: (dIn.id._eq(ID)
                                 | (dIn.id._eq(ID_LAST)
                                    & ~dIn.last)) & downloadPending
                   }).sync()
Example #31
0
    def _impl(self):
        ALIGN_BITS = log2ceil(self.DATA_WIDTH // 8 - 1).val
        TIMEOUT_MAX = self.TIMEOUT - 1
        ITEMS = self.ITEMS
        buff = self.buff
        reqAck = self.wDatapump.ack
        req = self.wDatapump.req
        w = self.wDatapump.w

        propagateClkRstn(self)

        sizeOfitems = self._reg("sizeOfItems", Bits(
            buff.size._dtype.bit_length()))

        # aligned base addr
        baseAddr = self._reg("baseAddrReg", Bits(self.ADDR_WIDTH - ALIGN_BITS))
        If(self.baseAddr.dout.vld,
           baseAddr(self.baseAddr.dout.data[:ALIGN_BITS])
           )
        self.baseAddr.din(Concat(baseAddr, vec(0, ALIGN_BITS)))

        # offset in buffer and its complement
        offset_t = Bits(log2ceil(ITEMS + 1), signed=False)
        offset = self._reg("offset", offset_t, defVal=0)
        remaining = self._reg("remaining", Bits(
            log2ceil(ITEMS + 1), signed=False), defVal=ITEMS)
        connect(remaining, self.buff_remain, fit=True)

        addrTmp = self._sig("baseAddrTmp", baseAddr._dtype)
        addrTmp(baseAddr + fitTo(offset, baseAddr))

        # req values logic
        req.id(self.ID)
        req.addr(Concat(addrTmp, vec(0, ALIGN_BITS)))
        req.rem(0)

        sizeTmp = self._sig("sizeTmp", buff.size._dtype)

        assert req.len._dtype.bit_length() == buff.size._dtype.bit_length() - 1, (
            req.len._dtype.bit_length(), buff.size._dtype.bit_length())

        buffSizeAsLen = self._sig("buffSizeAsLen", buff.size._dtype)
        buffSizeAsLen(buff.size - 1)
        buffSize_tmp = self._sig("buffSize_tmp", remaining._dtype)
        connect(buff.size, buffSize_tmp, fit=True)

        endOfLenBlock = (remaining - 1) < buffSize_tmp

        remainingAsLen = self._sig("remainingAsLen", remaining._dtype)
        remainingAsLen(remaining - 1)

        If(endOfLenBlock,
            connect(remainingAsLen, req.len, fit=True),
            connect(remaining, sizeTmp, fit=True)
        ).Else(
            connect(buffSizeAsLen, req.len, fit=True),
            sizeTmp(buff.size)
        )

        lastWordCntr = self._reg("lastWordCntr", buff.size._dtype, 0)
        w_last = lastWordCntr._eq(1)
        w_ack = w.ready & buff.dataOut.vld

        # timeout logic
        timeoutCntr = self._reg("timeoutCntr", Bits(log2ceil(self.TIMEOUT), False),
                                defVal=TIMEOUT_MAX)
        # buffer is full or timeout
        beginReq = buff.size._eq(self.BUFF_DEPTH) | timeoutCntr._eq(0)
        reqAckHasCome = self._sig("reqAckHasCome")
        reqAckHasCome(reqAck.vld & reqAck.data._eq(self.ID))
        st = FsmBuilder(self, stT)\
            .Trans(stT.waitOnInput,
                (beginReq & req.rd, stT.waitOnDataTx)
            ).Trans(stT.waitOnDataTx,
                    (w_last & w_ack, stT.waitOnAck)
            ).Trans(stT.waitOnAck,
                    (reqAckHasCome, stT.waitOnInput)
            ).stateReg

        If(st._eq(stT.waitOnInput) & beginReq,  # timeout is counting only when there is pending data
            # start new request
            req.vld(1),
            If(req.rd,
                If(endOfLenBlock,
                   offset(0),
                   remaining(ITEMS)
                ).Else(
                    offset(offset + fitTo(buff.size, offset)),
                    remaining(remaining - fitTo(buff.size, remaining))
                ),
                sizeOfitems(sizeTmp),
                timeoutCntr(TIMEOUT_MAX)
            )
        ).Else(
            req.vld(0),
            If(buff.dataOut.vld & st._eq(stT.waitOnInput) & (timeoutCntr != 0),
               timeoutCntr(timeoutCntr - 1)
            )
        )

        reqAck.rd(st._eq(stT.waitOnAck))

        self.uploadedCntrHandler(st, reqAckHasCome, sizeOfitems)

        # it does not matter when lastWordCntr is changing when there is no
        # request
        startSendingData = st._eq(stT.waitOnInput) & beginReq & req.rd
        If(startSendingData,
            lastWordCntr(sizeTmp)
        ).Elif((lastWordCntr != 0) & w_ack,
            lastWordCntr(lastWordCntr - 1)
        )

        buff.dataIn(self.items)

        connect(buff.dataOut.data, w.data, fit=True)

        StreamNode(masters=[buff.dataOut],
                   slaves=[w]
                   ).sync(st._eq(stT.waitOnDataTx))
        w.strb(mask(w.strb._dtype.bit_length()))
        w.last(w_last)