Exemple #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)
Exemple #2
0
    def translate_addr_signal(self, mem_map, sig_in, sig_out):
        cases = []
        AW = sig_in._dtype.bit_length()

        for (offset_in, size, offset_out) in mem_map:
            in_is_aligned = offset_in % size == 0 and isPow2(size)
            out_is_aligned = offset_out % size == 0 and isPow2(size)
            if in_is_aligned:
                L = (size - 1).bit_length()
                en_sig = sig_in[:L]._eq(offset_in >> L)
                _sig_in = sig_in[L:]
                if out_is_aligned:
                    addr_drive = Concat(
                        Bits(AW - L).from_py(offset_out), _sig_in)
                else:
                    addr_drive = Concat(Bits(AW - L).from_py(0),
                                        _sig_in) + offset_out
            else:
                en_sig = inRange(sig_in, offset_in, offset_in + size)
                if offset_in == offset_out:
                    addr_drive = sig_in
                elif offset_in < offset_out:
                    addr_drive = sig_in + (offset_out - offset_in)
                else:
                    # offset_in > offset_out:
                    addr_drive = sig_in - (offset_in - offset_out)
            cases.append((en_sig, sig_out(addr_drive)))
        SwitchLogic(cases, default=sig_out(sig_in))
Exemple #3
0
    def lookupResOfTablesDriver(self, resRead, resAck):
        tables = self.tables
        # one hot encoded index where item should be stored (where was found
        # or where is place)
        targetOH = self._reg("targetOH", Bits(self.TABLE_CNT))

        res = list(map(lambda t: t.lookupRes, tables))
        # synchronize all lookupRes from all tables
        StreamNode(masters=res).sync(resAck)

        insertFinal = self._reg("insertFinal")
        # select empty space or victim witch which current insert item
        # should be swapped with
        lookupResAck = StreamNode(masters=map(
            lambda t: t.lookupRes, tables)).ack()
        insertFoundOH = list(map(lambda t: t.lookupRes.found, tables))
        isEmptyOH = list(map(lambda t:~t.lookupRes.occupied, tables))
        _insertFinal = Or(*insertFoundOH, *isEmptyOH)

        If(resRead & lookupResAck,
            If(Or(*insertFoundOH),
                targetOH(Concat(*reversed(insertFoundOH)))
               ).Else(
                SwitchLogic([(empty, targetOH(1 << i))
                             for i, empty in enumerate(isEmptyOH)
                             ],
                            default=If(targetOH,
                                       targetOH(ror(targetOH, 1))
                                       ).Else(
                    targetOH(1 << (self.TABLE_CNT - 1))
                ))
            ),
            insertFinal(_insertFinal)
           )
        return lookupResAck, insertFinal, insertFoundOH, targetOH
Exemple #4
0
    def _impl(self) -> None:
        if len(self.MASTERS) > 1:
            raise NotImplementedError()

        m = self.s[0]

        wrack = rdack = err = BIT.from_py(0)
        AW = int(self.ADDR_WIDTH)
        rdata = []
        for i, (s, (s_offset, s_size)) in\
                enumerate(zip(self.m, self.SLAVES)):
            s.bus2ip_addr(m.bus2ip_addr, fit=True)
            s.bus2ip_be(m.bus2ip_be)
            s.bus2ip_rnw(m.bus2ip_rnw)
            s.bus2ip_data(m.bus2ip_data)

            bitsOfSubAddr = log2ceil(s_size - 1)
            prefix = get_bit_range(s_offset, bitsOfSubAddr, AW - bitsOfSubAddr)
            cs = self._sig(f"m_cs_{i:d}")
            cs(m.bus2ip_addr[AW:bitsOfSubAddr]._eq(prefix))
            s.bus2ip_cs(m.bus2ip_cs & cs)

            err = err | (cs & s.ip2bus_error)
            rdack = rdack | (cs & s.ip2bus_rdack)
            wrack = wrack | (cs & s.ip2bus_wrack)
            rdata.append((cs, s.ip2bus_data))

        m.ip2bus_error(err)
        m.ip2bus_rdack(rdack)
        m.ip2bus_wrack(wrack)

        SwitchLogic([(sel, m.ip2bus_data(data)) for sel, data in rdata],
                    default=m.ip2bus_data(None))
Exemple #5
0
 def _generate_driver_for_state_trans_dependent_out(
         self, st_transs: List[StateTransItem],
         input_regs,
         value_getter: Callable[[StateTransItem], object],
         connect_out_fn,
         make_defult_case: Optional[Callable[[], object]]):
     """
     specific variant of :func:`generate_driver_for_state_trans_dependent_out` for a single state
     """
     cases = []
     for cond, value in self.get_conds_for_unique_values(
             st_transs, input_regs,
             key=value_getter):
         cases.append((cond, connect_out_fn(value)))
     if make_defult_case is None:
         return SwitchLogic(cases)
     else:
         return SwitchLogic(cases, default=make_defult_case())
