def _eq(self, other: Union["StructIntf", StructValBase]): if isinstance(other, self.__class__): assert self._dtype == other._dtype return And( *(si._eq(oi) for si, oi in zip(self._interfaces, other._interfaces))) else: return And(*(si._eq(getattr(other, si._name)) for si in self._interfaces))
def get_lru(self): """ To find LRU, we can perform a depth-first-search starting from root, and traverse nodes in lower levels. If the node is 0, then we traverse the left sub-tree; otherwise, we traverse the right sub-tree. In the diagram above, the LRU is set 3. """ # node_index: bits rlu register node_paths = {} self._build_node_paths(node_paths, 0, tuple()) # also number of levels of rlu tree bin_index_w = log2ceil( self.lru_reg_items(self.lru_regs._dtype.bit_length())) lru_index_bin = [] # msb first in lru binary index for output_bit_i in range(bin_index_w): items_on_current_level = int(2**output_bit_i) current_level_offset = 2**output_bit_i - 1 possible_paths = [] for node_i in range(current_level_offset, current_level_offset + items_on_current_level): p = node_paths[node_i] possible_paths.append(And(*p)) lru_index_bin.append(Or(*possible_paths)) # MSB was first so the result is in little endian MSB..LSB return Concat(*lru_index_bin)
def stashLoad(self, isIdle, stash, lookupOrigin_out): lookup = self.lookup insert = self.insert delete = self.delete If(isIdle, If(self.clean.vld, stash.vldFlag(0) ).Elif(delete.vld, stash.key(delete.key), lookupOrigin_out(ORIGIN_TYPE.DELETE), stash.vldFlag(0), ).Elif(insert.vld, lookupOrigin_out(ORIGIN_TYPE.INSERT), stash.key(insert.key), stash.data(insert.data), stash.vldFlag(1), ).Elif(lookup.vld, lookupOrigin_out(ORIGIN_TYPE.LOOKUP), stash.key(lookup.key), ) ) priority = [self.clean, self.delete, self.insert, lookup] for i, intf in enumerate(priority): withLowerPrio = priority[:i] intf.rd(And(isIdle, *map(lambda x:~x.vld, withLowerPrio)))
def ack(self): """ :return: expression which's value is high when transaction can be made over interfaces """ # every interface has to have skip flag or it has to be ready/valid # and extraCond has to be True if present acks = [] for m in self.masters: extra, skip = self.getExtraAndSkip(m) if isinstance(m, ExclusiveStreamGroups): a = m.ack() else: a = _get_valid_signal(m) if extra: a = And(a, *extra) if skip is not None: a = Or(a, skip) acks.append(a) for s in self.slaves: extra, skip = self.getExtraAndSkip(s) if isinstance(s, ExclusiveStreamGroups): a = s.ack() else: a = _get_ready_signal(s) if extra: a = And(a, *extra) if skip is not None: a = Or(a, skip) acks.append(a) if not acks: return True return And(*acks)
def state_trans_cond(self, sst: StateTransItem, input_regs): cond = [] assert len(sst.input) == len(input_regs) for in_metas, in_regs in zip(sst.input, input_regs): assert len(in_metas) == len(in_regs) for in_meta, in_reg in zip(in_metas, in_regs): for k_i, k in enumerate(in_meta.keep): self.add_cond_bit(cond, in_reg.keep[k_i], k) self.add_cond_bit(cond, in_reg.relict, in_meta.relict) self.add_cond_bit(cond, in_reg.last, in_meta.last) return And(*cond)
def renderEventDepIfContainer(self, ifStm: IfContainer, s: RtlSignalBase, connectOut): assert not ifStm.ifFalse, ifStm if ifStm.elIfs: raise NotImplementedError(MUX) subStms = list(walkStatementsForSig(ifStm.ifTrue, s)) assert len(subStms) == 1, subStms subStm = subStms[0] assig = None clk_spec = [ ifStm.cond, ] subStm_tmp = subStm while True: if isinstance(subStm_tmp, IfContainer): clk_spec.append(subStm.cond) subStm_tmp = list(walkStatementsForSig(subStm_tmp.ifTrue, s)) if len(subStm_tmp) > 1: raise NotImplementedError("Probably write with the mask", subStm_tmp) subStm_tmp = subStm_tmp[0] continue elif isinstance(subStm_tmp, HdlAssignmentContainer): if subStm_tmp.indexes: assig = subStm_tmp break break if assig is None: _, _in = self.renderForSignal(subStm, s, False) return self.createFFNode(s, ifStm.cond, _in, connectOut) if len(assig.indexes) != 1: raise NotImplementedError() addr = assig.indexes[0] # ram write port # collect clk and clk_en if len(clk_spec) > 1: clk = clk_spec[0] w_en = And(*clk_spec[1:]) else: clk = clk_spec[0] w_en = None return self.createRamWriteNode(assig.dst, clk, addr, assig.src, w_en, connectOut)
def _impl(self): rd = self.getRd vld = self.getVld data = self.getData for io in self.dataOut: for i, o in zip(data(self.dataIn), data(io)): o(i) outRd = And(*[rd(i) for i in self.dataOut]) rd(self.dataIn)(outRd) for o in self.dataOut: # everyone else is ready and input is valid deps = [vld(self.dataIn)] for otherO in self.dataOut: if otherO is o: continue deps.append(rd(otherO)) _vld = And(*deps) vld(o)(_vld)
def ackForMaster(self, master): """ :return: driver of ready signal for master """ otherMasters = where(self.masters, lambda x: x is not master) extra, skip = self.getExtraAndSkip(master) conds = [*map(self.vld, otherMasters), *map(self.rd, self.slaves), *extra] if conds: r = And(*conds) else: r = BIT.from_py(1) if skip is not None: r = r & ~skip return r
def ackForSlave(self, slave): """ :return: driver of valid signal for slave """ otherSlaves = where(self.slaves, lambda x: x is not slave) extra, skip = self.getExtraAndSkip(slave) conds = [*map(self.vld, self.masters), *map(self.rd, otherSlaves), *extra] if conds: v = And(*conds) else: v = BIT.from_py(1) if skip is not None: v = v & ~skip return v
def _impl(self): rd = self.get_ready_signal vld = self.get_valid_signal dout = self.dataOut vldSignals = [vld(d) for d in self.dataIn] # data out mux dataCases = [] for i, din in enumerate(self.dataIn): allLowerPriorNotReady = map(lambda x: ~x, vldSignals[:i]) rd(din)(And(rd(dout), *allLowerPriorNotReady)) cond = vld(din) dataConnectExpr = self.dataConnectionExpr(din, dout) dataCases.append((cond, dataConnectExpr)) dataDefault = self.dataConnectionExpr(None, dout) SwitchLogic(dataCases, dataDefault) vld(dout)(Or(*vldSignals))
def getAckOfOthers(self: OutNodeInfo, others: List[OutNodeInfo]): ackOfOthers = [hBit(1) if o is self else o.ack() for o in others] if ackOfOthers: return And(*ackOfOthers) else: return hBit(1)
def getAckOfOthers(self: OutNodeInfo, others: List[OutNodeInfo]): ackOfOthers = [BIT.from_py(1) if o is self else o.ack() for o in others] return And(*ackOfOthers)
def stash_load(self, isIdle, lookupResNext, insertTargetOH, stash, lookup_not_in_progress, another_lookup_possible): """ load a stash register from lookup/insert/delete interface """ lookup = self.lookup insert = self.insert delete = self.delete table_lookup_ack = StreamNode(slaves=[t.lookup for t in self.tables]).ack() lookup_currently_executed = stash.origin_op._eq(ORIGIN_TYPE.LOOKUP) assert self.MAX_REINSERT > 0, self.MAX_REINSERT If(isIdle, If(lookup_not_in_progress & self.clean.vld, stash.origin_op(ORIGIN_TYPE.DELETE), stash.item_vld(0) ).Elif(lookup_not_in_progress & delete.vld, stash.origin_op(ORIGIN_TYPE.DELETE), stash.key(delete.key), stash.item_vld(0), ).Elif(lookup_not_in_progress & insert.vld, stash.origin_op(ORIGIN_TYPE.INSERT), stash.key(insert.key), stash.data(insert.data), stash.reinsert_cntr(self.MAX_REINSERT), stash.item_vld(1), ).Elif(lookup.vld & lookup.rd, stash.origin_op(ORIGIN_TYPE.LOOKUP), stash.key(lookup.key), ).Elif(table_lookup_ack, stash.origin_op(ORIGIN_TYPE.DELETE), # need to set something else than lookup stash.key(None), ) ).Elif(lookupResNext, SwitchLogic([ (insertTargetOH[i], [ # load stash from item found previously # :note: happens in same time as write to table # so the stash and item in table is swapped stash.key(t.lookupRes.key), stash.data(t.lookupRes.data), stash.reinsert_cntr(stash.reinsert_cntr - 1), stash.item_vld(t.lookupRes.occupied), ] ) for i, t in enumerate(self.tables) ], default=[ stash.origin_op(ORIGIN_TYPE.DELETE), stash.key(None), stash.data(None), stash.reinsert_cntr(None), stash.item_vld(None), ]) ) cmd_priority = [self.clean, self.delete, self.insert, lookup] for i, intf in enumerate(cmd_priority): withLowerPrio = cmd_priority[:i] rd = And(isIdle, *[~x.vld for x in withLowerPrio]) if intf is lookup: rd = rd & (~lookup_currently_executed | # the stash not loaded yet table_lookup_ack # stash will be consumed ) & another_lookup_possible else: rd = rd & lookup_not_in_progress intf.rd(rd)
def ack(self) -> RtlSignal: if self: return And(*map(lambda x: x.ack(), self)) else: return BIT.from_py(1)
def ack(self) -> RtlSignal: if self: return And(*map(lambda x: x.ack(), self)) else: return hBit(1)
def _impl(self): propagateClkRstn(self) lookupRes = self.lookupRes tables = self.tables # stash is storage for item which is going to be swapped with actual stash_t = HStruct( (Bits(self.KEY_WIDTH), "key"), (Bits(self.DATA_WIDTH), "data"), (BIT, "vldFlag") ) stash = self._reg("stash", stash_t) lookupOrigin = self._reg("lookupOrigin", Bits(2)) cleanAck = self._sig("cleanAck") cleanAddr, cleanLast = self.cleanUpAddrIterator(cleanAck) lookupResRead = self._sig("lookupResRead") lookupResNext = self._sig("lookupResNext") (lookupResAck, insertFinal, insertFound, targetOH) = self.lookupResOfTablesDriver(lookupResRead, lookupResNext) lookupAck = StreamNode(slaves=map(lambda t: t.lookup, tables)).ack() insertAck = StreamNode(slaves=map(lambda t: t.insert, tables)).ack() fsm_t = HEnum("insertFsm_t", ["idle", "cleaning", "lookup", "lookupResWaitRd", "lookupResAck"]) isExternLookup = lookupOrigin._eq(ORIGIN_TYPE.LOOKUP) state = FsmBuilder(self, fsm_t, "insertFsm")\ .Trans(fsm_t.idle, (self.clean.vld, fsm_t.cleaning), # before each insert suitable place has to be searched first (self.insert.vld | self.lookup.vld | self.delete.vld, fsm_t.lookup) ).Trans(fsm_t.cleaning, # walk all items and clean it's vldFlags (cleanLast, fsm_t.idle) ).Trans(fsm_t.lookup, # search and resolve in which table item # should be stored (lookupAck, fsm_t.lookupResWaitRd) ).Trans(fsm_t.lookupResWaitRd, # process result of lookup and # write data stash to tables if # required (lookupResAck, fsm_t.lookupResAck) ).Trans(fsm_t.lookupResAck, # process lookupRes, if we are going to insert on place where # valid item is, it has to # be stored (lookupOrigin._eq( ORIGIN_TYPE.DELETE), fsm_t.idle), (isExternLookup & lookupRes.rd, fsm_t.idle), # insert into specified # table (~isExternLookup & insertAck & insertFinal, fsm_t.idle), (~isExternLookup & insertAck & ~insertFinal, fsm_t.lookup) ).stateReg cleanAck(StreamNode(slaves=[t.insert for t in tables]).ack() & state._eq(fsm_t.cleaning)) lookupResRead(state._eq(fsm_t.lookupResWaitRd)) lookupResNext(And(state._eq(fsm_t.lookupResAck), Or(lookupOrigin != ORIGIN_TYPE.LOOKUP, lookupRes.rd))) isIdle = state._eq(fsm_t.idle) self.stashLoad(isIdle, stash, lookupOrigin) insertIndex = self.insertAddrSelect(targetOH, state, cleanAddr) self.insetOfTablesDriver( state, targetOH, insertIndex, stash, isExternLookup) self.lookupResDriver(state, lookupOrigin, lookupAck, insertFound) self.lookupOfTablesDriver(state, stash.key)
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 _injectParametersIntoPortTypes( self, port_type_variants: List[Tuple[HdlPortItem, Dict[Tuple[Param, HValue], List[HdlType]]]], param_signals: List[RtlSignal]): updated_type_ids = set() param_sig_by_name = {p.name: p for p in param_signals} param_value_domain = {} for parent_port, param_val_to_t in port_type_variants: for (param, param_value), port_types in param_val_to_t.items(): param_value_domain.setdefault(param, set()).add(param_value) for parent_port, param_val_to_t in port_type_variants: if id(parent_port._dtype) in updated_type_ids: continue # check which unique parameter values affects the type of the port # if the type changes with any parameter value integrate it in to type of the port # print(parent_port, param_val_to_t) type_to_param_values = {} for (param, param_value), port_types in param_val_to_t.items(): for pt in port_types: cond = type_to_param_values.setdefault(pt, UniqList()) cond.append((param, param_value)) assert type_to_param_values, parent_port if len(type_to_param_values) == 1: continue # type does not change # Param: values params_used = {} for t, param_values in type_to_param_values.items(): for (param, param_val) in param_values: params_used.setdefault(param, set()).add(param_val) # filter out parameters which are not part of type specification process for p, p_vals in list(params_used.items()): if len(param_value_domain[p]) == len(p_vals): params_used.pop(p) # reset sets used to check parameter values for p, p_vals in params_used.items(): p_vals.clear() if not params_used: raise AssertionError( parent_port, "Type changes between the variants but it does not depend on parameter", param_val_to_t) if len(params_used) == 1 and list( params_used.keys())[0].get_hdl_type() == INT: # try to extract param * x + y p_val_to_port_w = {} for t, param_values in type_to_param_values.items(): for (param, param_val) in param_values: if param not in params_used: continue assert param_val not in p_val_to_port_w or p_val_to_port_w[ param_val] == t.bit_length(), parent_port p_val_to_port_w[param_val] = t.bit_length() # t_width = n*p + c _p_val_to_port_w = sorted(p_val_to_port_w.items()) t_width0, p0 = _p_val_to_port_w[0] t_width1, p1 = _p_val_to_port_w[1] # 0 == t_width0 - n*p0 + c # 0 == t_width1 - n*p1 + c # 0 == t_width0 - n*p0 - c + t_width1 - n*p1 - c # 0 == t_width0 + t_width1 - n*(p0 + p1) - 2c # c == (t_width0 + t_width1 - n*(p0 + p1) ) //2 # n has to be int, 0 < n <= t_width0/p0 # n is something like base size of port which is multipled by parameter # we searching n for which we can resolve c found_nc = None for n in range(1, t_width0 // p0 + 1): c = (t_width0 + t_width1 - n * (p0 + p1)) // 2 if t_width0 - n * p0 + c == 0 and t_width1 - n * p1 + c == 0: found_nc = (n, c) break if found_nc is None: raise NotImplementedError() else: p = list(params_used.keys())[0] p = param_sig_by_name[p._name] (n, c) = found_nc t = parent_port._dtype t._bit_length = INT.from_py(n) * p + c t._bit_length._const = True updated_type_ids.add(id(t)) else: condition_and_type_width = [] default_width = None for t, p_vals in sorted(type_to_param_values.items(), key=lambda x: x[0].bit_length()): cond = And(*(param_sig_by_name[p.hdl_name]._eq(p_val) for p, p_val in p_vals if p in params_used)) w = t.bit_length() if default_width is None: default_width = w condition_and_type_width.append((cond, w)) t = parent_port._dtype t._bit_length = reduce_ternary(condition_and_type_width, default_width) t._bit_length._const = True updated_type_ids.add(id(t))