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)
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)
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), ))
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)
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)
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)
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)
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))))