Exemple #6
0
    def is_footer_mask_set_values(self, LOOK_AHEAD, regs):
        D_W = self.DATA_WIDTH
        BYTE_CNT = D_W // 8
        FOOTER_WIDTH = self.FOOTER_WIDTH
        din = self.dataIn

        if self.USE_KEEP:
            in_mask = din.keep
        elif self.USE_STRB:
            in_mask = din.strb
        elif self.DATA_WIDTH == 8:
            in_mask = BIT.from_py(1, 1)
        else:
            raise NotImplementedError(
                "keep/strb can be ignored only for DATA_WIDTH=8")

        set_is_footer = self._sig("set_is_footer")
        set_is_footer(din.valid & din.last)
        mask_cases = []
        for last_B_valid, bytes_in_last_input_word in iter_with_last(
                range(1, BYTE_CNT + 1)):
            footer_end = (LOOK_AHEAD * BYTE_CNT + bytes_in_last_input_word) * 8
            footer_start = footer_end - FOOTER_WIDTH
            assert footer_start > 0, (
                "otherwise we would not be able to send last for previous frame",
                footer_start)
            assert footer_start < D_W * 3, (
                "footer start can appear only in last-1 or last-2 regster,"
                " last register is output register", footer_start, D_W)
            _is_footer = set_bit_range(0, footer_start // 8, FOOTER_WIDTH // 8,
                                       mask(FOOTER_WIDTH // 8))
            set_flags = []
            for i, (_, _, is_footer_set_val, _, _) in enumerate(regs):
                if i == 0:
                    is_footer_val = 0
                    is_footer_val_last_word = get_bit_range(
                        _is_footer, (LOOK_AHEAD - i) * BYTE_CNT, BYTE_CNT)
                    set_flags.append(
                        If(set_is_footer,
                           is_footer_set_val(is_footer_val_last_word)).Else(
                               is_footer_set_val(is_footer_val)))
                else:
                    is_footer_val = get_bit_range(
                        _is_footer, (LOOK_AHEAD - i + 1) * BYTE_CNT, BYTE_CNT)
                    set_flags.append(is_footer_set_val(is_footer_val))

            if last_B_valid:
                # last byte also valid
                mask_default = set_flags
            else:
                # last 0 from the end of the validity mask
                mask_cases.append(
                    (~in_mask[bytes_in_last_input_word], set_flags))

        SwitchLogic(mask_cases, mask_default)
        return set_is_footer
Exemple #7
0
 def insertAddrSelect(self, targetOH, state, cleanAddr):
     insertIndex = self._sig("insertIndex", Bits(self.HASH_WITH))
     If(state._eq(state._dtype.cleaning),
         insertIndex(cleanAddr)
        ).Else(
         SwitchLogic([(targetOH[i],
                       insertIndex(t.lookupRes.hash))
                      for i, t in enumerate(self.tables)],
                     default=insertIndex(None))
     )
     return insertIndex
Exemple #8
0
    def _impl(self):
        propagateClkRstn(self)
        dIn = AxiSBuilder(self, self.dataIn).buff().end

        sb = self.sizesBuff
        db = self.dataBuff

        wordCntr = self._reg("wordCntr",
                             Bits(log2ceil(self.MAX_LEN) + 1),
                             def_val=0)

        overflow = wordCntr._eq(self.MAX_LEN)
        last = dIn.last | overflow
        If(
            StreamNode(masters=[dIn], slaves=[sb.dataIn, db.dataIn]).ack(),
            If(last, wordCntr(0)).Else(wordCntr(wordCntr + 1)))

        length = self._sig("length", wordCntr._dtype)
        BYTE_CNT = dIn.data._dtype.bit_length() // 8
        if dIn.USE_STRB:
            # compress strb mask as binary number
            rem = self._sig("rem", Bits(log2ceil(BYTE_CNT)))

            SwitchLogic(cases=[(dIn.strb[i],
                                rem(0 if i == BYTE_CNT - 1 else i + 1))
                               for i in reversed(range(BYTE_CNT))],
                        default=[
                            rem(0),
                        ])
            if self.EXPORT_ALIGNMENT_ERROR:
                errorAlignment = self._reg("errorAlignment_reg", def_val=0)
                self.errorAlignment(errorAlignment)
                If(dIn.valid & (dIn.strb != mask(BYTE_CNT)) & ~dIn.last,
                   errorAlignment(1))

            If(last & (dIn.strb != mask(BYTE_CNT)),
               length(wordCntr)).Else(length(wordCntr + 1))
        else:
            length(wordCntr + 1)
            rem = Bits(log2ceil(BYTE_CNT)).from_py(0)

        sb.dataIn.data(Concat(length, rem))

        db.dataIn(dIn, exclude=[dIn.valid, dIn.ready, dIn.last])
        db.dataIn.last(last)

        StreamNode(masters=[dIn],
                   slaves=[sb.dataIn, db.dataIn],
                   extraConds={
                       sb.dataIn: last
                   }).sync()

        self.sizes(sb.dataOut)
        self.dataOut(db.dataOut)
Exemple #9
0
    def inputMuxLogic(self, isSelectedFlags):
        vld = self.get_valid_signal
        dout = self.dataOut

        # data out mux
        dataCases = []
        for isSelected, din in zip(isSelectedFlags, self.dataIn):
            dataConnectExpr = self.dataConnectionExpr(din, dout)
            cond = vld(din) & isSelected
            dataCases.append((cond, dataConnectExpr))

        dataDefault = self.dataConnectionExpr(None, dout)
        SwitchLogic(dataCases, dataDefault)
Exemple #10
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)
Exemple #11
0
    def lookupRes_driver(self, state: RtlSignal, lookupFoundOH: RtlSignal):
        """
        If lookup request comes from external interface "lookup" propagate results
        from tables to "lookupRes".
        """
        fsm_t = state._dtype
        lookupRes = self.lookupRes
        lookupResVld = StreamNode(masters=[t.lookupRes for t in self.tables]).ack()
        lookupRes.vld(state._eq(fsm_t.idle) & lookupResVld)

        SwitchLogic([(lookupFoundOH[i],
                      lookupRes(t.lookupRes,
                                exclude={lookupRes.vld,
                                         lookupRes.rd}))
                     for i, t in enumerate(self.tables)],
                    default=[
                        lookupRes(self.tables[0].lookupRes,
                                  exclude={lookupRes.vld,
                                           lookupRes.rd})]
                    )
Exemple #12
0
    def tables_lookupRes_resolver(self, insertResRead: RtlSignal):
        """
        Control lookupRes interface for each table
        """
        tables = self.tables
        # one hot encoded index where item should be stored (where was found
        # or where is place)
        insertTargetOH = self._reg("insertTargetOH", Bits(self.TABLE_CNT, force_vector=True))

        res = [t.lookupRes for t in tables]
        insertFinal = self._reg("insertFinal")
        # select empty space or victim which which current insert item
        # should be swapped with
        lookupResVld = StreamNode(masters=res).ack()
        lookupFoundOH = [t.lookupRes.found for t in tables]
        isEmptyOH = [~t.lookupRes.occupied for t in tables]

        If(insertResRead & lookupResVld,
            # resolve in which table the item should be stored
            If(Or(*lookupFoundOH),
                # an item found in some table, set target to this table
                insertTargetOH(Concat(*reversed(lookupFoundOH)))
            ).Else(
                # set target to first table with an empty item
                SwitchLogic(
                    [(isEmpty, insertTargetOH(1 << i))
                     for i, isEmpty in enumerate(isEmptyOH)],
                    # if there is no empty place in any table, swap
                    # item with an item from next table or last table
                    # if this is a first insert
                    default=If(insertTargetOH != 0,
                                insertTargetOH(ror(insertTargetOH, 1))
                            ).Else(
                                insertTargetOH(1 << (self.TABLE_CNT - 1))
                            )
                )
            ),
            # final if the item was already somewhere or there is an empty place in some table
            insertFinal(Or(*lookupFoundOH, *isEmptyOH))
        )
        return lookupResVld, insertFinal, lookupFoundOH, insertTargetOH
Exemple #13
0
    def _impl(self):
        rd = self.get_ready_signal
        vld = self.get_valid_signal
        dout = self.dataOut

        vldSignals = [vld(d) for d in self.dataIn]

        # data out mux
        dataCases = []
        for i, din in enumerate(self.dataIn):
            allLowerPriorNotReady = map(lambda x: ~x, vldSignals[:i])
            rd(din)(And(rd(dout), *allLowerPriorNotReady))

            cond = vld(din)
            dataConnectExpr = self.dataConnectionExpr(din, dout)
            dataCases.append((cond, dataConnectExpr))

        dataDefault = self.dataConnectionExpr(None, dout)
        SwitchLogic(dataCases, dataDefault)

        vld(dout)(Or(*vldSignals))
    def _impl(self) -> None:
        if len(self._masters) > 1:
            raise NotImplementedError()

        m_offset, _ = self._masters[0]
        if m_offset != 0:
            raise NotImplementedError()

        m = self.s[0]

        err = hBit(0)
        rdack = hBit(0)
        wrack = hBit(0)
        AW = int(self.ADDR_WIDTH)
        wdata = []
        for i, (s, (s_offset, s_size,
                    _)) in enumerate(zip(self.m, self._slaves)):
            connect(m.bus2ip_addr, s.bus2ip_addr, fit=True)
            s.bus2ip_be(m.bus2ip_be)
            s.bus2ip_rnw(m.bus2ip_rnw)
            s.bus2ip_data(m.bus2ip_data)

            bitsOfSubAddr = int(log2ceil(s_size - 1))
            prefix = selectBitRange(s_offset, bitsOfSubAddr,
                                    AW - bitsOfSubAddr)
            cs = self._sig("m_cs_%d" % i)
            cs(m.bus2ip_addr[AW:bitsOfSubAddr]._eq(prefix))
            s.bus2ip_cs(m.bus2ip_cs & cs)

            err = err | (cs & s.ip2bus_error)
            rdack = rdack | (cs & s.ip2bus_rdack)
            wrack = wrack | (cs & s.ip2bus_wrack)
            wdata.append((cs, s.ip2bus_data))

        m.ip2bus_error(err)
        m.ip2bus_rdack(rdack)
        m.ip2bus_wrack(wrack)

        SwitchLogic([(sel, m.ip2bus_data(data)) for sel, data in wdata],
                    default=m.ip2bus_data(None))
Exemple #15
0
    def lookupResDriver(self, state, lookupOrigin, lookupAck, insertFoundOH):
        """
        If lookup request comes from external interface "lookup" propagate results
        from tables to "lookupRes".
        """
        fsm_t = state._dtype
        lookupRes = self.lookupRes
        lookupRes.vld(state._eq(fsm_t.lookupResAck) & 
                      lookupOrigin._eq(ORIGIN_TYPE.LOOKUP) & 
                      lookupAck)

        SwitchLogic([(insertFoundOH[i],
                      connect(t.lookupRes,
                              lookupRes,
                              exclude={lookupRes.vld,
                                       lookupRes.rd}))
                     for i, t in enumerate(self.tables)],
                    default=[
                        connect(self.tables[0].lookupRes,
                                lookupRes,
                                exclude={lookupRes.vld,
                                         lookupRes.rd})]
                    )
Exemple #16
0
    def apply_data_write_forwarding(self, st: OOOOpPipelineStage,
                           st_load_en: RtlSignal,
                           data_modifier=lambda dst_st, src_st: dst_st.data(src_st.data)):
        """
        :param st_collision_detect: in format stages X pipeline[WRITE_BACK-1:], if bit = 1 it means
            that the stage data should be updated from stage on that index
        """
        st_prev = self.pipeline[st.index - 1]

        def is_not_0(sig):
            return not (isinstance(sig, int) and sig == 0)

        # we can write forward to a stages from STATE_LOAD to WRITE_BACK
        # however we can not replace the valid value in WRITE_BACK stage
        # and we need to wait on load_en
        res = SwitchLogic([
                (
                    # the previous which is beeing loaded into this is colliding with src
                    (st_load_en & st_prev.collision_detect[src_i]) |
                    (~st_load_en & st.collision_detect[src_i]),
                    # forward data instead of data from previous stage
                    data_modifier(st, src_st)
                )
                for src_i, src_st in enumerate(self.pipeline) if (
                        # filter out stage combinations which do not have forwarding
                        is_not_0(st.collision_detect[src_i]) or
                        is_not_0(st_prev.collision_detect[src_i])
                    )
            ],
            default=\
            If(st_load_en,
               data_modifier(st, st_prev)
            )
        )

        return res
Exemple #17
0
    def _impl(self):
        In = self.dataIn
        rd = self.get_ready_signal

        sel = self.selectOneHot
        r = HandshakedReg(Handshaked)
        r.DATA_WIDTH = sel.data._dtype.bit_length()
        self.selReg = r
        r.dataIn(sel)
        propagateClkRstn(self)
        sel = r.dataOut

        for index, outIntf in enumerate(self.dataOut):
            for ini, outi in zip(In._interfaces, outIntf._interfaces):
                if ini == self.get_valid_signal(In):
                    # out.vld
                    outi(sel.vld & ini & sel.data[index])
                elif ini == rd(In):
                    pass
                else:  # data
                    outi(ini)

        din = self.dataIn
        SwitchLogic(
            cases=[(~sel.vld, [sel.rd(0),
                                rd(In)(0)])
                  ] +
                  [(sel.data[index],
                    [rd(In)(rd(out)),
                     sel.rd(rd(out) & self.get_valid_signal(din) & sel.vld & self._select_consume_en())])
                   for index, out in enumerate(self.dataOut)],
            default=[
                     sel.rd(None),
                     rd(In)(None)
            ]
        )
Exemple #18
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))
Exemple #19
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))
Exemple #20
0
    def _impl(self) -> None:
        if len(self.MASTERS) > 1:
            raise NotImplementedError()
        m = self.s[0]
        # :note: theoretically not required
        b = Mi32Buff()
        b.ADDR_BUFF_DEPTH = 1
        b.DATA_BUFF_DEPTH = 1
        b._updateParamsFrom(self)
        self.s_0_buff = b
        b.s(m)
        m = b.m

        propagateClkRstn(self)

        r_order = self.r_data_order.dataIn
        AW = int(self.ADDR_WIDTH)
        rdata = []
        r_data_t = HStruct(
            (m.drd._dtype, "data"),
            (BIT, "vld"),
        )
        for i, (s, (s_offset, s_size)) in\
                enumerate(zip(self.m, self.SLAVES)):
            # s = Mi32()
            s.addr(m.addr, fit=True)
            s.be(m.be)

            s.dwr(m.dwr)

            bitsOfSubAddr = log2ceil(s_size - 1)
            prefix = get_bit_range(s_offset, bitsOfSubAddr, AW - bitsOfSubAddr)
            cs = self._sig(f"m_cs_{i:d}")
            cs(m.addr[AW:bitsOfSubAddr]._eq(prefix))
            s.rd(m.rd & cs & r_order.rd)
            s.wr(m.wr & cs & r_order.rd)

            # we have to add 1 read data latency because the slave index would not be ready
            # oder fifo
            r_data_tmp = self._reg(f"r_data{i:d}_tmp",
                                   r_data_t,
                                   def_val={"vld": 0})
            r_data_tmp.data(s.drd)
            r_data_tmp.vld(s.drdy)
            rdata.append((i, cs & s.ardy, r_data_tmp))

        # r_data_order feed
        SwitchLogic([(addr_en, r_order.data(i)) for i, addr_en, _ in rdata],
                    default=r_order.data(None))
        addr_ack = Or(*[x[1] for x in rdata])
        r_order.vld(addr_ack & m.rd)
        # m = Mi32()
        m.ardy(addr_ack & r_order.rd & (m.rd | m.wr))

        r_order = self.r_data_order.dataOut
        If(
            r_order.vld,
            Switch(r_order.data).add_cases(
                [(slave_i, [m.drd(data.data), m.drdy(1)])
                 for slave_i, _, data in rdata], ).Default(
                     # this case can not happen unless bug in code
                     m.drd(None),
                     m.drdy(None))).Else(
                         m.drd(None),
                         m.drdy(False),
                     )
        r_order.rd(Or(*[data.vld for _, _, data in rdata]))
