def _declr(self): HandshakeSync._declr(self) args = HObjList() for a in self._exception.hw_args: _a = monitor_of(a) args.append(_a) self.args = args
def _declr(self) -> None: self._normalize_config() addClkRstn(self) slavePorts = HObjList() for _ in self.MASTERS: s = Mi32() s._updateParamsFrom(self) slavePorts.append(s) self.s = slavePorts masterPorts = HObjList() for _, size in self.SLAVES: m = Mi32()._m() m.ADDR_WIDTH = log2ceil(size - 1) m.DATA_WIDTH = self.DATA_WIDTH masterPorts.append(m) self.m = masterPorts # fifo which keeps index of slave for master read transaction # so the interconnect can delivery the read data to master # which asked for it f = self.r_data_order = HandshakedFifo(Handshaked) f.DEPTH = self.MAX_TRANS_OVERLAP f.DATA_WIDTH = log2ceil(len(self.SLAVES))
def _declr(self): BusInterconnect._normalize_config(self) self.connection_groups_r = BusInterconnectUtils._extract_separable_groups( self.MASTERS, self.SLAVES, READ) self.connection_groups_w = BusInterconnectUtils._extract_separable_groups( self.MASTERS, self.SLAVES, WRITE) super(AxiInterconnectMatrix, self)._declr() # instantiate sub interconnects for each independent master-slave connection # subgraph (r, w separately) self.sub_interconnect_connections = [] r_interconnects = HObjList() masters_with_read_ch = set() slaves_with_read_ch = set() for r_group in self.connection_groups_r: master_indexes, slave_indexes = r_group masters_with_read_ch.update(master_indexes) slaves_with_read_ch.update(slave_indexes) inter = AxiInterconnectMatrixR(self.intfCls) con = self.configure_sub_interconnect(master_indexes, slave_indexes, inter) r_interconnects.append(inter) self.sub_interconnect_connections.extend(con) masters_with_write_ch = set() slaves_with_write_ch = set() w_interconnects = HObjList() for w_group in self.connection_groups_w: master_indexes, slave_indexes = w_group masters_with_write_ch.update(master_indexes) slaves_with_write_ch.update(slave_indexes) inter = AxiInterconnectMatrixW(self.intfCls) con = self.configure_sub_interconnect(master_indexes, slave_indexes, inter) w_interconnects.append(inter) self.sub_interconnect_connections.extend(con) with self._paramsShared(exclude=({"SLAVES", "MASTERS"}, set())): self.r_interconnects = r_interconnects self.w_interconnects = w_interconnects # dissable read/write unused channels on master/slave interfaces for m_i, m in enumerate(self.s): m.HAS_R = m_i in masters_with_read_ch m.HAS_W = m_i in masters_with_write_ch assert m.HAS_R or m.HAS_W, m_i for s_i, s in enumerate(self.m): s.HAS_R = s_i in slaves_with_read_ch s.HAS_W = s_i in slaves_with_write_ch assert s.HAS_R or s.HAS_W, s_i
def _declr_children(self): # for the case where this memory will be relized using multiple memory blocks children = HObjList() MAX_DW = self.MAX_BLOCK_DATA_WIDTH if MAX_DW is not None and MAX_DW < self.DATA_WIDTH: DW = self.DATA_WIDTH while DW > 0: c = self.__class__() c._updateParamsFrom(self, exclude=({"DATA_WIDTH"}, {})) c.DATA_WIDTH = min(DW, MAX_DW) if self.INIT_DATA is not None: raise NotImplementedError() children.append(c) DW -= MAX_DW self.children = children
def _declr(self): AxiInterconnectCommon._declr(self, has_r=False, has_w=True) masters_for_slave = AxiInterconnectMatrixCrossbar._masters_for_slave( self.MASTERS, len(self.SLAVES)) # fifo for master index for each slave so slave knows # which master did read and where is should send it order_m_index_for_s_data = HObjList() order_m_index_for_s_b = HObjList() for connected_masters in masters_for_slave: if len(connected_masters) > 1: f_w = HandshakedFifo(Handshaked) f_b = HandshakedFifo(Handshaked) for _f in [f_w, f_b]: _f.DEPTH = self.MAX_TRANS_OVERLAP _f.DATA_WIDTH = log2ceil(len(self.MASTERS)) else: f_w, f_b = None, None order_m_index_for_s_data.append(f_w) order_m_index_for_s_b.append(f_b) self.order_m_index_for_s_data = order_m_index_for_s_data self.order_m_index_for_s_b = order_m_index_for_s_b # fifo for slave index for each master # so master knows where it should expect the data order_s_index_for_m_data = HObjList() order_s_index_for_m_b = HObjList() for connected_slaves in self.MASTERS: if len(connected_slaves) > 1: f_w = HandshakedFifo(Handshaked) f_b = HandshakedFifo(Handshaked) for f in [f_w, f_b]: f.DEPTH = self.MAX_TRANS_OVERLAP f.DATA_WIDTH = log2ceil(len(self.SLAVES)) else: f_w, f_b = None, None order_s_index_for_m_data.append(f_w) order_s_index_for_m_b.append(f_b) self.order_s_index_for_m_data = order_s_index_for_m_data self.order_s_index_for_m_b = order_s_index_for_m_b AXI = self.intfCls with self._paramsShared(): self.addr_crossbar = AxiInterconnectMatrixAddrCrossbar(AXI.AW_CLS) with self._paramsShared(): c = self.data_crossbar = AxiInterconnectMatrixCrossbar(AXI.W_CLS) c.INPUT_CNT = len(self.MASTERS) W_OUTPUTS = [set() for _ in self.SLAVES] for m_i, accessible_slaves in enumerate(self.MASTERS): for s_i in accessible_slaves: W_OUTPUTS[s_i].add(m_i) c.OUTPUTS = W_OUTPUTS with self._paramsShared(): c = self.b_crossbar = AxiInterconnectMatrixCrossbarB(AXI.B_CLS) c.INPUT_CNT = len(self.SLAVES) c.OUTPUTS = self.MASTERS
def parseTemplate(self): t = self._structT try: t.bit_length() is_const_size_frame = True except TypeError: is_const_size_frame = False if is_const_size_frame: self.sub_t = [] self.children = [] super(AxiS_frameParser, self).parseTemplate() else: if self._tmpl or self._frames: raise NotImplementedError() children = HObjList() self.sub_t = sub_t = [] is_const_sized = self.sub_t_is_const_sized = [] is_padding = self.sub_t_is_padding = [] separated = list(HdlType_separate(t, is_non_const_stream)) if len(separated) > 1 or separated[0][0]: # it may be required to delegate this on children first = True for is_non_const_sized, s_t in separated: _is_padding = is_only_padding(s_t) if is_non_const_sized or (not first and _is_padding): c = None else: c = self.__class__(s_t) sub_t.append(s_t) children.append(c) first = False is_padding.append(_is_padding) is_const_sized.append(not is_non_const_sized) if len(is_const_sized) >= 2 and \ is_const_sized[0] and\ not is_const_sized[1]: # we will parse const-size prefix and # then there will be a variable size suffix children[0].OVERFLOW_SUPPORT = True with self._paramsShared(exclude=({"OVERFLOW_SUPPORT", "T"}, {})): self.children = children
def create_data_reg(self, name_prefix, clk=None, rst=None): """ Create a registers for data signals with default values from :class:`hwt.synthesizer.unit.Unit` parameters and with specified clk/rst """ regs = HObjList() def_vals = self.DATA_RESET_VAL d_sigs = self.get_data(self.dataIn) if def_vals is None or isinstance(def_vals, (int)): def_vals = [def_vals for _ in d_sigs] for d, def_val in zip(d_sigs, def_vals): r = self._reg(name_prefix + d._name, d._dtype, def_val=def_val, clk=clk, rst=rst) regs.append(r) return regs
def _declr(self) -> None: self._normalize_config() addClkRstn(self) slavePorts = HObjList() for _ in self.MASTERS: s = Ipif() s._updateParamsFrom(self) slavePorts.append(s) self.s = slavePorts masterPorts = HObjList() for _, size in self.SLAVES: m = Ipif()._m() m.ADDR_WIDTH = log2ceil(size - 1) m.DATA_WIDTH = self.DATA_WIDTH masterPorts.append(m) self.m = masterPorts
def _declr(self): AxiInterconnectCommon._declr(self, has_r=True, has_w=False) masters_for_slave = AxiInterconnectMatrixCrossbar._masters_for_slave( self.MASTERS, len(self.SLAVES)) # fifo for master index for each slave so slave knows # which master did read and where is should send it order_m_index_for_s_data = HObjList() for connected_masters in masters_for_slave: if len(connected_masters) > 1: f = HandshakedFifo(Handshaked) f.DEPTH = self.MAX_TRANS_OVERLAP f.DATA_WIDTH = log2ceil(len(self.MASTERS)) else: f = None order_m_index_for_s_data.append(f) self.order_m_index_for_s_data = order_m_index_for_s_data # fifo for slave index for each master # so master knows where it should expect the data order_s_index_for_m_data = HObjList() for connected_slaves in self.MASTERS: if len(connected_slaves) > 1: f = HandshakedFifo(Handshaked) f.DEPTH = self.MAX_TRANS_OVERLAP f.DATA_WIDTH = log2ceil(len(self.SLAVES)) else: f = None order_s_index_for_m_data.append(f) self.order_s_index_for_m_data = order_s_index_for_m_data with self._paramsShared(): self.addr_crossbar = AxiInterconnectMatrixAddrCrossbar( self.intfCls.AR_CLS) with self._paramsShared(): c = self.data_crossbar = AxiInterconnectMatrixCrossbar( self.intfCls.R_CLS) c.INPUT_CNT = len(self.SLAVES) c.OUTPUTS = self.MASTERS
def _declr_ports(self): PORTS = self.PORT_CNT with self._paramsShared(): ports = HObjList() if isinstance(PORTS, int): for _ in range(PORTS): p = self.PORT_CLS() ports.append(p) else: for access_mode in PORTS: p = self.PORT_CLS() if access_mode == READ_WRITE: pass elif access_mode == READ: p.HAS_W = False elif access_mode == WRITE: p.HAS_R = False else: raise ValueError(access_mode) ports.append(p) self.port = ports
def _declr(self): addClkRstn(self) INTF_CLS = self.intfCls INPUT_CNT = self.INPUT_CNT OUTPUT_CNT = len(self.OUTPUTS) self.OUTS_FOR_IN = self._masters_for_slave(self.OUTPUTS, self.INPUT_CNT) with self._paramsShared(): self.dataIn = HObjList([INTF_CLS() for _ in range(INPUT_CNT)]) with self._paramsShared(): self.dataOut = HObjList( [INTF_CLS()._m() for _ in range(OUTPUT_CNT)]) # master index for each slave so slave knows # which master did read and where is should send it order_dout_index_for_din_in = HObjList() for connected_outs in self.OUTS_FOR_IN: if len(connected_outs) > 1: f = Handshaked() f.DATA_WIDTH = log2ceil(OUTPUT_CNT) else: f = None order_dout_index_for_din_in.append(f) self.order_dout_index_for_din_in = order_dout_index_for_din_in order_din_index_for_dout_in = HObjList() # slave index for each master # so master knows where it should expect the data for connected_ins in self.OUTPUTS: if len(connected_ins) > 1: f = Handshaked() f.DATA_WIDTH = log2ceil(INPUT_CNT) else: f = None order_din_index_for_dout_in.append(f) self.order_din_index_for_dout_in = order_din_index_for_dout_in
def _declr(self) -> None: addClkRstn(self) slavePorts = HObjList() for _, features in self._masters: if features is not ACCESS_RW: raise NotImplementedError(features) m = Ipif() m._updateParamsFrom(self) slavePorts.append(m) self.s = slavePorts masterPorts = HObjList() for _, size, features in self._slaves: if features is not ACCESS_RW: raise NotImplementedError(features) s = Ipif()._m() s.ADDR_WIDTH.set(log2ceil(size - 1)) s._replaceParam(s.DATA_WIDTH, self.DATA_WIDTH) masterPorts.append(s) self.m = masterPorts
def delegate_to_children(self): """ For the cases where output frames contains the streams which does not have start aligned to a frame word boundary, we have to build rest of the frame in child FrameForge and then instantiate AxiS_FrameJoin which will join such a unaligned frames together. """ Cls = self.__class__ assert len(self.sub_t) > 1, "We need to delegate to children only " \ "if there is something which we can't do in this comp. directly" children = HObjList() for t in self.sub_t: _t = _get_only_stream(t) if _t is None: # we need a child to build a sub frame c = Cls(t) c.USE_KEEP = self.USE_STRB | self.DATA_WIDTH != 8 else: # we will connect stream directly c = None children.append(c) with self._paramsShared( exclude=({"USE_KEEP", "USE_STRB", *TYPE_CONFIG_PARAMS_NAMES}, {})): self.children = children fjoin = AxiS_FrameJoin() sub_t_flatten = [to_primitive_stream_t(s_t) for s_t in self.sub_t] fjoin.T = HStruct(*((s_t, f"frame{i:d}") for i, s_t in enumerate(sub_t_flatten))) fjoin._updateParamsFrom(self, exclude=({"USE_KEEP", "T"}, {})) # has to have keep, because we know that atleast one output will # have unaligned start fjoin.USE_KEEP = True self.frame_join = fjoin dout = self.dataOut if not self.USE_KEEP: exclude = (fjoin.dataOut.keep, ) else: exclude = () dout(fjoin.dataOut, exclude=exclude) propagateClkRstn(self) for i, c in enumerate(children): if c is None: # find the input stream _t, child_out = drill_down_in_HStruct_fields( self.sub_t[i], self.dataIn) assert isinstance(_t, HStream) else: # connect children inputs connect_optional_with_best_effort_axis_mask_propagation( self.dataIn, c.dataIn) child_out = c.dataOut # join children output streams to output fj_in = fjoin.dataIn[i] if fj_in.USE_KEEP and not child_out.USE_KEEP: if child_out.USE_STRB: exclude = {child_out.strb, fj_in.keep} fj_in.keep(child_out.strb) if fj_in.USE_STRB: fj_in.strb(child_out.strb) else: exclude = {fj_in.keep} keep_all = mask(fj_in.keep._dtype.bit_length()) fj_in.keep(keep_all) if fj_in.USE_STRB: fj_in.strb(keep_all) elif not self.USE_STRB and child_out.USE_STRB: exclude = (child_out.strb, ) else: exclude = () fj_in(child_out, exclude=exclude)
def _impl(self): REG_IN = self.REG_IN REQUIRES_CASCADE = self.REG_OUT and self.DATA_WIDTH > 48 dsps = HObjList() for i in range(ceil(self.DATA_WIDTH / 48)): dsp = DSP48E1() dsp.A_INPUT = "DIRECT" dsp.B_INPUT = "DIRECT" dsp.USE_DPORT = "FALSE" dsp.ACASCREG = \ dsp.ALUMODEREG = \ dsp.AREG = \ dsp.BCASCREG = \ dsp.BREG = \ dsp.CARRYINSELREG = \ dsp.CREG = int(REG_IN or (REQUIRES_CASCADE and i > 0)) dsp.ADREG = 0 dsp.CARRYINSELREG = 0 dsp.DREG = 0 dsp.INMODEREG = 0 dsp.MREG = 0 dsp.OPMODEREG = 1 dsp.PREG = int(self.REG_OUT) dsp.USE_MULT = "NONE" dsp.USE_SIMD = "ONE48" dsps.append(dsp) self.dsp = dsps carry = 0 carry_column = 0 dsp_outputs = [] din = self.data_in dout = self.data_out dsp_clock_enables = [] dsp_inputs = [] for i, dsp in enumerate(dsps): offset = i * 48 width = min(48, self.DATA_WIDTH - offset) if width <= 18: a = 0 b = din.b[offset + width:offset] else: a = din.b[offset + width:18 + offset] b = din.b[offset + 18:offset] c = din.a[offset + width:offset] dsp_inputs.append((a, b, c)) # register to wait 1 clock before 1st operation to load operation and operand selection registers mode_preload = self._reg("mode_preload", def_val=1) mode_preload(0) if REQUIRES_CASCADE: # cascade is required because carry out signal has register and thus the input data # to a next DSP has to be delayed assert self.REG_OUT stage_cnt = int(self.REG_IN) + int(self.REG_OUT) + ceil(self.DATA_WIDTH / 48) - 1 clock_enables, _, in_ready, out_valid = generate_handshake_pipe_cntrl( self, stage_cnt, "pipe_reg", din.vld & ~mode_preload, dout.rd) delayed_dsp_inputs = [] for i, (dsp, (a, b, c)) in enumerate(zip(dsps, dsp_inputs)): if self.REG_IN: input_ces = clock_enables[:i] ce_0 = clock_enables[i] ce_1 = clock_enables[i + 1] else: if i == 0: # :note: only first does not have in registers ce_0 = 1 ce_1 = clock_enables[i] input_ces = [] else: ce_0 = clock_enables[i - 1] ce_1 = clock_enables[i] input_ces = clock_enables[:i - 1] # because the last register is a part of DPS dsp_clock_enables.append((ce_0, ce_1)) a_delayed = self.postpone_val(a, input_ces, f"a{i:d}_") b_delayed = self.postpone_val(b, input_ces, f"b{i:d}_") c_delayed = self.postpone_val(c, input_ces, f"c{i:d}_") delayed_dsp_inputs.append((a_delayed, b_delayed, c_delayed)) dsp_inputs = delayed_dsp_inputs else: stage_cnt = int(self.REG_IN) + int(self.REG_OUT) clock_enables, _, in_ready, out_valid = generate_handshake_pipe_cntrl( self, stage_cnt, "pipe_reg", din.vld & ~mode_preload, dout.rd) if self.REG_IN: ce_0 = clock_enables[0] else: ce_0 = 1 if self.REG_OUT: if self.REG_IN: ce_1 = clock_enables[1] else: ce_1 = clock_enables[0] else: ce_1 = 1 for i, dsp in enumerate(dsps): dsp_clock_enables.append((mode_preload | ce_0, mode_preload | ce_1)) dout.vld(out_valid & ~mode_preload) din.rd(in_ready & ~mode_preload) for i, (dsp, (ce_0, ce_1), (a, b, c)) in enumerate(zip(dsps, dsp_clock_enables, dsp_inputs)): offset = i * 48 width = min(48, self.DATA_WIDTH - offset) dsp.CLK(self.clk) dsp.ACIN(0) dsp.BCIN(0) dsp.MULTSIGNIN(1) dsp.PCIN(0) dsp.CEINMODE(1) self.set_mode(dsp) dsp.RSTINMODE(0) if i == 0: dsp.CARRYINSEL(CARRYIN_SEL.CARRYIN.value) dsp.CARRYIN(carry) dsp.CARRYCASCIN(carry_column) carry = dsp.CARRYOUT[3] carry_column = dsp.CARRYCASCOUT else: dsp.CARRYINSEL(CARRYIN_SEL.CARRYCASCIN.value) dsp.CARRYIN(0) dsp.CARRYCASCIN(carry_column) carry_column = dsp.CARRYCASCOUT if width <= 18: assert isinstance(a, int) and a == 0, a dsp.A(a) dsp.B(fitTo(b, dsp.B, shrink=False)) dsp.C(fitTo(c, dsp.C, shrink=False)) elif width < 48: dsp.A(fitTo(a, dsp.A, shrink=False)) dsp.B(b) dsp.C(fitTo(c, dsp.C, shrink=False)) else: dsp.A(a) dsp.B(b) dsp.C(c) dsp.D(0) dsp_outputs.append(dsp.P[width:]) for _ce in [ dsp.CEA1, dsp.CEA2, dsp.CEALUMODE, dsp.CEB2, dsp.CEB1, dsp.CEC, dsp.CECARRYIN, dsp.CECTRL, ]: _ce(ce_0) for _ce in [dsp.CEAD, dsp.CED, dsp.CEM]: _ce(1) dsp.CEP(ce_1) for _rst in [dsp.RSTA, dsp.RSTALLCARRYIN, dsp.RSTALUMODE, dsp.RSTB, dsp.RSTC, dsp.RSTCTRL, dsp.RSTD, dsp.RSTM, dsp.RSTP,]: _rst(~self.rst_n) if REQUIRES_CASCADE: delayed_dsp_outputs = [] max_delay = len(dsp_outputs) - 1 for i, out in enumerate(dsp_outputs): delay = max_delay - i if delay > 0: # select n last ces = clock_enables[-delay:] delayed_out = self.postpone_val(out, ces, f"out_delay_{i:d}") else: delayed_out = out delayed_dsp_outputs.append(delayed_out) dsp_outputs = delayed_dsp_outputs dout.data(Concat(*reversed(dsp_outputs)))