Exemplo n.º 1
0
    def _impl(self):
        # internal signals
        ACASCREG, ADREG, ALUMODEREG, AREG, AUTORESET_PATDET, A_INPUT, BCASCREG, BREG, B_INPUT, CARRYINREG, CARRYINSELREG, \
        CREG, DREG, INMODEREG, IS_ALUMODE_INVERTED, IS_CARRYIN_INVERTED, IS_CLK_INVERTED, IS_INMODE_INVERTED, IS_OPMODE_INVERTED, MASK, MREG, \
        OPMODEREG, PATTERN, PREG, SEL_MASK, SEL_PATTERN, USE_DPORT, USE_MULT, USE_PATTERN_DETECT, USE_SIMD, ACOUT, \
        BCOUT, CARRYCASCOUT, CARRYOUT, MULTSIGNOUT, OVERFLOW, P, PATTERNBDETECT, PATTERNDETECT, PCOUT, UNDERFLOW, \
        A, ACIN, ALUMODE, B, BCIN, C, CARRYCASCIN, CARRYIN, CARRYINSEL, CEA1, \
        CEA2, CEAD, CEALUMODE, CEB1, CEB2, CEC, CECARRYIN, CECTRL, CED, CEINMODE, \
        CEM, CEP, CLK, D, INMODE, MULTSIGNIN, OPMODE, PCIN, RSTA, RSTALLCARRYIN, \
        RSTALUMODE, RSTB, RSTC, RSTCTRL, RSTD, RSTINMODE, RSTM, RSTP = \
        self.ACASCREG, self.ADREG, self.ALUMODEREG, self.AREG, self.AUTORESET_PATDET, self.A_INPUT, self.BCASCREG, self.BREG, self.B_INPUT, self.CARRYINREG, self.CARRYINSELREG, \
        self.CREG, self.DREG, self.INMODEREG, self.IS_ALUMODE_INVERTED, self.IS_CARRYIN_INVERTED, self.IS_CLK_INVERTED, self.IS_INMODE_INVERTED, self.IS_OPMODE_INVERTED, self.MASK, self.MREG, \
        self.OPMODEREG, self.PATTERN, self.PREG, self.SEL_MASK, self.SEL_PATTERN, self.USE_DPORT, self.USE_MULT, self.USE_PATTERN_DETECT, self.USE_SIMD, self.ACOUT, \
        self.BCOUT, self.CARRYCASCOUT, self.CARRYOUT, self.MULTSIGNOUT, self.OVERFLOW, self.P, self.PATTERNBDETECT, self.PATTERNDETECT, self.PCOUT, self.UNDERFLOW, \
        self.A, self.ACIN, self.ALUMODE, self.B, self.BCIN, self.C, self.CARRYCASCIN, self.CARRYIN, self.CARRYINSEL, self.CEA1, \
        self.CEA2, self.CEAD, self.CEALUMODE, self.CEB1, self.CEB2, self.CEC, self.CECARRYIN, self.CECTRL, self.CED, self.CEINMODE, \
        self.CEM, self.CEP, self.CLK, self.D, self.INMODE, self.MULTSIGNIN, self.OPMODE, self.PCIN, self.RSTA, self.RSTALLCARRYIN, \
        self.RSTALUMODE, self.RSTB, self.RSTC, self.RSTCTRL, self.RSTD, self.RSTINMODE, self.RSTM, self.RSTP
        #------------------- constants -------------------------
        CARRYOUT_W = 4
        A_W = 30
        ALUMODE_W = 4
        A_MULT_W = 25
        B_W = 18
        B_MULT_W = 18
        D_W = 25
        INMODE_W = 5
        OPMODE_W = 7
        ALU_FULL_W = 48

        IS_ALUMODE_INVERTED_BIN = self._sig("IS_ALUMODE_INVERTED_BIN",
                                            Bits(4),
                                            def_val=IS_ALUMODE_INVERTED)
        IS_CARRYIN_INVERTED_BIN = self._sig("IS_CARRYIN_INVERTED_BIN",
                                            def_val=IS_CARRYIN_INVERTED)
        IS_CLK_INVERTED_BIN = self._sig("IS_CLK_INVERTED_BIN",
                                        def_val=IS_CLK_INVERTED)
        IS_INMODE_INVERTED_BIN = self._sig("IS_INMODE_INVERTED_BIN",
                                           Bits(5),
                                           def_val=IS_INMODE_INVERTED)
        IS_OPMODE_INVERTED_BIN = self._sig("IS_OPMODE_INVERTED_BIN",
                                           Bits(7),
                                           def_val=IS_OPMODE_INVERTED)
        a_o_mux = self._sig("a_o_mux", Bits(30))
        qa_o_mux = self._sig("qa_o_mux", Bits(30))
        qa_o_reg1 = self._sig("qa_o_reg1", Bits(30))
        qa_o_reg2 = self._sig("qa_o_reg2", Bits(30))
        qacout_o_mux = self._sig("qacout_o_mux", Bits(30))
        # new
        qinmode_o_mux = self._sig("qinmode_o_mux", Bits(5))
        qinmode_o_reg = self._sig("qinmode_o_reg", Bits(5))
        # new
        a_preaddsub = self._sig("a_preaddsub", Bits(25))
        b_o_mux = self._sig("b_o_mux", Bits(18))
        qb_o_mux = self._sig("qb_o_mux", Bits(18))
        qb_o_reg1 = self._sig("qb_o_reg1", Bits(18))
        qb_o_reg2 = self._sig("qb_o_reg2", Bits(18))
        qbcout_o_mux = self._sig("qbcout_o_mux", Bits(18))
        qcarryinsel_o_mux = self._sig("qcarryinsel_o_mux", Bits(3))
        qcarryinsel_o_reg1 = self._sig("qcarryinsel_o_reg1", Bits(3))
        # new
        #d_o_mux = self._sig("d_o_mux", Bits(D_W))
        qd_o_mux = self._sig("qd_o_mux", Bits(D_W))
        qd_o_reg1 = self._sig("qd_o_reg1", Bits(D_W))
        qmult_o_mux = self._sig("qmult_o_mux", Bits(A_MULT_W + B_MULT_W))
        qmult_o_reg = self._sig("qmult_o_reg", Bits(A_MULT_W + B_MULT_W))
        # 42:0
        qc_o_mux = self._sig("qc_o_mux", Bits(48))
        qc_o_reg1 = self._sig("qc_o_reg1", Bits(48))
        qp_o_mux = self._sig("qp_o_mux", Bits(48))
        qp_o_reg1 = self._sig("qp_o_reg1", Bits(48))
        qx_o_mux = self._sig("qx_o_mux", Bits(48))
        qy_o_mux = self._sig("qy_o_mux", Bits(48))
        qz_o_mux = self._sig("qz_o_mux", Bits(48))
        qopmode_o_mux = self._sig("qopmode_o_mux", Bits(7))
        qopmode_o_reg1 = self._sig("qopmode_o_reg1", Bits(7))
        qcarryin_o_mux0 = self._sig("qcarryin_o_mux0")
        qcarryin_o_reg0 = self._sig("qcarryin_o_reg0")
        qcarryin_o_mux7 = self._sig("qcarryin_o_mux7")
        qcarryin_o_reg7 = self._sig("qcarryin_o_reg7")
        qcarryin_o_mux = self._sig("qcarryin_o_mux")
        qalumode_o_mux = self._sig("qalumode_o_mux", Bits(4))
        qalumode_o_reg1 = self._sig("qalumode_o_reg1", Bits(4))
        self.invalid_opmode = self._sig("invalid_opmode", def_val=1)
        self.opmode_valid_flag = opmode_valid_flag = self._sig(
            "opmode_valid_flag", def_val=1)
        #   reg [47:0] alu_o;
        alu_o = self._sig("alu_o", Bits(48))
        qmultsignout_o_reg = self._sig("qmultsignout_o_reg")
        multsignout_o_mux = self._sig("multsignout_o_mux")
        multsignout_o_opmode = self._sig("multsignout_o_opmode")
        pdet_o_mux = self._sig("pdet_o_mux")
        pdetb_o_mux = self._sig("pdetb_o_mux")
        the_pattern = self._sig("the_pattern", Bits(48))
        the_mask = self._sig("the_mask", Bits(48), def_val=0)
        carrycascout_o = self._sig("carrycascout_o")
        the_auto_reset_patdet = self._sig("the_auto_reset_patdet")
        carrycascout_o_reg = self._sig("carrycascout_o_reg", def_val=0)
        carrycascout_o_mux = self._sig("carrycascout_o_mux", def_val=0)

        # CR 588861
        carryout_o_reg = self._sig("carryout_o_reg", Bits(4), def_val=0)
        carryout_o_mux = self._sig("carryout_o_mux", Bits(4))
        carryout_x_o = self._sig("carryout_x_o", Bits(4))
        pdet_o = self._sig("pdet_o")
        pdetb_o = self._sig("pdetb_o")
        pdet_o_reg1 = self._sig("pdet_o_reg1")
        pdet_o_reg2 = self._sig("pdet_o_reg2")
        pdetb_o_reg1 = self._sig("pdetb_o_reg1")
        pdetb_o_reg2 = self._sig("pdetb_o_reg2")
        overflow_o = self._sig("overflow_o")
        underflow_o = self._sig("underflow_o")
        mult_o = self._sig("mult_o", Bits(A_MULT_W + B_MULT_W))
        #   reg [(MSB_A_MULT+MSB_B_MULT+1):0] mult_o;  // 42:0
        # new
        ad_addsub = self._sig("ad_addsub", Bits(A_MULT_W))
        ad_mult = self._sig("ad_mult", Bits(A_MULT_W))
        qad_o_reg1 = self._sig("qad_o_reg1", Bits(A_MULT_W))
        qad_o_mux = self._sig("qad_o_mux", Bits(A_MULT_W))
        b_mult = self._sig("b_mult", Bits(B_MULT_W))
        # cci_drc_msg = self._sig("cci_drc_msg", def_val=0b0)
        # cis_drc_msg = self._sig("cis_drc_msg", def_val=0b0)
        opmode_in = self._sig("opmode_in", Bits(OPMODE_W))
        alumode_in = self._sig("alumode_in", Bits(ALUMODE_W))
        carryin_in = self._sig("carryin_in")
        clk_in = self._sig("clk_in")
        inmode_in = self._sig("inmode_in", Bits(INMODE_W))
        #*** Y mux
        # 08-06-08
        # IR 478378
        y_mac_cascd = rename_signal(
            self,
            qopmode_o_mux[7:4]._eq(0b100)._ternary(replicate(48, MULTSIGNIN),
                                                   Bits(48).from_py(mask(48))),
            "y_mac_cascd")
        #--####################################################################
        #--#####                         ALU                              #####
        #--####################################################################
        co = self._sig("co", Bits(ALU_FULL_W))
        s = self._sig("s", Bits(ALU_FULL_W))
        comux = self._sig("comux", Bits(ALU_FULL_W))
        smux = self._sig("smux", Bits(ALU_FULL_W))
        carryout_o = self._sig("carryout_o", Bits(CARRYOUT_W))
        # FINAL ADDER
        s0 = rename_signal(
            self,
            Concat(BIT.from_py(0), comux[11:0], qcarryin_o_mux) +
            Concat(BIT.from_py(0), smux[12:0]), "s0")
        cout0 = rename_signal(self, comux[11] + s0[12], "cout0")
        C1 = rename_signal(
            self,
            BIT.from_py(0b0) if USE_SIMD == "FOUR12" else s0[12], "C1")
        co11_lsb = rename_signal(
            self,
            BIT.from_py(0b0) if USE_SIMD == "FOUR12" else comux[11],
            "co11_lsb")
        s1 = rename_signal(
            self,
            Concat(BIT.from_py(0), comux[23:12], co11_lsb) +
            Concat(BIT.from_py(0), smux[24:12]) +
            Concat(Bits(12).from_py(0), C1), "s1")
        cout1 = rename_signal(self, comux[23] + s1[12], "cout1")
        C2 = rename_signal(
            self,
            BIT.from_py(0b0) if (USE_SIMD in ["TWO24", "FOUR12"]) else s1[12],
            "C2")
        co23_lsb = rename_signal(
            self,
            BIT.from_py(0b0) if
            (USE_SIMD in ["TWO24", "FOUR12"]) else comux[23], "co23_lsb")
        s2 = rename_signal(
            self,
            Concat(BIT.from_py(0), comux[35:24], co23_lsb) +
            Concat(BIT.from_py(0), smux[36:24]) +
            Concat(Bits(12).from_py(0), C2), "s2")
        cout2 = rename_signal(self, comux[35] + s2[12], "cout2")
        C3 = rename_signal(
            self,
            BIT.from_py(0b0) if USE_SIMD == "FOUR12" else s2[12], "C3")
        co35_lsb = rename_signal(
            self,
            BIT.from_py(0b0) if USE_SIMD == "FOUR12" else comux[35],
            "co35_lsb")
        s3 = rename_signal(
            self,
            Concat(BIT.from_py(0), comux[48:36], co35_lsb) +
            Concat(Bits(2).from_py(0), smux[48:36]) +
            Concat(Bits(13).from_py(0), C3), "s3")
        cout3 = rename_signal(self, s3[12], "cout3")
        #cout4 = rename_signal(self, s3[13], "cout4")
        qcarryin_o_mux_tmp = self._sig("qcarryin_o_mux_tmp")

        ACOUT(qacout_o_mux)
        BCOUT(qbcout_o_mux)
        CARRYCASCOUT(carrycascout_o_mux)
        CARRYOUT(carryout_x_o)
        MULTSIGNOUT(multsignout_o_mux)
        OVERFLOW(overflow_o)
        P(qp_o_mux)
        PCOUT(qp_o_mux)
        PATTERNDETECT(pdet_o_mux)
        PATTERNBDETECT(pdetb_o_mux)
        UNDERFLOW(underflow_o)
        alumode_in(ALUMODE ^ IS_ALUMODE_INVERTED_BIN)
        carryin_in(CARRYIN ^ IS_CARRYIN_INVERTED_BIN)
        clk_in(CLK ^ IS_CLK_INVERTED_BIN)
        inmode_in(INMODE ^ IS_INMODE_INVERTED_BIN)
        opmode_in(OPMODE ^ IS_OPMODE_INVERTED_BIN)

        #*********************************************************
        #**********  INMODE signal registering        ************
        #*********************************************************
        If(
            clk_in._onRisingEdge(),
            If(RSTINMODE, qinmode_o_reg(0b0)).Elif(CEINMODE,
                                                   qinmode_o_reg(inmode_in)))
        if INMODEREG == 0:
            qinmode_o_mux(inmode_in)
        elif INMODEREG == 1:
            qinmode_o_mux(qinmode_o_reg)
        else:
            raise AssertionError()

        if A_INPUT == "DIRECT":
            a_o_mux(A)
        elif A_INPUT == "CASCADE":
            a_o_mux(ACIN)
        else:
            raise AssertionError()

        if AREG in (1, 2):
            If(
                clk_in._onRisingEdge(),
                If(RSTA, qa_o_reg1(0b0), qa_o_reg2(0b0)).Else(
                    If(CEA1, qa_o_reg1(a_o_mux)),
                    If(
                        CEA2,
                        qa_o_reg2(a_o_mux if AREG ==
                                  1 else qa_o_reg1 if AREG == 2 else None))))
        else:
            qa_o_reg1(None)

        if AREG == 0:
            qa_o_mux(a_o_mux)
        elif AREG == 1:
            qa_o_mux(qa_o_reg2)
        elif AREG == 2:
            qa_o_mux(qa_o_reg2)
        else:
            raise AssertionError()

        if ACASCREG == 1:
            qacout_o_mux(qa_o_reg1 if AREG == 2 else qa_o_mux)
        elif ACASCREG == 0:
            qacout_o_mux(qa_o_mux)
        elif ACASCREG == 2:
            qacout_o_mux(qa_o_mux)
        else:
            raise AssertionError()

        If(qinmode_o_mux[1], a_preaddsub(0b0)).Elif(
            qinmode_o_mux[0],
            a_preaddsub(qa_o_reg1[25:0]),
        ).Else(a_preaddsub(qa_o_mux[25:0]), )
        if B_INPUT == "DIRECT":
            b_o_mux(B)
        elif B_INPUT == "CASCADE":
            b_o_mux(BCIN)
        else:
            raise AssertionError()

        if BREG in (1, 2):
            If(
                clk_in._onRisingEdge(),
                If(RSTB, qb_o_reg1(0b0), qb_o_reg2(0b0)).Else(
                    If(CEB1, qb_o_reg1(b_o_mux)),
                    If(
                        CEB2,
                        qb_o_reg2(b_o_mux if BREG ==
                                  1 else qb_o_reg1 if BREG == 1 else None))))
        else:
            qb_o_reg1(None)

        if BREG == 0:
            qb_o_mux(b_o_mux)
        elif BREG == 1:
            qb_o_mux(qb_o_reg2)
        elif BREG == 2:
            qb_o_mux(qb_o_reg2)
        else:
            raise AssertionError()

        if BCASCREG == 1:
            qbcout_o_mux(qb_o_reg1 if BREG == 2 else qb_o_mux)
        elif BCASCREG == 0:
            qbcout_o_mux(qb_o_mux)
        elif BCASCREG == 2:
            qbcout_o_mux(qb_o_mux)
        else:
            raise AssertionError()

        b_mult(qinmode_o_mux[4]._ternary(qb_o_reg1, qb_o_mux))

        #*********************************************************
        #*** Input register C with 1 level deep of register
        #*********************************************************
        If(clk_in._onRisingEdge(),
           If(RSTC, qc_o_reg1(0b0)).Elif(CEC, qc_o_reg1(C)))
        if CREG == 0:
            qc_o_mux(C)
        elif CREG == 1:
            qc_o_mux(qc_o_reg1)
        else:
            raise AssertionError()

        #*********************************************************
        #*** Input register D with 1 level deep of register
        #*********************************************************
        If(clk_in._onRisingEdge(),
           If(RSTD, qd_o_reg1(0b0)).Elif(CED, qd_o_reg1(D)))
        if DREG == 0:
            qd_o_mux(D)
        elif DREG == 1:
            qd_o_mux(qd_o_reg1)
        else:
            raise AssertionError()

        ad_addsub(qinmode_o_mux[3]._ternary(
            -a_preaddsub + qinmode_o_mux[2]._ternary(qd_o_mux, 0b0),
            a_preaddsub + qinmode_o_mux[2]._ternary(qd_o_mux, 0b0)))

        If(clk_in._onRisingEdge(),
           If(RSTD, qad_o_reg1(0b0)).Elif(CEAD, qad_o_reg1(ad_addsub)))
        if ADREG == 0:
            qad_o_mux(ad_addsub)
        elif ADREG == 1:
            qad_o_mux(qad_o_reg1)
        else:
            raise AssertionError()

        ad_mult(qad_o_mux if USE_DPORT == "TRUE" else a_preaddsub)

        #*********************************************************
        #*********************************************************
        #***************      25x18 Multiplier     ***************
        #*********************************************************
        # 05/26/05 -- FP -- Added warning for invalid mult when USE_MULT=NONE
        # SIMD=FOUR12 and SIMD=TWO24
        # Made mult_o to be "X"
        if USE_MULT == "NONE" or USE_SIMD != "ONE48":
            mult_o(0b0)
        else:
            If(CARRYINSEL._eq(0b010), mult_o(None)).Else(
                mult_o(
                    replicate(18, ad_mult[24])._concat(ad_mult[25:0]) *
                    replicate(25, b_mult[17])._concat(b_mult)))

        If(clk_in._onRisingEdge(),
           If(RSTM, qmult_o_reg(0b0)).Elif(CEM, qmult_o_reg(mult_o)))

        If(qcarryinsel_o_mux._eq(0b010), qmult_o_mux(None)).Else(
            qmult_o_mux(qmult_o_reg if MREG == 1 else mult_o))

        #*** X mux
        # ask jmt
        # add post 2014.4
        # else
        Switch(qopmode_o_mux[2:0])\
            .Case(0b00,
                # X_SEL.ZERO
                qx_o_mux(0b0))\
            .Case(0b01,
                # X_SEL.M
                qx_o_mux(replicate(5, qmult_o_mux[A_MULT_W + B_MULT_W - 1])._concat(qmult_o_mux)))\
            .Case(0b10,
                # X_SEL.P
                qx_o_mux(qp_o_mux if PREG == 1 else None))\
            .Case(0b11,
                # X_SEL.A_B
                qx_o_mux(None)
                if USE_MULT == "MULTIPLY" and (
                    (AREG == 0 and BREG == 0 and MREG == 0) or
                    (AREG == 0 and BREG == 0 and PREG == 0) or
                    (MREG == 0 and PREG == 0))
                # print("OPMODE Input Warning : The OPMODE[1:0] %b to DSP48E1 instance %m is invalid when using attributes USE_MULT = MULTIPLY at %.3f ns. Please set USE_MULT to either NONE or DYNAMIC.", qopmode_o_mux[slice(2, 0)], sim.now // 1000.000000)
                else qx_o_mux(qa_o_mux[A_W:0]._concat(qb_o_mux[B_W:0]))
            )

        # add post 2014.4
        Switch(qopmode_o_mux[4:2])\
            .Case(0b00,
                qy_o_mux(0b0))\
            .Case(0b01,
                qy_o_mux(0b0))\
            .Case(0b10,
                qy_o_mux(y_mac_cascd))\
            .Case(0b11,
                qy_o_mux(qc_o_mux))

        #*** Z mux
        # ask jmt
        # add post 2014.4
        Switch(qopmode_o_mux[7:4])\
            .Case(0b000,
                qz_o_mux(0b0))\
            .Case(0b001,
                qz_o_mux(PCIN))\
            .Case(0b010,
                qz_o_mux(qp_o_mux))\
            .Case(0b011,
                qz_o_mux(qc_o_mux))\
            .Case(0b100,
                qz_o_mux(qp_o_mux))\
            .Case(0b101,
                qz_o_mux(replicate(17, PCIN[47])._concat(PCIN[48:17])))\
            .Case(0b110,
                qz_o_mux(replicate(17, qp_o_mux[47])._concat(qp_o_mux[48:17])))\
            .Case(0b111,
                qz_o_mux(replicate(17, qp_o_mux[47])._concat(qp_o_mux[48:17])))

        #*** CarryInSel and OpMode with 1 level of register
        If(
            clk_in._onRisingEdge(),
            If(RSTCTRL, qcarryinsel_o_reg1(0b0),
               qopmode_o_reg1(0b0)).Elif(CECTRL,
                                         qcarryinsel_o_reg1(CARRYINSEL),
                                         qopmode_o_reg1(opmode_in)))
        if CARRYINSELREG == 0:
            qcarryinsel_o_mux(CARRYINSEL)

        elif CARRYINSELREG == 1:
            qcarryinsel_o_mux(qcarryinsel_o_reg1)
        else:
            raise AssertionError()

        # CR 219047 (3)
        # If(qcarryinsel_o_mux._eq(0b010),
        #    If(~((cci_drc_msg._eq(0b1) | qopmode_o_mux._eq(0b1001000)) | (MULTSIGNIN._eq(0b0) & CARRYCASCIN._eq(0b0))),
        #        #print("DRC warning : CARRYCASCIN can only be used in the current DSP48E1 instance %m if the previous DSP48E1 is performing a two input ADD or SUBTRACT operation, or the current DSP48E1 is configured in the MAC extend opmode 7'b1001000 at %.3f ns.", sim.now // 1000.000000),
        #        cci_drc_msg(0b1)
        #    ),
        #    If(~((qopmode_o_mux[4:0] != 0b0101)._isOn())._isOn(),
        #        #print("DRC warning : CARRYINSEL is set to 010 with OPMODE set to multiplication (xxx0101). This is an illegal mode and may show deviation between simulation results and hardware behavior. DSP48E1 instance %m at %.3f ns.", sim.now // 1000.000000)
        #    ),
        #    If(~cis_drc_msg._eq(0b1),
        #        #print("DRC warning : CARRYINSEL is set to 010 with OPMODEREG set to 0. This causes unknown values after reset occurs. It is suggested to use OPMODEREG = 1 when cascading large adders. DSP48E1 instance %m at %.3f ns.", sim.now // 1000.000000),
        #        cis_drc_msg(0b1)
        #    ) if OPMODEREG == 0b1 else []
        # )
        if OPMODEREG == 0:
            qopmode_o_mux(opmode_in)
        elif OPMODEREG == 1:
            qopmode_o_mux(qopmode_o_reg1)
        else:
            raise AssertionError()

        #*** ALUMODE with 1 level of register
        If(
            clk_in._onRisingEdge(),
            If(RSTALUMODE,
               qalumode_o_reg1(0b0)).Elif(CEALUMODE,
                                          qalumode_o_reg1(alumode_in)))
        if ALUMODEREG == 0:
            qalumode_o_mux(alumode_in)
        elif ALUMODEREG == 1:
            qalumode_o_mux(qalumode_o_reg1)
        else:
            raise AssertionError()

        def deassign_xyz_mux_if_PREG_eq_1():
            if PREG != 1:
                return self.display_invalid_opmode()
            else:
                return self.deassign_xyz_mux()

        def DCR_check_logic_modes():
            # -- LOGIC MODES DRC
            return If(
                In(qopmode_o_mux, LOGIC_MODES_DRC_deassign_xyz_mux),
                self.deassign_xyz_mux()
            ).Elif(
                In(qopmode_o_mux,
                   LOGIC_MODES_DRC_deassign_xyz_mux_if_PREG_eq_1),
                deassign_xyz_mux_if_PREG_eq_1(),
            ).Else(
                # print("OPMODE Input Warning : The OPMODE %b to DSP48E1 instance %m is invalid for LOGIC MODES at %.3f ns.", qopmode_o_mux, sim.now // 1000.000000)
            )

        # display_invalid_opmode
        arith_mode_tmp = qopmode_o_mux._concat(qcarryinsel_o_mux)
        # no check at first 100ns
        Switch(qalumode_o_mux[4:2])\
            .Case(0b00,
                # -- ARITHMETIC MODES DRC
                If(In(arith_mode_tmp, ARITHMETIC_MODES_DRC_deassign_xyz_mux),
                    self.deassign_xyz_mux()
                ).Elif(In(arith_mode_tmp, ARITHMETIC_MODES_DRC_deassign_xyz_mux_if_PREG_eq_1),
                    deassign_xyz_mux_if_PREG_eq_1()
                ).Else(
                    # CR 444150
                    # If(qopmode_o_mux._concat(qcarryinsel_o_mux)._eq(0b0000000010)._isOn() & (OPMODEREG._eq(1)._isOn() & CARRYINSELREG._eq(0)._isOn())._isOn(),
                    #    print("DRC warning : CARRYINSELREG is set to %d. It is required to have CARRYINSELREG be set to 1 to match OPMODEREG, in order to ensure that the simulation model will match the hardware behavior in all use cases.", CARRYINSELREG)
                    # ),
                    # print("OPMODE Input Warning : The OPMODE %b to DSP48E1 instance %m is either invalid or the CARRYINSEL %b for that specific OPMODE is invalid at %.3f ns. This warning may be due to a mismatch in the OPMODEREG and CARRYINSELREG attribute settings. It is recommended that OPMODEREG and CARRYINSELREG always be set to the same value. ", qopmode_o_mux, qcarryinsel_o_mux, sim.now // 1000.000000)
                )
            )\
            .Case(0b01,
               DCR_check_logic_modes()
            )\
            .Case(0b11,
               DCR_check_logic_modes()
            )\
            .Default(
                # print("OPMODE Input Warning : The OPMODE %b to DSP48E1 instance %m is invalid for LOGIC MODES at %.3f ns.", qopmode_o_mux, sim.now // 1000.000000)
            )

        If(
            qalumode_o_mux[0],
            co(qx_o_mux & qy_o_mux
               | ~qz_o_mux & qy_o_mux | qx_o_mux & ~qz_o_mux),
            s(~qz_o_mux ^ qx_o_mux ^ qy_o_mux)).Else(
                co(qx_o_mux & qy_o_mux | qz_o_mux & qy_o_mux
                   | qx_o_mux & qz_o_mux), s(qz_o_mux ^ qx_o_mux ^ qy_o_mux))

        If(
            qalumode_o_mux[2],
            comux(0),
        ).Else(comux(co), )
        smux(qalumode_o_mux[3]._ternary(co, s))

        carryout_o_hw = self._sig("carryout_o_hw", Bits(CARRYOUT_W))
        carryout_o_hw[0](
            (qalumode_o_mux[0] & qalumode_o_mux[1])._ternary(~cout0, cout0))
        carryout_o_hw[1](
            (qalumode_o_mux[0] & qalumode_o_mux[1])._ternary(~cout1, cout1))
        carryout_o_hw[2](
            (qalumode_o_mux[0] & qalumode_o_mux[1])._ternary(~cout2, cout2))
        carryout_o_hw[3](
            (qalumode_o_mux[0] & qalumode_o_mux[1])._ternary(~cout3, cout3))
        alu_o(qalumode_o_mux[1]._ternary(
            ~Concat(s3[12:0], s2[12:0], s1[12:0], s0[12:0]),
            Concat(s3[12:0], s2[12:0], s1[12:0], s0[12:0])))
        carrycascout_o(cout3)
        multsignout_o_opmode(
            (qopmode_o_mux[7:4]._eq(0b100))._ternary(MULTSIGNIN,
                                                     qmult_o_mux[42]))
        If(
            (qopmode_o_mux[4:0]._eq(0b0101) | (qalumode_o_mux[4:2] != 0b00)),
            carryout_o[3](None),
            carryout_o[2](None),
            carryout_o[1](None),
            carryout_o[0](None),
        ).Else(
            carryout_o[3](carryout_o_hw[3]),
            carryout_o[2](carryout_o_hw[2] if USE_SIMD == "FOUR12" else None),
            carryout_o[1](carryout_o_hw[1] if USE_SIMD in
                          ["TWO24", "FOUR12"] else None),
            carryout_o[0](carryout_o_hw[0] if USE_SIMD == "FOUR12" else None),
        )

        #--########################### END ALU ################################
        #*** CarryIn Mux and Register
        #-------  input 0
        If(
            clk_in._onRisingEdge(),
            If(RSTALLCARRYIN,
               qcarryin_o_reg0(0b0)).Elif(CECARRYIN,
                                          qcarryin_o_reg0(carryin_in)))
        if CARRYINREG == 0:
            qcarryin_o_mux0(carryin_in)
        elif CARRYINREG == 1:
            qcarryin_o_mux0(qcarryin_o_reg0)
        else:
            raise AssertionError()

        #-------  input 7
        If(
            clk_in._onRisingEdge(),
            If(RSTALLCARRYIN, qcarryin_o_reg7(0b0)).Elif(
                CEM, qcarryin_o_reg7(ad_mult[24]._eq(b_mult[17]))))

        if MREG == 0:
            qcarryin_o_mux7(ad_mult[24]._eq(b_mult[17]))
        elif MREG == 1:
            qcarryin_o_mux7(qcarryin_o_reg7)
        else:
            raise ValueError(
                "MREG is set to %d. Legal values for this attribute are 0 or 1.",
                MREG)

        Switch(qcarryinsel_o_mux)\
            .Case(CARRYIN_SEL.CARRYIN.value,
                qcarryin_o_mux_tmp(qcarryin_o_mux0))\
            .Case(CARRYIN_SEL.PCIN_47_n.value,
                qcarryin_o_mux_tmp(~PCIN[47]))\
            .Case(CARRYIN_SEL.CARRYCASCIN.value,
                qcarryin_o_mux_tmp(CARRYCASCIN))\
            .Case(CARRYIN_SEL.PCIN_47.value,
                qcarryin_o_mux_tmp(PCIN[47]))\
            .Case(CARRYIN_SEL.CARRYCASCOUT.value,
                qcarryin_o_mux_tmp(carrycascout_o_mux))\
            .Case(CARRYIN_SEL.P_47_n.value,
                qcarryin_o_mux_tmp(~qp_o_mux[47]))\
            .Case(CARRYIN_SEL.A_27_eq_B_17.value,
                qcarryin_o_mux_tmp(qcarryin_o_mux7))\
            .Case(CARRYIN_SEL.P_47.value,
                qcarryin_o_mux_tmp(qp_o_mux[47]))

        # disable carryin when performing logic operation
        If(qalumode_o_mux[3] | qalumode_o_mux[2],
           qcarryin_o_mux(0b0)).Else(qcarryin_o_mux(qcarryin_o_mux_tmp))

        if AUTORESET_PATDET == "RESET_MATCH":
            the_auto_reset_patdet(pdet_o_reg1)
        elif AUTORESET_PATDET == "RESET_NOT_MATCH":
            the_auto_reset_patdet(pdet_o_reg2 & ~pdet_o_reg1)
        else:
            the_auto_reset_patdet(0)

        #--####################################################################
        #--#####      CARRYOUT, CARRYCASCOUT. MULTSIGNOUT and PCOUT      ######
        #--####################################################################
        #*** register with 1 level of register
        If(
            clk_in._onRisingEdge(),
            If(RSTP._isOn() | the_auto_reset_patdet._isOn(),
               carryout_o_reg(0b0), carrycascout_o_reg(0b0),
               qmultsignout_o_reg(0b0),
               qp_o_reg1(0b0)).Elif(CEP, carryout_o_reg(carryout_o),
                                    carrycascout_o_reg(carrycascout_o),
                                    qmultsignout_o_reg(multsignout_o_opmode),
                                    qp_o_reg1(alu_o)))
        if PREG == 0:
            carryout_o_mux(carryout_o)
            carrycascout_o_mux(carrycascout_o)
            multsignout_o_mux(multsignout_o_opmode)
            qp_o_mux(alu_o)

        elif PREG == 1:
            carryout_o_mux(carryout_o_reg)
            carrycascout_o_mux(carrycascout_o_reg)
            multsignout_o_mux(qmultsignout_o_reg)
            qp_o_mux(qp_o_reg1)
        else:
            raise AssertionError()

        carryout_x_o(
            Concat(
                carryout_o_mux[3],
                carryout_o_mux[2]
                if USE_SIMD == "FOUR12" else BIT.from_py(None),
                carryout_o_mux[1]
                if USE_SIMD in ["TWO24", "FOUR12"] else BIT.from_py(None),
                carryout_o_mux[0]
                if USE_SIMD == "FOUR12" else BIT.from_py(None),
            ))

        the_pattern(PATTERN if SEL_PATTERN == "PATTERN" else qc_o_mux)

        # selet mask
        if USE_PATTERN_DETECT == "NO_PATDET":
            the_mask(mask(48))
        elif SEL_MASK == "MASK":
            the_mask(MASK)
        elif SEL_MASK == "C":
            the_mask(qc_o_mux)
        elif SEL_MASK == "ROUNDING_MODE1":
            the_mask(~qc_o_mux << 1)
        elif SEL_MASK == "ROUNDING_MODE2":
            the_mask(~qc_o_mux << 2)
        else:
            raise AssertionError()

        If(
            opmode_valid_flag,
            pdet_o(And(*(~(the_pattern ^ alu_o) | the_mask))),
            pdetb_o(And(*(the_pattern ^ alu_o | the_mask))),
        ).Else(
            pdet_o(None),
            pdetb_o(None),
        )
        pdet_o_mux(pdet_o_reg1 if PREG == 1 else pdet_o)
        pdetb_o_mux(pdetb_o_reg1 if PREG == 1 else pdetb_o)

        #*** Output register PATTERN DETECT and UNDERFLOW / OVERFLOW
        If(
            clk_in._onRisingEdge(),
            If(RSTP._isOn() | the_auto_reset_patdet._isOn(), pdet_o_reg1(0b0),
               pdet_o_reg2(0b0), pdetb_o_reg1(0b0),
               pdetb_o_reg2(0b0)).Elif(CEP, pdet_o_reg2(pdet_o_reg1),
                                       pdet_o_reg1(pdet_o),
                                       pdetb_o_reg2(pdetb_o_reg1),
                                       pdetb_o_reg1(pdetb_o)))
        if PREG == 1 or USE_PATTERN_DETECT == "PATDET":
            overflow_o(pdet_o_reg2 & ~pdet_o_reg1 & ~pdetb_o_reg1),
            underflow_o(pdetb_o_reg2 & ~pdet_o_reg1 & ~pdetb_o_reg1)
        else:
            overflow_o(None),
            underflow_o(None)