Exemple #21
0
    def data_array_io(
            self,
            aw_lru_incr: IndexWayHs,  # out
            aw_tagRes: AxiCacheTagArrayLookupResIntf,  # in
            victim_req: AddrHs,
            victim_way: Handshaked,  # out, in
            data_arr_read_req: IndexWayHs,
            data_arr_read: Axi4_r,  # in, out
            data_arr_r_port: BramPort_withoutClk,
            data_arr_w_port: BramPort_withoutClk,  # out, out
            tag_update: AxiCacheTagArrayUpdateIntf  # out
    ):
        """
        :ivar aw_lru_incr: an interface to increment LRU for write channel
        :ivar victim_req: an interface to get a victim from LRU array for a specified index
        :ivar victim_way: return interface for victim_req
        :ivar aw_tagRes: an interface with a results from tag lookup
        :ivar data_arr_read_req: an input interface with read requests from read section
        :ivar data_arr_read: an output interface with a read data to read section
        :ivar data_arr_r_port: read port of main data array
        :ivar data_arr_w_port: write port of main data array
        """
        # note that the lru update happens even if the data is stalled
        # but that is not a problem because it wont change the order of the usage
        # of the cahceline
        self.incr_lru_on_hit(aw_lru_incr, aw_tagRes)

        st0 = self._reg(
            "victim_load_status0",
            HStruct(
                (self.s.aw.id._dtype, "write_id"
                 ),  # the original id and address of a write transaction
                (self.s.aw.addr._dtype, "replacement_addr"),
                (aw_tagRes.TAG_T[aw_tagRes.WAY_CNT], "tags"),
                (BIT, "tag_found"),
                (BIT, "had_empty"),  # had some empty tag
                (aw_tagRes.way._dtype, "found_way"),
                (BIT, "valid"),
            ),
            def_val={
                "valid": 0,
            })
        # resolve if we need to select a victim and optianally ask for it
        st0_ready = self._sig("victim_load_status0_ready")
        has_empty = rename_signal(self,
                                  Or(*(~t.valid for t in aw_tagRes.tags)),
                                  "has_empty")
        If(
            st0_ready,
            st0.write_id(aw_tagRes.id),
            st0.replacement_addr(aw_tagRes.addr),
            st0.tags(aw_tagRes.tags),
            st0.tag_found(aw_tagRes.found),
            st0.found_way(aw_tagRes.way),
            st0.had_empty(has_empty),
            # this register is beeing flushed, the values can become invalid
            # the st0.valid is used to detect this state
            st0.valid(aw_tagRes.vld),
        )
        victim_req.addr(self.parse_addr(aw_tagRes.addr)[1])
        tag_check_node = StreamNode(
            [aw_tagRes], [victim_req],
            skipWhen={
                victim_req: aw_tagRes.vld & (aw_tagRes.found | has_empty)
            },
            extraConds={victim_req: ~aw_tagRes.found & ~has_empty})

        st1_ready = self._sig("victim_load_status1_ready")
        tag_check_node.sync(~st0.valid | st1_ready)
        tag_check_node_ack = rename_signal(self, tag_check_node.ack(),
                                           "tag_check_node_ack")
        st0_ready((st0.valid & tag_check_node_ack & st1_ready) | ~st0.valid
                  | st1_ready)

        victim_load_st = HStruct(
            # and address constructed from an original tag in cache which is beeing replaced
            (self.s.aw.addr._dtype, "victim_addr"),
            # new data to write to data_array
            # (replacement data is still in in_w buffer because it was not consumed
            #  if the tag was not found)
            (aw_tagRes.way._dtype, "victim_way"),
            (self.s.ar.id._dtype, "read_id"),
            (self.s.aw.id._dtype, "write_id"),
            (self.s.aw.addr._dtype, "replacement_addr"
             ),  # the original address used to resolve new tag
            (Bits(2), "data_array_op"),  # type of operation with data_array
        )
        ########################## st1 - pre (read request resolution, victim address resolution) ##############
        d_arr_r, d_arr_w = self.instantiate_data_array_to_hs(
            data_arr_r_port, data_arr_w_port)

        # :note: flush with higher priority than regular read
        need_to_flush = rename_signal(
            self, st0.valid & (~st0.had_empty & ~st0.tag_found),
            "need_to_flush")

        If(
            need_to_flush,
            d_arr_r.addr.data(
                self.addr_in_data_array(
                    victim_way.data,
                    self.parse_addr(st0.replacement_addr)[1])),
        ).Else(
            d_arr_r.addr.data(
                self.addr_in_data_array(data_arr_read_req.way,
                                        data_arr_read_req.index)))
        _victim_way = self._sig("victim_way_tmp", Bits(log2ceil(self.WAY_CNT)))
        _victim_tag = self._sig("victim_tag_tmp", Bits(self.TAG_W))
        SwitchLogic(
            [
                # select first empty tag
                (~tag.valid, [
                    _victim_way(i),
                    _victim_tag(tag.tag),
                ]) for i, tag in enumerate(st0.tags)
            ],
            default=[
                # select an victim specified by victim_way
                _victim_way(victim_way.data),
                SwitchLogic([(victim_way.data._eq(i), _victim_tag(tag.tag))
                             for i, tag in enumerate(st0.tags)],
                            default=_victim_tag(None))
            ])
        victim_load_status = HObjList(
            HandshakedReg(HsStructIntf) for _ in range(2))
        for i, st in enumerate(victim_load_status):
            st.T = victim_load_st
            if i == 0:
                st.LATENCY = (1, 2)  # to break a ready chain
        self.victim_load_status = victim_load_status

        st1_in = victim_load_status[0].dataIn.data
        # placed between st0, st1
        pure_write = rename_signal(
            self, st0.valid & ~need_to_flush & ~data_arr_read_req.vld,
            "pure_write")
        pure_read = rename_signal(self, ~st0.valid & data_arr_read_req.vld,
                                  "pure_read")
        read_plus_write = rename_signal(
            self, st0.valid & ~need_to_flush & data_arr_read_req.vld,
            "read_plus_write")
        flush_write = rename_signal(
            self, st0.valid & need_to_flush & ~data_arr_read_req.vld,
            "flush_write")
        read_flush_write = rename_signal(
            self, st0.valid & need_to_flush & data_arr_read_req.vld,
            "read_flush_write")  # not dispatched at once

        read_req_node = StreamNode(
            [victim_way, data_arr_read_req],
            [d_arr_r.addr, victim_load_status[0].dataIn],
            extraConds={
                victim_way:
                flush_write | read_flush_write,  # 0
                # only write without flush       not write at all but read request
                data_arr_read_req:
                pure_read | read_plus_write,  # pure_read | read_plus_write, #
                d_arr_r.addr:
                pure_read | read_plus_write | flush_write |
                read_flush_write,  # need_to_flush | data_arr_read_req.vld, # 1
                # victim_load_status[0].dataIn: st0.valid | data_arr_read_req.vld,
            },
            skipWhen={
                victim_way: pure_write | pure_read | read_plus_write,
                data_arr_read_req: pure_write | flush_write | read_flush_write,
                d_arr_r.addr: pure_write,
            })
        read_req_node.sync()
        st1_ready(victim_load_status[0].dataIn.rd & read_req_node.ack())

        st1_in.victim_addr(
            self.deparse_addr(_victim_tag,
                              self.parse_addr(st0.replacement_addr)[1], 0))
        st1_in.victim_way(st0.tag_found._ternary(st0.found_way, _victim_way)),
        st1_in.read_id(data_arr_read_req.id)
        st1_in.write_id(st0.write_id)
        st1_in.replacement_addr(st0.replacement_addr)
        If(pure_write, st1_in.data_array_op(data_trans_t.write)).Elif(
            pure_read, st1_in.data_array_op(data_trans_t.read)).Elif(
                read_plus_write,
                st1_in.data_array_op(data_trans_t.read_and_write)
            ).Else(  # .Elif(flush_write | read_flush_write,
                st1_in.data_array_op(data_trans_t.write_and_flush))
        # If(st0.valid,
        #    If(need_to_flush,
        #        st1_in.data_array_op(data_trans_t.write_and_flush)
        #    ).Elif(st0.tag_found & data_arr_read_req.vld,
        #        st1_in.data_array_op(data_trans_t.read_and_write)
        #    ).Else(
        #        st1_in.data_array_op(data_trans_t.write)
        #    )
        # ).Else(
        #    st1_in.data_array_op(data_trans_t.read)
        # )

        victim_load_status[1].dataIn(victim_load_status[0].dataOut)

        self.flush_or_read_node(d_arr_r, d_arr_w,
                                victim_load_status[1].dataOut, data_arr_read,
                                tag_update)