Exemplo n.º 2
0
    def main_pipeline(self):
        PIPELINE_CONFIG = self.PIPELINE_CONFIG
        self.pipeline = pipeline = [
            OOOOpPipelineStage(i, f"st{i:d}", self)
            for i in range(PIPELINE_CONFIG.WAIT_FOR_WRITE_ACK + 1)
        ]

        state_read = self.state_array.port[1]
        self.collision_detector(pipeline)
        HAS_TRANS_ST = self.TRANSACTION_STATE_T is not None

        for i, st in enumerate(pipeline):
            if i > 0:
                st_prev = pipeline[i - 1]

            if i < len(pipeline) - 1:
                st_next = pipeline[i + 1]

            # :note: pipeline stages described in PIPELINE_CONFIG enum
            if i == PIPELINE_CONFIG.READ_DATA_RECEIVE:
                # :note: we can not apply forward write data there because we do not know the original address yet
                r = self.m.r
                state_read.addr(r.id)
                st.addr = state_read.dout[self.MAIN_STATE_INDEX_WIDTH:]
                if HAS_TRANS_ST:
                    low = self.MAIN_STATE_INDEX_WIDTH
                    st.transaction_state = state_read.dout[:low]._reinterpret_cast(self.TRANSACTION_STATE_T)

                r.ready(st.in_ready)
                st.in_valid(r.valid)
                st.out_ready(st_next.in_ready)
                state_read.en(st.load_en)
                If(st.load_en,
                    st.id(r.id),
                    self.data_load(r, st),
                )

            elif i <= PIPELINE_CONFIG.STATE_LOAD:
                If(st.load_en,
                    st.id(st_prev.id),
                    st.addr(st_prev.addr),
                    self.propagate_trans_st(st_prev, st),
                )
                self.apply_data_write_forwarding(st, st.load_en)
                st.in_valid(st_prev.valid)
                st.out_ready(st_next.in_ready)

            elif i == PIPELINE_CONFIG.WRITE_BACK:
                If(st.load_en,
                    st.id(st_prev.id),
                    st.addr(st_prev.addr),
                    self.propagate_trans_st(st_prev, st),
                )
                self.apply_data_write_forwarding(st, st.load_en, self.main_op)
                aw = self.m.aw
                w = self.m.w

                cancel = rename_signal(self, self.write_cancel(st), "write_back_cancel")
                st.in_valid(st_prev.valid)
                st.out_ready(st_next.in_ready & ((aw.ready & w.ready) | cancel))

                StreamNode(
                    [], [aw, w],
                    extraConds={
                        aw: st.valid & st_next.in_ready & ~cancel,
                        w: st.valid & st_next.in_ready & ~cancel
                    },
                    skipWhen={
                        aw:cancel,
                        w:cancel,
                    }
                ).sync()

                self._axi_addr_defaults(aw, 1)
                aw.id(st.id)
                aw.addr(Concat(st.addr, Bits(self.ADDR_OFFSET_W).from_py(0)))

                st_data = st.data
                if not isinstance(st_data, RtlSignal):
                    st_data = packIntf(st_data)

                w.data(st_data._reinterpret_cast(w.data._dtype))
                w.strb(mask(self.DATA_WIDTH // 8))
                w.last(1)

            elif i > PIPELINE_CONFIG.WRITE_BACK and i != PIPELINE_CONFIG.WAIT_FOR_WRITE_ACK:
                if i == PIPELINE_CONFIG.WRITE_BACK + 1:
                    st.in_valid(st_prev.valid & ((aw.ready & w.ready) | cancel))
                else:
                    st.in_valid(st_prev.valid)
                st.out_ready(st_next.in_ready)

                If(st.load_en,
                   st.id(st_prev.id),
                   st.addr(st_prev.addr),
                   st.data(st_prev.data),
                   self.propagate_trans_st(st_prev, st),
                )
            elif i == PIPELINE_CONFIG.WAIT_FOR_WRITE_ACK:
                If(st.load_en,
                    st.id(st_prev.id),
                    st.addr(st_prev.addr),
                    self.propagate_trans_st(st_prev, st),
                    st.data(st_prev.data),
                )
                dout = self.dataOut
                b = self.m.b
                confirm = self.ooo_fifo.read_confirm
                cancel = self.write_cancel(st)

                # ommiting st_next.ready as there is no next
                w_ack_node = StreamNode(
                    [b],
                    [dout, confirm],
                    extraConds={
                        dout: st.valid,
                        b: st.valid & ~cancel,
                        confirm: st.valid,
                    },
                    skipWhen={
                        b: st.valid & cancel,
                    }
                )
                w_ack_node.sync()
                st.in_valid(st_prev.valid)
                st.out_ready((b.valid | cancel) & dout.rd & confirm.rd)

                dout.addr(st.addr)
                dout.data(st.data)
                if HAS_TRANS_ST:
                    dout.transaction_state(st.transaction_state)

                confirm.data(st.id)
Exemplo n.º 3
0
    def _impl(self):
        USE_KEEP = self.USE_KEEP
        USE_STRB = self.USE_STRB
        FOOTER_WIDTH = self.FOOTER_WIDTH
        D_W = self.DATA_WIDTH
        LOOK_AHEAD = ceil(FOOTER_WIDTH / D_W)
        if FOOTER_WIDTH % 8 != 0:
            raise NotImplementedError()
        if not (self.USE_KEEP or self.USE_STRB):
            assert D_W == 8, ("AxiStream is configured not to use KEEP/STRB"
                              " but is required to resolve frame end", D_W)
        dout = self.dataOut
        regs = self.generate_regs(LOOK_AHEAD)
        self.flush_en_logic(regs)
        # resolve footer flags
        set_is_footer = self.is_footer_mask_set_values(LOOK_AHEAD, regs)
        din = self.dataIn
        # connect inputs/outputs of registers, dataIn, dataOut
        for is_last, (i, (r, is_footer, is_footer_set_val, can_flush, ready)) in\
                iter_with_last(enumerate(regs)):
            # :note: reg[0] is dataIn, reg[-1] is out_reg
            if is_last:
                # connect last register to outputs
                prev_r, prev_is_footer, _, _, _ = regs[i - 1]
                en = rename_signal(self, din.valid | can_flush, "out_en")
                # at least starts with non footer data
                d0_en = rename_signal(self, ~is_footer[0], "d0_en")
                # contains at least some footer data
                d1_en = rename_signal(self, is_footer != 0, "d1_en")

                # connect prefix data
                dout[0].data(r.data)
                # last if this word contains footer, or next word does not contains data
                d0_last_word_in_last_r = prev_r.valid & prev_is_footer[0]
                dout[0].last((is_footer != 0) | d0_last_word_in_last_r)
                dout[0].valid(r.valid & d0_en & en & (~d1_en | dout[1].ready))

                # connect footer
                dout[1].data(r.data)
                dout[1].last(r.last)
                dout[1].valid(r.valid & d1_en & en & (~d0_en | dout[0].ready))

                mask0 = ~is_footer
                mask1 = is_footer
                if USE_KEEP:
                    dout[0].keep(r.keep & mask0)
                    dout[1].keep(r.keep & mask1)
                if USE_STRB:
                    dout[0].strb(r.strb & mask0)
                    dout[1].strb(r.strb & mask1)

                ready(~r.valid
                      | ((dout[0].ready | ~d0_en) & (dout[1].ready | ~d1_en)))
            else:
                # connect only ready, because inputs of next register
                # are connected by next register
                next_ready = regs[i + 1][-1]
                if i == 0:
                    # dataIn is actually not a register
                    # and we do not need any extra check
                    ready(next_ready)
                else:
                    ready(~r.valid | next_ready)

            if i > 0:
                # connect register inputs, skip 0 because it is dataIn itself
                prev_r, prev_is_footer, _, prev_can_flush, _ = regs[i - 1]

                data_feed = []
                if USE_KEEP:
                    data_feed.append(r.keep(prev_r.keep))
                if USE_STRB:
                    data_feed.append(r.strb(prev_r.strb))

                prev_r_vld = prev_r.valid & (din.valid | prev_can_flush)
                If(
                    ready,
                    If(
                        prev_r_vld | can_flush,
                        r.data(prev_r.data),
                        r.last(prev_r.last),
                        *data_feed,
                    ),
                    If(
                        set_is_footer & ~(prev_r.valid & prev_r.last),
                        is_footer(is_footer_set_val),
                        r.valid(prev_r.valid),
                    ).Elif(
                        prev_r_vld,
                        is_footer(prev_is_footer),
                        r.valid(prev_r.valid),
                    ).Elif(
                        can_flush,
                        is_footer(0),
                        r.valid(0),
                    ))
Exemplo n.º 4
0
    def _impl(self):
        m = self.lru_mem
        victim_req_r, victim_req_w = m.port[:2]

        # victim selection ports
        victim_req = self.victim_req
        victim_req_r.en(victim_req.vld)
        victim_req_r.addr(victim_req.addr)
        victim_req_tmp = self._reg(
            "victim_req_tmp",
            HStruct(
              (victim_req.addr._dtype, "index"),
              (BIT, "vld")
            ),
            def_val={"vld": 0}
        )
        set_ = self.set
        victim_data = self.victim_data
        victim_req.rd(~set_.vld & (~victim_req_tmp.vld | victim_data.rd))
        If((~victim_req_tmp.vld | victim_data.rd) & ~set_.vld,
           victim_req_tmp.index(victim_req.addr),
           victim_req_tmp.vld(victim_req.vld),
        )

        incr_rw = list(grouper(2, m.port[2:]))

        # in the first stp we have to collect all pending addresses
        # because we need it in order to resolve any potential access merging
        incr_tmp_mask_oh = []
        for i, (incr_in, (incr_r, _)) in enumerate(zip(self.incr, incr_rw)):
            incr_tmp = self._reg(
                f"incr_tmp{i:d}",
                HStruct(
                    (incr_in.index._dtype, "index"),
                    (incr_in.way._dtype, "way"),
                    (BIT, "vld")
                ),
                def_val={"vld": 0}
            )
            incr_tmp.index(incr_in.index)
            incr_tmp.way(incr_in.way)
            incr_tmp.vld(incr_in.vld & ~set_.vld)

            incr_val_oh = rename_signal(self, binToOneHot(incr_in.way), f"incr_val{i:d}_oh")
            incr_tmp_mask_oh.append((incr_tmp, incr_val_oh))

        lru = PseudoLru(victim_req_r.dout)
        victim = rename_signal(self, lru.get_lru(), "victim")
        victim_oh = rename_signal(self, binToOneHot(victim), "victim_oh")

        victim_data.data(victim)
        victim_data.vld(victim_req_tmp.vld & ~set_.vld)

        succ_writes = [
            (incr2_tmp.vld & incr2_tmp.index._eq(victim_req_tmp.index), incr2_val_oh)
            for incr2_tmp, incr2_val_oh in incr_tmp_mask_oh
        ]
        _victim_oh = self.merge_successor_writes_into_incr_one_hot(succ_writes, victim_oh)
        _victim_oh = rename_signal(self, _victim_oh, f"victim_val{i:d}_oh_final")

        set_.rd(1)
        If(set_.vld,
            # repurpose victim req victim_req_w port for an intialization of LRU array using "set" port
            victim_req_w.en(1),
            victim_req_w.addr(set_.addr),
            victim_req_w.din(set_.data),
        ).Else(
            # use victim_req_w port for a victim req write back as usuall
            victim_req_w.en(victim_req_tmp.vld),
            victim_req_w.addr(victim_req_tmp.index),
            victim_req_w.din(lru.mark_use_many(_victim_oh)),
        )

        for i, (incr_in, (incr_r, incr_w), (incr_tmp, incr_val_oh)) in enumerate(zip(self.incr, incr_rw, incr_tmp_mask_oh)):
            # drive incr_r port
            incr_r.addr(incr_in.index)
            incr_r.en(incr_in.vld)
            incr_in.rd(~set_.vld)

            # resolve the final mask of LRU incrementation for this port and drive incr_w
            prev_writes = [
                    victim_req_tmp.vld & victim_req_tmp.index._eq(incr_tmp.index)
                ] + [
                    incr2_tmp.vld & incr2_tmp.index._eq(incr_tmp.index)
                    for incr2_tmp, _ in incr_tmp_mask_oh[:i]
                ]
            # if any of previous port writes to same index we need to ommit this write as it is writen by some previous port
            incr_w.addr(incr_tmp.index)
            incr_w.en(incr_tmp.vld & ~Or(*prev_writes) & ~set_.vld)

            succ_writes = [
                (incr2_tmp.vld & incr2_tmp.index._eq(incr_tmp.index), incr2_val_oh)
                for incr2_tmp, incr2_val_oh in incr_tmp_mask_oh[i + 1:]
            ]

            # if collides with others merge the incr_val_oh
            incr_val_oh = self.merge_successor_writes_into_incr_one_hot(succ_writes, incr_val_oh)
            incr_val_oh = rename_signal(self, incr_val_oh, f"incr_val{i:d}_oh_final")
            incr_w.din(PseudoLru(incr_r.dout).mark_use_many(incr_val_oh))

        propagateClkRstn(self)
Exemplo n.º 5
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)
Exemplo n.º 6
0
    def read_request_section(self, read_ack: RtlSignal, item_vld: RtlSignal,
                             waiting_transaction_id: RtlSignal,
                             waiting_transaction_vld: RtlSignal,
                             data_copy_override: VldSynced):
        s = self.s
        m = self.m
        addr_cam = self.addr_cam
        ITEMS = addr_cam.ITEMS
        addr_cam_out = self.add_addr_cam_out_reg(item_vld)

        with self._paramsShared():
            s_ar_tmp = self.s_ar_tmp = AxiSReg(s.AR_CLS)

        last_cam_insert_match = self._reg("last_cam_insert_match",
                                          Bits(ITEMS),
                                          def_val=0)
        match_res = rename_signal(
            self, item_vld & (addr_cam_out.data | last_cam_insert_match)
            & ~waiting_transaction_vld, "match_res")
        blocking_access = rename_signal(
            self, s.ar.valid & (item_vld[s.ar.id] |
                                (s_ar_tmp.dataOut.valid &
                                 (s.ar.id._eq(s_ar_tmp.dataOut.id)))),
            "blocking_access")
        s_ar_node = StreamNode(
            [s.ar],
            [addr_cam.match[0], s_ar_tmp.dataIn],
        )
        s_ar_node.sync(~blocking_access)
        # s_ar_node_ack = s_ar_node.ack() & ~blocking_access
        s_ar_tmp.dataIn(s.ar, exclude={s.ar.valid, s.ar.ready})

        parent_transaction_id = oneHotToBin(self, match_res,
                                            "parent_transaction_id")

        m_ar_node = StreamNode(
            [s_ar_tmp.dataOut, addr_cam_out],
            [m.ar],
            extraConds={m.ar: match_res._eq(0)},
            skipWhen={m.ar: match_res != 0},
        )
        m_ar_node.sync()
        m.ar(s_ar_tmp.dataOut, exclude={m.ar.valid, m.ar.ready})
        addr_cam.match[0].data(s.ar.addr[:self.CACHE_LINE_OFFSET_BITS])
        ar_ack = rename_signal(self, m_ar_node.ack(), "ar_ack")

        # insert into cam on empty position specified by id of this transaction
        acw = addr_cam.write
        acw.addr(s_ar_tmp.dataOut.id)
        acw.data(s_ar_tmp.dataOut.addr[:self.CACHE_LINE_OFFSET_BITS])
        acw.vld(addr_cam_out.vld)
        #If(s_ar_node_ack,
        last_cam_insert_match(
            binToOneHot(
                s_ar_tmp.dataOut.id,
                en=~blocking_access & s.ar.valid & s_ar_tmp.dataOut.valid
                & s_ar_tmp.dataOut.addr[:self.CACHE_LINE_OFFSET_BITS]._eq(
                    s.ar.addr[:self.CACHE_LINE_OFFSET_BITS])))
        #)

        for trans_id in range(ITEMS):
            # it becomes ready if we are requested for it on "s" interface
            this_trans_start = s_ar_tmp.dataOut.id._eq(trans_id) & \
                (data_copy_override.vld | ar_ack)
            # item becomes invalid if we read last data word
            this_trans_end = read_ack & s.r.id._eq(trans_id) & s.r.last
            this_trans_end = rename_signal(self, this_trans_end,
                                           f"this_trans_end{trans_id:d}")
            item_vld[trans_id](apply_set_and_clear(item_vld[trans_id],
                                                   this_trans_start,
                                                   this_trans_end))

            waiting_transaction_start = (ar_ack & (match_res != 0)
                                         & parent_transaction_id._eq(trans_id)
                                         & ~this_trans_end)
            # note: this_trans_end in this context is for parent transactio
            # which was not started just now, so it may be ending just now
            waiting_transaction_start = rename_signal(
                self, waiting_transaction_start,
                f"waiting_transaction_start{trans_id:d}")
            _waiting_transaction_vld = apply_set_and_clear(
                waiting_transaction_vld[trans_id], waiting_transaction_start,
                this_trans_end)
            waiting_transaction_vld[trans_id](rename_signal(
                self, _waiting_transaction_vld,
                f"waiting_transaction_vld{trans_id:d}"))

        If(
            self.clk._onRisingEdge(),
            If((match_res != 0) & ar_ack,
               waiting_transaction_id[parent_transaction_id](
                   s_ar_tmp.dataOut.id)))

        # parent transaction is finishing just now
        # we need to quickly grab the data in data buffer and copy it also
        # for this transaction
        data_copy_override.vld(s_ar_tmp.dataOut.valid & read_ack
                               & (match_res != 0)
                               & s.r.id._eq(parent_transaction_id) & s.r.last)
        data_copy_override.data(s_ar_tmp.dataOut.id)
Exemplo n.º 7
0
    def connect_lookup_port(self, lookup: AddrHs,
                            tag_mem_port_r: BramPort_withoutClk,
                            lookupRes: AxiCacheTagArrayLookupResIntf,
                            update_tmp: StructIntf):
        lookup_tmp = self._reg(
            "lookup_tmp",
            HStruct(*([(lookup.id._dtype, "id")] if lookup.ID_WIDTH else ()),
                    (lookup.addr._dtype, "addr"), (BIT, "vld")),
            def_val={"vld": 0})

        pa = self.parse_addr
        just_updated = rename_signal(
            self,
            # updated on same index (using "update" port) = the result which is currently on output
            # of the ram may be invalid
            update_tmp.vld
            & pa(lookup_tmp.addr)[1]._eq(pa(update_tmp.addr)[1]),
            "just_updated")

        # tag comparator
        tag, _, _ = self.parse_addr(lookup_tmp.addr)
        tags = tag_mem_port_r.dout._reinterpret_cast(
            self.tag_record_t[self.WAY_CNT])
        found = [
            # is matching and just this tag was not updated
            (t.valid & t.tag._eq(tag) &
             (~just_updated | (update_tmp.vld & ~update_tmp.way_en[i]))) | (
                 # or was updated to the matching tag
                 just_updated & update_tmp.way_en[i] & ~update_tmp.delete
                 & pa(lookup_tmp.addr)[0]._eq(pa(update_tmp.addr)[0]))
            for i, t in enumerate(tags)
        ]

        # if the data which is currently on output of the ram was
        # just updated it means that the data is invalid and the update
        # data will be lost in next clock cycle, if the consumer of lookupRes
        # can not consume the data just know, we need to perform lookup in tag_array
        # once again
        lookup.rd(~lookup_tmp.vld | lookupRes.rd)
        If(
            lookup.rd,
            lookup_tmp.id(lookup.id) if lookup.ID_WIDTH else [],
            lookup_tmp.addr(lookup.addr),
        )
        lookup_tmp.vld(lookup.vld | (lookup_tmp.vld & ~lookupRes.rd))

        tag_mem_port_r.addr((lookup_tmp.vld & ~lookupRes.rd)._ternary(
            self.parse_addr(lookup_tmp.addr)
            [1],  # lookup previous address and look for a change
            self.parse_addr(lookup.addr)[1],  # lookup a new address
        ))
        tag_mem_port_r.en(lookup.vld | (lookup_tmp.vld & ~lookupRes.rd))

        if lookupRes.ID_WIDTH:
            lookupRes.id(lookup_tmp.id)
        lookupRes.addr(lookup_tmp.addr)
        lookupRes.way(oneHotToBin(self, found))
        lookupRes.found(Or(*found))
        lookupRes.tags(tags)

        lookupRes.vld(lookup_tmp.vld)
Exemplo n.º 8
0
    def _impl(self):
        DEPTH = self.DEPTH

        index_t = Bits(log2ceil(DEPTH), signed=False)
        s = self._sig
        r = self._reg

        mem = self.mem = s("memory", Bits(self.DATA_WIDTH)[self.DEPTH + 1])
        # write pointer which is seen by reader
        wr_ptr = r("wr_ptr", index_t, 0)
        # read pointer which is used by reader and can be potentially
        # reseted to a rd_ptr value (copy command) or can update rd_ptr (non-copy command)
        rd_ptr_tmp = r("rd_ptr_tmp", index_t, 0)
        rd_ptr = r("rd_ptr", index_t, 0)
        MAX_DEPTH = DEPTH - 1
        assert MAX_DEPTH.bit_length() == index_t.bit_length(), (MAX_DEPTH,
                                                                index_t)

        dout = self.dataOut
        din = self.dataIn

        fifo_write = s("fifo_write")
        fifo_read = s("fifo_read")
        frame_copy = self.dataOut_copy_frame

        # Update Tail pointer as needed
        If(
            fifo_read,
            If(
                frame_copy.vld & frame_copy.data,
                If(rd_ptr._eq(MAX_DEPTH),
                   rd_ptr_tmp(0)).Else(rd_ptr_tmp(rd_ptr + 1))).Elif(
                       rd_ptr_tmp._eq(MAX_DEPTH),
                       rd_ptr_tmp(0)).Else(rd_ptr_tmp(rd_ptr_tmp + 1)),
        )
        If(
            frame_copy.vld & ~frame_copy.data,
            # jump to next frame
            rd_ptr(rd_ptr_tmp)
            # If(rd_ptr_tmp._eq(MAX_DEPTH),
            #    rd_ptr(0)
            # ).Else(
            #    rd_ptr(rd_ptr_tmp + 1)
            # )
        )

        wr_ptr_next = self._sig("wr_ptr_next", index_t)
        If(wr_ptr._eq(MAX_DEPTH), wr_ptr_next(0)).Else(wr_ptr_next(wr_ptr + 1))
        # Increment Head pointer as needed
        If(fifo_write, wr_ptr(wr_ptr_next))

        If(
            self.clk._onRisingEdge(),
            If(
                fifo_write,
                # Write Data to Memory
                mem[wr_ptr](din.data)))

        fifo_read(dout.en & (
            (wr_ptr != rd_ptr_tmp) | (frame_copy.vld & frame_copy.data)))
        read_addr_tmp = rename_signal(
            self,
            (frame_copy.vld & frame_copy.data)._ternary(rd_ptr, rd_ptr_tmp),
            "read_addr_tmp")
        If(
            self.clk._onRisingEdge(),
            If(
                fifo_read,
                # Update data output
                dout.data(mem[read_addr_tmp])))

        fifo_write(din.en & (wr_ptr_next != rd_ptr))

        # Update Empty and Full flags
        din.wait(wr_ptr_next._eq(rd_ptr))
        If(frame_copy.vld & frame_copy.data,
           dout.wait(0)).Else(dout.wait((wr_ptr._eq(rd_ptr_tmp))))