Exemple #22
0
    def connectPartsOfWord(self, wordData_out: RtlSignal,
                           tPart: Union[TransPart, ChoicesOfFrameParts,
                                        StreamOfFramePars],
                           inPorts_out: List[Union[Handshaked, StreamNode]],
                           lastInPorts_out: List[Union[Handshaked,
                                                       StreamNode]]):
        """
        Connect transactions parts to signal for word of output stream

        :param wordData_out: signal for word of output stream
        :param tPart: instance of TransPart or ChoicesOfFrameParts to connect
        :param inPorts_out: input interfaces to this transaction part
        :param lastInPorts_out: input interfaces for last parts of transactions
        """

        tToIntf = self.dataIn._fieldsToInterfaces

        if isinstance(tPart, ChoicesOfFrameParts):
            # connnect parts of union to output signal
            w = tPart.bit_length()
            high, low = tPart.getBusWordBitRange()
            parentIntf = tToIntf[tPart.origin.parent.origin]

            if parentIntf not in self._tmpRegsForSelect.keys():
                sel = HsBuilder(self, parentIntf._select).buff().end
                self._tmpRegsForSelect[parentIntf] = sel

            inPortGroups = ExclusiveStreamGroups()
            lastInPortsGroups = ExclusiveStreamGroups()

            # tuples (cond, part of data mux for dataOut)
            unionChoices = []

            # for all union choices
            for choice in tPart:
                tmp = self._sig("union_tmp_", Bits(w))
                intfOfChoice = tToIntf[choice.tmpl.origin]
                _, isSelected, isSelectValid = AxiS_frameParser.choiceIsSelected(
                    self, intfOfChoice)
                unionChoices.append((isSelected, wordData_out[high:low](tmp)))

                isSelected = isSelected & isSelectValid

                inPortsNode = StreamNode()
                lastPortsNode = StreamNode()

                inPortGroups.append((isSelected, inPortsNode))
                lastInPortsGroups.append((isSelected, lastPortsNode))

                # walk all parts in union choice
                for _tPart in choice:
                    self.connectPartsOfWord(tmp, _tPart, inPortsNode.masters,
                                            lastPortsNode.masters)

            # generate data out mux
            SwitchLogic(unionChoices, default=wordData_out(None))

            inPorts_out.append(inPortGroups)
            lastInPorts_out.append(lastInPortsGroups)
        elif isinstance(tPart, StreamOfFramePars):
            if len(tPart) != 1:
                raise NotImplementedError(
                    "Structuralized streams not implemented yiet")

            p = tPart[0]
            intf = tToIntf[p.tmpl.origin]

            if int(intf.DATA_WIDTH) != wordData_out._dtype.bit_length():
                raise NotImplementedError(
                    "Dynamic resizing of streams not implemented yiet")

            if len(self._frames) > 1:
                raise NotImplementedError(
                    "Dynamic splitting on frames not implemented yet")
            wordData_out(self.byteOrderCare(intf.data))
            inPorts_out.append(intf)

            if tPart.isLastPart():
                lastInPorts_out.append(intf)

            return intf.strb

        else:
            # connect parts of fields to output signal
            high, low = tPart.getBusWordBitRange()
            if tPart.isPadding:
                wordData_out[high:low](None)
            else:
                intf = tToIntf[tPart.tmpl.origin]
                fhigh, flow = tPart.getFieldBitRange()
                wordData_out[high:low](self.byteOrderCare(
                    intf.data)[fhigh:flow])
                inPorts_out.append(intf)

                if tPart.isLastPart():
                    lastInPorts_out.append(intf)
Exemple #23
0
    def remSizeToStrb(self, remSize: RtlSignal, strb: RtlSignal, isFirstWord,
                      isLastWord):
        sizeRm = self.sizeRmFifo.dataOut
        STRB_W = strb._dtype.bit_length()
        if self.isAlwaysAligned():
            STRB_ALL = mask(STRB_W)
            strbSwitch = Switch(remSize)\
                .Case(0,
                      strb(STRB_ALL)
                ).add_cases(
                    [(i + 1, strb(mask(i + 1)))
                     for i in range(STRB_W - 1)]
                ).Default(
                    strb(None)
                )
            if isinstance(isLastWord, (bool, int, HValue)):
                if isLastWord:
                    return strbSwitch
                else:
                    return strb(STRB_ALL)
            else:
                return If(isLastWord, strbSwitch).Else(strb(STRB_ALL))
        else:
            CHUNK = self.CHUNK_WIDTH // 8
            MAX_BYTES = CHUNK * self.MAX_CHUNKS
            STRB_ALL = mask(min(STRB_W, MAX_BYTES))
            ALIGNAS = self.ALIGNAS
            possibleBytesInLastWord = set()
            assert self.DATA_WIDTH % ALIGNAS == 0, (
                "Required to resolve number of bytes in last word",
                self.DATA_WIDTH, ALIGNAS)
            for CHUNK_CNT in range(
                    1,
                    min(self.MAX_CHUNKS, max(3, self.DATA_WIDTH // CHUNK * 3))
                    + 1):
                for o in range(0, STRB_W, ALIGNAS // 8):
                    bytesInLastWord = (o + CHUNK * CHUNK_CNT) % (
                        self.DATA_WIDTH // 8)
                    if bytesInLastWord in possibleBytesInLastWord:
                        break
                    possibleBytesInLastWord.add(bytesInLastWord)
            possibleBytesInLastWord = sorted(possibleBytesInLastWord)

            offsetsAlignmentCombinations = set([
                # bytesInLastWord, offset value of value in last word, index of shift option
                (min(bytesInLastWord, MAX_BYTES), sh // 8, sh_i)
                for bytesInLastWord in possibleBytesInLastWord
                for sh_i, sh in enumerate(sizeRm.SHIFT_OPTIONS)
                if bytesInLastWord <= MAX_BYTES
            ])
            offsetsAlignmentCombinations = sorted(offsetsAlignmentCombinations)

            t = strb._dtype.from_py
            # :attention: last word can be first word as well
            MASK_ALL = mask(STRB_W)
            WORD_W = strb._dtype.bit_length()
            return \
                SwitchLogic([
                    (remSize._eq(0 if bytesInLastWord == STRB_W else bytesInLastWord) & sizeRm.shift._eq(shift_i),
                        strb(
                             # dissable prefix bytes if this is first word
                             isFirstWord._ternary(t((MASK_ALL << shift) & MASK_ALL), t(MASK_ALL)) &
                             # dissable suffix bytes if this last word
                             isLastWord._ternary(t(MASK_ALL >> ((WORD_W - bytesInLastWord - shift) % WORD_W)), t(MASK_ALL))
                        )
                    )
                    for bytesInLastWord, shift, shift_i in offsetsAlignmentCombinations
                    ],
                    default=strb(None)
                )
Exemple #24
0
    def connectPartsOfWord(self, wordData_out: RtlSignal,
                           tPart: Union[TransPart,
                                        ChoicesOfFrameParts],
                           inPorts_out: List[Union[Handshaked,
                                                   StreamNode]],
                           lastInPorts_out: List[Union[Handshaked,
                                                       StreamNode]])\
            ->Tuple[Optional[RtlSignal], Optional[RtlSignal]]:
        """
        Connect transactions parts to signal for word of output stream

        :param wordData_out: signal for word of output stream
        :param tPart: instance of TransPart or ChoicesOfFrameParts to connect
        :param inPorts_out: input interfaces to this transaction part
        :param lastInPorts_out: input interfaces for last parts of transactions
        :return: tuple (strb, keep) if strb/keep driven by input stream, else (None, None)
        """

        tToIntf = self.dataIn._fieldsToInterfaces

        if isinstance(tPart, ChoicesOfFrameParts):
            # connect parts of union to output signal
            high, low = tPart.getBusWordBitRange()
            parentIntf = tToIntf[tPart.origin.parent.getFieldPath()]

            if parentIntf not in self._tmpRegsForSelect.keys():
                sel = HsBuilder(self, parentIntf._select).buff().end
                self._tmpRegsForSelect[parentIntf] = sel

            inPortGroups = ExclusiveStreamGroups()
            lastInPortsGroups = ExclusiveStreamGroups()
            w = tPart.bit_length()

            # tuples (cond, part of data mux for dataOut)
            unionChoices = []
            sk_stashes = []
            # for all choices in union
            for choice in tPart:
                tmp = self._sig("union_tmp_", Bits(w))
                intfOfChoice = tToIntf[choice.tmpl.getFieldPath()]
                _, _isSelected, isSelectValid = \
                    AxiS_frameParserFieldConnector.choiceIsSelected(self, intfOfChoice)
                unionChoices.append((_isSelected, wordData_out[high:low](tmp)))

                isSelected = _isSelected & isSelectValid

                # build meta for handshake logic sync
                inPortsNode = StreamNode()
                inPortGroups.append((isSelected, inPortsNode))

                lastPortsNode = StreamNode()
                lastInPortsGroups.append((isSelected, lastPortsNode))

                sk_stash = StrbKeepStash()
                # walk all parts in union choice
                start = tPart.startOfPart
                for choicePart in choice:
                    if start != choicePart.startOfPart:
                        # add padding because there is a hole in data
                        _w = choicePart.startOfPart - start
                        assert _w > 0, _w
                        sk_stash.push((_w, 0), (_w, 0))

                    _strb, _keep = self.connectPartsOfWord(
                        tmp, choicePart, inPortsNode.masters,
                        lastPortsNode.masters)
                    sk_stash.push(_strb, _keep)
                    start = choicePart.endOfPart

                if start != tPart.endOfPart:
                    # add padding because there is a hole after
                    _w = tPart.endOfPart - start
                    assert _w > 0, _w
                    sk_stash.push((_w, 0), (_w, 0))

                # store isSelected sig and strb/keep value for later strb/keep resolving
                sk_stashes.append((isSelected, sk_stash))

            # generate data out mux
            SwitchLogic(unionChoices, default=wordData_out(None))

            inPorts_out.append(inPortGroups)
            lastInPorts_out.append(lastInPortsGroups)
            # resolve strb/keep from strb/keep and isSelected of union members
            if w % 8 != 0:
                raise NotImplementedError(w)
            strb, keep = reduce_conditional_StrbKeepStashes(sk_stashes)
        else:
            # connect parts of fields to output signal
            high, low = tPart.getBusWordBitRange()
            if tPart.isPadding:
                wordData_out[high:low](None)
            else:
                intf = tToIntf[tPart.tmpl.getFieldPath()]
                fhigh, flow = tPart.getFieldBitRange()
                wordData_out[high:low](self.byteOrderCare(
                    intf.data)[fhigh:flow])
                inPorts_out.append(intf)

                if tPart.isLastPart():
                    lastInPorts_out.append(intf)

            w = tPart.bit_length()
            strb = int(not tPart.isPadding)
            keep = int(not tPart.canBeRemoved)
        return ((w, strb), (w, keep))
Exemple #25
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)
Exemple #26
0
    def stash_load(self, isIdle, lookupResNext, insertTargetOH, stash, lookup_not_in_progress, another_lookup_possible):
        """
        load a stash register from lookup/insert/delete interface
        """
        lookup = self.lookup
        insert = self.insert
        delete = self.delete
        table_lookup_ack = StreamNode(slaves=[t.lookup for t in self.tables]).ack()
        lookup_currently_executed = stash.origin_op._eq(ORIGIN_TYPE.LOOKUP)
        assert self.MAX_REINSERT > 0, self.MAX_REINSERT
        If(isIdle,
            If(lookup_not_in_progress & self.clean.vld,
                stash.origin_op(ORIGIN_TYPE.DELETE),
                stash.item_vld(0)
            ).Elif(lookup_not_in_progress & delete.vld,
                stash.origin_op(ORIGIN_TYPE.DELETE),
                stash.key(delete.key),
                stash.item_vld(0),
            ).Elif(lookup_not_in_progress & insert.vld,
                stash.origin_op(ORIGIN_TYPE.INSERT),
                stash.key(insert.key),
                stash.data(insert.data),
                stash.reinsert_cntr(self.MAX_REINSERT),
                stash.item_vld(1),
            ).Elif(lookup.vld & lookup.rd,
                stash.origin_op(ORIGIN_TYPE.LOOKUP),
                stash.key(lookup.key),
            ).Elif(table_lookup_ack,
                stash.origin_op(ORIGIN_TYPE.DELETE),  # need to set something else than lookup
                stash.key(None),
            )
        ).Elif(lookupResNext,
            SwitchLogic([
                (insertTargetOH[i],
                    [
                        # load stash from item found previously
                        # :note: happens in same time as write to table
                        #     so the stash and item in table is swapped
                        stash.key(t.lookupRes.key),
                        stash.data(t.lookupRes.data),
                        stash.reinsert_cntr(stash.reinsert_cntr - 1),
                        stash.item_vld(t.lookupRes.occupied),
                    ]
                  )
                  for i, t in enumerate(self.tables)
                ],
                default=[
                    stash.origin_op(ORIGIN_TYPE.DELETE),
                    stash.key(None),
                    stash.data(None),
                    stash.reinsert_cntr(None),
                    stash.item_vld(None),
                ])
        )
        cmd_priority = [self.clean, self.delete, self.insert, lookup]
        for i, intf in enumerate(cmd_priority):
            withLowerPrio = cmd_priority[:i]
            rd = And(isIdle, *[~x.vld for x in withLowerPrio])
            if intf is lookup:
                rd = rd & (~lookup_currently_executed |  # the stash not loaded yet
                     table_lookup_ack  # stash will be consumed
                    ) & another_lookup_possible
            else:
                rd = rd & lookup_not_in_progress

            intf.rd(rd)