def _impl(self): propagateClkRstn(self) addr_crossbar = self.addr_crossbar data_crossbar = self.data_crossbar b_crossbar = self.b_crossbar master_addr_channels = HObjList([m.aw for m in self.s]) slave_addr_channels = HObjList([s.aw for s in self.m]) addr_crossbar.s(master_addr_channels) slave_addr_channels(addr_crossbar.m) master_w_channels = HObjList([m.w for m in self.s]) data_crossbar.dataIn(master_w_channels) slave_w_channels = HObjList([s.w for s in self.m]) slave_w_channels(data_crossbar.dataOut) master_b_channels = HObjList([m.b for m in self.s]) master_b_channels(b_crossbar.dataOut) slave_b_channels = HObjList([s.b for s in self.m]) b_crossbar.dataIn(slave_b_channels) for addr_crossbar_s_index_out, f_w, f_b in zip( addr_crossbar.order_s_index_for_m_data_out, self.order_s_index_for_m_data, self.order_s_index_for_m_b): if f_w is None: assert f_b is None continue HsBuilder(self, addr_crossbar_s_index_out)\ .split_copy_to(f_w.dataIn, f_b.dataIn) for f_w, f_b, data_dout_for_din, b_din_for_dout in zip( self.order_s_index_for_m_data, self.order_s_index_for_m_b, data_crossbar.order_dout_index_for_din_in, b_crossbar.order_din_index_for_dout_in): if f_w is None: assert f_b is None continue data_dout_for_din(f_w.dataOut) b_din_for_dout(f_b.dataOut) for addr_crossbar_m_index_out, f_w, f_b in zip( addr_crossbar.order_m_index_for_s_data_out, self.order_m_index_for_s_data, self.order_m_index_for_s_b): if f_w is None: assert f_b is None assert addr_crossbar_m_index_out is None continue HsBuilder(self, addr_crossbar_m_index_out)\ .split_copy_to(f_w.dataIn, f_b.dataIn) for f_w, f_b, data_din_for_dout, b_dout_for_din in zip( self.order_m_index_for_s_data, self.order_m_index_for_s_b, data_crossbar.order_din_index_for_dout_in, b_crossbar.order_dout_index_for_din_in): if f_w is None: assert f_b is None assert data_din_for_dout is None continue data_din_for_dout(f_w.dataOut) b_dout_for_din(f_b.dataOut)
def _impl(self): # instanciate builder b = HsBuilder(self, self.a) # HsBuilder is derived from AbstractStreamBuilder and implements # it can: # * instantiate and connect: # * fifos, registers, delays # * frame builders, frame parsers # * data width resizers # * various stream join/split components # * clock domain crossing # for most of stream interfaces like AvalonST, LocalLink ... # there is builder with same program interface # instanciate handshaked register (default buff items=1) # and connect it to end (which is self.a) b.buff() # instantiate fifo with 16 items and connect it to output of register # from previous step b.buff(items=16) # instantiate register with latency=2 and delay=1 and connect it # to output of fifo from previous step b.buff(latency=2, delay=1) # b.end is now output of register from previous step, # connect it to uptput self.b(b.end)
def _impl(self): dma = AxiVirtualDma(self.axi_m, alignas=self.ALIGNAS) rxGet, rxR = dma.read(frameHeader) txSet, txW, wAck = dma.write(frameHeader) dma.build() # send address to an engine which reads and writes the packet header HsBuilder(self, self.packetAddr)\ .split_copy_to(rxGet, txSet) # ignore write ack wAck.rd(1) def withFifo(interface): return HsBuilder(self, interface)\ .buff(items=4)\ .end # swap dst/src in IP and Ethernet MAC, use fifo to compensate for # a diferent arrival times of the data txW.eth.dst(withFifo(rxR.eth.src)) txW.eth.src(withFifo(rxR.eth.dst)) txW.ipv4.dst(withFifo(rxR.ipv4.src)) txW.ipv4.src(withFifo(rxR.ipv4.dst)) propagateClkRstn(self)
def connect_r(self, s_r: RamHsR, axi: Axi4, r_cntr: RtlSignal, CNTR_MAX: int, in_axi_t: Union[HStruct, HUnion]): self.addr_defaults(axi.ar) # rm id from r channel as it is not currently supported in frame parser r_tmp = AxiStream() r_tmp.USE_STRB = False r_tmp.DATA_WIDTH = axi.r.DATA_WIDTH self.r_tmp = r_tmp r_tmp(axi.r, exclude=( axi.r.id, axi.r.resp, )) r_data = AxiSBuilder(self, r_tmp)\ .parse(in_axi_t).data if self.data_words_in_axi_word <= 1: self.connect_addr(s_r.addr.data, axi.ar.addr) s_r.data.data(r_data.data[s_r.DATA_WIDTH:]) ar_sn = StreamNode([s_r.addr], [axi.ar]) r_sn = StreamNode([r_data], [s_r.data]) else: addr, sub_addr = self.split_subaddr(s_r.addr.data) self.connect_addr(addr, axi.ar.addr) sel = HsBuilder(self, r_data._select, master_to_slave=False)\ .buff(self.MAX_TRANS_OVERLAP).end sel.data(sub_addr) data_items = [ getattr(r_data, f"data{i:d}").data for i in range(self.data_words_in_axi_word) ] r_data_selected = HsBuilder.join_prioritized(self, data_items).end s_r.data.data(r_data_selected.data) ar_sn = StreamNode([s_r.addr], [axi.ar, sel]) r_sn = StreamNode([r_data_selected], [s_r.data]) ar_sn.sync(r_cntr != CNTR_MAX) r_sn.sync() r_en = r_sn.ack() If(axi.ar.ready & axi.ar.valid, If(~r_en, r_cntr(r_cntr + 1))).Elif(r_en, r_cntr(r_cntr - 1))
def _impl(self): req = self.wDatapump.req w = self.wDatapump.w ack = self.wDatapump.ack # multi frame ackPropageteInfo = HandshakedFifo(Handshaked) ackPropageteInfo.DATA_WIDTH.set(1) ackPropageteInfo.DEPTH.set(self.MAX_OVERLAP) self.ackPropageteInfo = ackPropageteInfo propagateClkRstn(self) if self.WRITE_ACK: _set = self.set else: _set = HsBuilder(self, self.set).buff().end req.id(self.ID) req.rem(0) def propagateRequests(frame, indx): ack = StreamNode(slaves=[req, ackPropageteInfo.dataIn]).ack() statements = [req.addr(_set.data + frame.startBitAddr // 8), req.len(frame.getWordCnt() - 1), StreamNode(slaves=[req, ackPropageteInfo.dataIn], ).sync(_set.vld) ] if indx != 0: prop = SKIP else: prop = PROPAGATE statements.append(ackPropageteInfo.dataIn.data(prop)) isLastFrame = indx == len(self._frames) - 1 if isLastFrame: statements.append(_set.rd(ack)) else: statements.append(_set.rd(0)) return statements, ack & _set.vld StaticForEach(self, self._frames, propagateRequests) # connect write channel w(self.frameAssember.dataOut) # propagate ack StreamNode(masters=[ack, ackPropageteInfo.dataOut], slaves=[self.writeAck], skipWhen={ self.writeAck: ackPropageteInfo.dataOut.data._eq(PROPAGATE) }).sync() # connect fields to assembler for _, transTmpl in self._tmpl.walkFlatten(): f = transTmpl.origin intf = self.frameAssember.dataIn._fieldsToInterfaces[f] intf(self.dataIn._fieldsToInterfaces[f])
def _impl(self): req = self.wDatapump.req w = self.wDatapump.w ack = self.wDatapump.ack # multi frame if self.MAX_OVERLAP > 1: ackPropageteInfo = HandshakedFifo(Handshaked) ackPropageteInfo.DEPTH = self.MAX_OVERLAP else: ackPropageteInfo = HandshakedReg(Handshaked) ackPropageteInfo.DATA_WIDTH = 1 self.ackPropageteInfo = ackPropageteInfo if self.WRITE_ACK: _set = self.set else: _set = HsBuilder(self, self.set).buff().end if self.ID_WIDTH: req.id(self.ID) def propagateRequest(frame, indx): inNode = StreamNode(slaves=[req, ackPropageteInfo.dataIn]) ack = inNode.ack() isLastFrame = indx == len(self._frames) - 1 statements = [ req.addr(_set.data + frame.startBitAddr // 8), req.len(frame.getWordCnt() - 1), self.driveReqRem( req, frame.parts[-1].endOfPart - frame.startBitAddr), ackPropageteInfo.dataIn.data(SKIP if indx != 0 else PROPAGATE), inNode.sync(_set.vld), _set.rd(ack if isLastFrame else 0), ] return statements, ack & _set.vld StaticForEach(self, self._frames, propagateRequest) # connect write channel w(self.frameAssember.dataOut) # propagate ack StreamNode(masters=[ack, ackPropageteInfo.dataOut], slaves=[self.writeAck], skipWhen={ self.writeAck: ackPropageteInfo.dataOut.data._eq(PROPAGATE) }).sync() # connect fields to assembler for _, transTmpl in self._tmpl.walkFlatten(): f = transTmpl.getFieldPath() intf = self.frameAssember.dataIn._fieldsToInterfaces[f] intf(self.dataIn._fieldsToInterfaces[f]) propagateClkRstn(self)
def _impl(self): """ Read operation: * Use index to lookup in tag memory * if tag matches return cacheline else dispatch read request (the transaction is dispatched with original id, uppon data receive the transaction is passed to master without any synchronisation with the cache ) Write operation: * Use index to lookup in tag memory * If tag matches and the cacheline is not beeing replaced update the data in data array. * If tag is not found in corresponding set select a victim and read it from data array, flush it and write back cacheline to array and update tag """ # transaction type usind in data array memory access pipeline data_array_r, data_array_w = self.data_array.port ar_tagRes, aw_tagRes = self.tag_array.lookupRes with self._paramsShared(): data_arr_read = self.data_arr_read = Axi4_r() data_arr_read_req = IndexWayHs() data_arr_read_req.INDEX_WIDTH = self.INDEX_W self.data_arr_read_req = data_arr_read_req self.connect_tag_lookup() # addd a register with backup register for poential overflow # we need this as we need to check if we can store data in advance. # this is because we need a higher priority for flushing # in order to avoid deadlock. _data_arr_read = AxiSBuilder(self, data_arr_read)\ .buff(1, latency=(1, 2))\ .end _data_arr_read_req = HsBuilder(self, data_arr_read_req)\ .buff(1, latency=(1, 2))\ .end self.read_handler(self.lru_array.incr[0], ar_tagRes, data_arr_read_req, _data_arr_read) self.data_array_io( self.lru_array.incr[1], aw_tagRes, self.lru_array.victim_req, self.lru_array.victim_data, _data_arr_read_req, data_arr_read, data_array_r, data_array_w, self.tag_array.update[0], ) propagateClkRstn(self)
def reqHandler(self, dpReq, orderFifoIn): # join with roundrobin on requests form drivers and selected index is stored into orderFifo # because it is just proxy driversReq = list(map(lambda d: d.req, self.drivers)) b = HsBuilder.join_fair(self, driversReq, exportSelected=True) req = b.end reqJoin = b.lastComp StreamNode(masters=[req], slaves=[dpReq, orderFifoIn]).sync() connect(req, dpReq, exclude=[dpReq.vld, dpReq.rd]) orderFifoIn.data(oneHotToBin(self, reqJoin.selectedOneHot.data))
def _impl(self): self.tables_tmp = HObjList([ HashTableIntf()._updateParamsFrom(t.io) for t in self.table_cores ]) for t_io, t in zip(self.tables_tmp, self.table_cores): t.io(t_io, exclude={t.io.lookupRes}) t_io.lookupRes( HsBuilder(self, t.io.lookupRes).buff(latency=(1, 2)).end) self.tables = list(self.tables_tmp) CuckooHashTable._impl(self)
def _impl(self): """ * read on 'en' faling edge, write on 'en' rising edge * 'en' max frequency = LCD_FREQ / 10 * rs has to be set at least 1 clk (LCD_FREQ) before rising edge of 'en' """ LCD_DW = self.LCD_DATA_WIDTH assert LCD_DW in (4, 8), LCD_DW cmd_timer_rst = self._sig("cmd_timer_rst") HALF_LCD_PERIOD = ceil(self.FREQ / (self.LCD_FREQ * 2)) LCD_CLK_PER = 2 * HALF_LCD_PERIOD lcd_clk_en, = ClkBuilder(self, self.clk).timers([ ("lcd_clk_en", LCD_CLK_PER), ]) delay_cmd_half_done, delay_cmd_done, delay_cmd_long_done =\ ClkBuilder(self, self.clk)\ .timers([ # used to signalize that the 'en' should be asserted low ("delay_cmd_half_done", Hd44780Intf.DELAY_CMD // 2), # used to signalize that the processing of command is completed ("delay_cmd_done", Hd44780Intf.DELAY_CMD), # used to signalize that the long command (return home, etc.) is completed ("delay_cmd_long_done", Hd44780Intf.DELAY_RETURN_HOME) ], enableSig=lcd_clk_en, rstSig=cmd_timer_rst ) data_in_tmp = Hd44780CmdIntf() data_in_tmp.DATA_WIDTH = self.LCD_DATA_WIDTH self.data_in_tmp = data_in_tmp self._io_core(data_in_tmp, cmd_timer_rst, lcd_clk_en, delay_cmd_half_done, delay_cmd_done, delay_cmd_long_done) INIT_SEQUENCE = [ Hd44780Intf.CMD_FUNCTION_SET( Hd44780Intf.DATA_LEN_8b if LCD_DW == 8 else Hd44780Intf.DATA_LEN_4b, self.LCD_ROWS - 1, Hd44780Intf.FONT_5x8), Hd44780Intf.CMD_DISPLAY_CONTROL(1, 0, 0), Hd44780Intf.CMD_ENTRY_MODE_SET(1, 1), ] init_seq = Hd44780CmdIntfBurst() init_seq.DATA_WIDTH = self.LCD_DATA_WIDTH init_seq.DATA = tuple( (Hd44780Intf.RS_CONTROL, Hd44780Intf.RW_WRITE, 0, d) for d in INIT_SEQUENCE ) self.init_seq = init_seq propagateClkRstn(self) data_in = self._translate_data_in(self.dataIn) data_in_tmp(HsBuilder.join_prioritized(self, [init_seq.dataOut, data_in]).end)
def _impl(self): m = self._Mi32_addr_to_Mi32AddrHs(self.s, "addr_tmp") m = HsBuilder(self, m).buff(items=self.ADDR_BUFF_DEPTH).end self._connect_Mi32AddrHs_to_Mi32(m, self.m) data_t = HStruct( (self.m.drd._dtype, "drd"), # read data (BIT, "drdy"), # read data valid ) m = (self.m.drd, self.m.drdy) for i in range(self.DATA_BUFF_DEPTH): reg = self._reg(f"read_data_reg{i:d}", data_t, def_val={"drdy": 0}) reg.drd(m[0]) reg.drdy(m[1]) m = (reg.drd, reg.drdy) self.s.drd(m[0]) self.s.drdy(m[1])
def _impl(self): propagateClkRstn(self) req = self.rDatapump.req req.rem(0) if self.READ_ACK: get = self.get else: get = HsBuilder(self, self.get).buff().end def f(frame, indx): s = [ req.addr(get.data + frame.startBitAddr // 8), req.len(frame.getWordCnt() - 1), req.vld(get.vld) ] isLastFrame = indx == len(self._frames) - 1 if isLastFrame: rd = req.rd else: rd = 0 s.append(get.rd(rd)) ack = StreamNode(masters=[get], slaves=[self.rDatapump.req]).ack() return s, ack StaticForEach(self, self._frames, f) r = self.rDatapump.r data_sig_to_exclude = [] req.id(self.ID) if hasattr(r, "id"): data_sig_to_exclude.append(r.id) if hasattr(r, "strb"): data_sig_to_exclude.append(r.strb) connect(r, self.parser.dataIn, exclude=data_sig_to_exclude) for _, field in self._tmpl.walkFlatten(): myIntf = self.dataOut._fieldsToInterfaces[field.origin] parserIntf = self.parser.dataOut._fieldsToInterfaces[field.origin] myIntf(parserIntf)
def _impl(self): propagateClkRstn(self) req = self.rDatapump.req if self.READ_ACK: get = self.get else: get = HsBuilder(self, self.get).buff().end def propagateRequest(frame, indx): isLastFrame = indx == len(self._frames) - 1 s = [ req.addr(get.data + frame.startBitAddr // 8), req.len(frame.getWordCnt() - 1), self.driveReqRem(req, frame.parts[-1].endOfPart - frame.startBitAddr), req.vld(get.vld), get.rd(req.rd if isLastFrame else 0) ] ack = StreamNode(masters=[get], slaves=[self.rDatapump.req]).ack() return s, ack StaticForEach(self, self._frames, propagateRequest) r = self.rDatapump.r data_sig_to_exclude = [] if self.ID_WIDTH: req.id(self.ID) if hasattr(r, "id"): data_sig_to_exclude.append(r.id) if hasattr(r, "strb"): data_sig_to_exclude.append(r.strb) self.parser.dataIn(r, exclude=data_sig_to_exclude) for _, field in self._tmpl.walkFlatten(): p = field.getFieldPath() myIntf = self.dataOut._fieldsToInterfaces[p] parserIntf = self.parser.dataOut._fieldsToInterfaces[p] myIntf(parserIntf)
def connectChoicesOfFrameParts(self, hsNondes: ListOfOutNodeInfos, part: ChoicesOfFrameParts, en: Union[RtlSignal, bool], exclusiveEn: Optional[RtlSignal], wordIndex: Optional[RtlSignal], currentWordIndex: int): tToIntf = self.dataOut._fieldsToInterfaces parentIntf = tToIntf[part.origin.parent.getFieldPath()] try: sel = self._tmpRegsForSelect[parentIntf] except KeyError: sel = HsBuilder(self.parent, parentIntf._select).buff().end self._tmpRegsForSelect[parentIntf] = sel unionGroup = ExclusieveListOfHsNodes(sel) # for unions for choice in part: # connect data signals of choices and collect info about # streams intfOfChoice = tToIntf[choice.tmpl.getFieldPath()] selIndex, isSelected, isSelectValid = self.choiceIsSelected( intfOfChoice) _exclusiveEn = isSelectValid & isSelected & exclusiveEn unionMemberPart = ListOfOutNodeInfos() for p in choice: self.connectPart(unionMemberPart, p, en, _exclusiveEn, wordIndex, currentWordIndex) unionGroup.append(selIndex, unionMemberPart) hsNondes.append(unionGroup) if wordIndex is not None: en = en & wordIndex._eq(currentWordIndex) if part.isLastPart(): # synchronization of reading from _select register for unions selNode = InNodeInfo(sel, en) else: selNode = InNodeReadOnlyInfo(sel, en) hsNondes.append(selNode)
def _impl(self): propagateClkRstn(self) connectDp(self, self.rxPacketLoader, self.rxDataPump, self.axi_m) connectDp(self, self.txPacketUpdater, self.txDataPump, self.axi_m) self.txPacketUpdater.writeAck.rd(1) rxR = self.rxPacketLoader.dataOut txW = self.txPacketUpdater.dataIn def withFifo(interface): return HsBuilder(self, interface)\ .buff(items=4)\ .end txW.eth.dst(withFifo(rxR.eth.src)) txW.eth.src(withFifo(rxR.eth.dst)) txW.ipv4.dst(withFifo(rxR.ipv4.src)) txW.ipv4.src(withFifo(rxR.ipv4.dst)) HsBuilder(self, self.packetAddr).split_copy_to(self.rxPacketLoader.get, self.txPacketUpdater.set)
def _impl(self): # Builder is class which simplifies building of datapaths # and keeps components which are used which this interface together a = HsBuilder(self, self.a, name="builderFromA") # .end = last interface in datapath # .lastComp = last component in datapath # ... take a look at AbstractStreamBuilder # register a.buff(items=1, latency=1, delay=0) # fifo a.buff(items=4, latency=1, delay=0) # reg + fifo a.buff(items=5, latency=2, delay=0) # reg wit delay (breaks combinational loop of ready signal) a.buff(items=1, latency=2, delay=1) # create 3 identhical streams and connect them to a_0-3 # there is also only split_copy which only create split component # but left output unconnected a.split_copy_to(self.a_0, self.a_1, self.a_2) # round robin like split, data is send only to one of output ports # and there is cycling flag which selects priority for each output # to assert uniform load b = HsBuilder(self, self.b)\ .split_fair_to(self.b_0, self.b_1, self.b_2, exportSelected=True) self.b_selected(b.lastComp.selectedOneHot) # send data output interface which is ready and has higher priority # (=lowest index) HsBuilder(self, self.c).split_prioritized_to(self.c_0, self.c_1) # explicitly select output HsBuilder(self, self.d)\ .split_select_to([1, 2, 1, 0], self.d_0, self.d_1, self.d_2) # explicitly select output HsBuilder(self, self.e)\ .split_select_to(self.e_select, self.e_0, self.e_1, self.e_2)
def withFifo(interface): return HsBuilder(self, interface)\ .buff(items=4)\ .end
def connectPart(self, hsNondes: list, part: Union[TransPart, ChoicesOfFrameParts], en: Union[RtlSignal, bool], exclusiveEn: Optional[RtlSignal]=hBit(1)): """ Create datamux for one word in main fsm and colect metainformations for handshake logic :param hsNondes: list of nodes of handshaked logic """ busVld = self.dataIn.valid tToIntf = self.dataOut._fieldsToInterfaces if isinstance(part, ChoicesOfFrameParts): parentIntf = tToIntf[part.origin.parent.origin] try: sel = self._tmpRegsForSelect[parentIntf] except KeyError: sel = HsBuilder(self, parentIntf._select).buff().end self._tmpRegsForSelect[parentIntf] = sel unionGroup = ExclusieveListOfHsNodes(sel) # for unions for choice in part: # connect data signals of choices and collect info about # streams intfOfChoice = tToIntf[choice.tmpl.origin] selIndex, isSelected, isSelectValid = self.choiceIsSelected( intfOfChoice) _exclusiveEn = isSelectValid & isSelected & exclusiveEn unionMemberPart = ListOfOutNodeInfos() for p in choice: self.connectPart(unionMemberPart, p, en, _exclusiveEn) unionGroup.append(selIndex, unionMemberPart) hsNondes.append(unionGroup) if part.isLastPart(): # synchronization of reading from _select register for unions selNode = InNodeInfo(sel, en) else: selNode = InNodeReadOnlyInfo(sel, en) hsNondes.append(selNode) return if part.isPadding: return fPartSig = self.getInDataSignal(part) fieldInfo = part.tmpl.origin try: signalsOfParts = self._signalsOfParts[part.tmpl] except KeyError: signalsOfParts = [] self._signalsOfParts[part.tmpl] = signalsOfParts if part.isLastPart(): # connect all parts in this group to output stream signalsOfParts.append(fPartSig) intf = self.dataOut._fieldsToInterfaces[fieldInfo] intf.data(self.byteOrderCare( Concat( *reversed(signalsOfParts) )) ) on = OutNodeInfo(self, intf, en, exclusiveEn) hsNondes.append(on) else: dataVld = busVld & en & exclusiveEn # part is in some word as last part, we have to store its value to register # until the last part arrive fPartReg = self._reg("%s_part_%d" % (fieldInfo.name, len(signalsOfParts)), fPartSig._dtype) If(dataVld, fPartReg(fPartSig) ) signalsOfParts.append(fPartReg)
def speculative_read_handler(self): """ Connect the speculative_read port to internal storages of the :class:`AxiWriteAggregator` We need to handle several cases: 1. the data is currently in tmp register 2. the data was in tmp register and now is in data memory 3. the data is in data memory 4. the data was in data memory and now it is deallocated 5. the data was not found anywhere Handling of speculative read has following stages: 1. search input register and main address CAM for data 2. optionaly load the data from ram 3. send data to speculative_read_data and set resp to error if was not found it may also happen that the data was flushed in the mean time .. figure:: ./_static/AxiStoreQueueWritePropagating_speculativeRead.png :note: speculative read never block the write channel and thus data may be invalid if the speculative read data is stalled. This should be handled in master of speculative read port (Other component which is using this component). """ sra = self.speculative_read_addr # CLOCK_PERIOD 0 ooo_fifo = self.ooo_fifo ooo_fifo.read_lookup.data(sra.addr[:self.CACHE_LINE_OFFSET_BITS]) w_in_reg = self.w_in_reg.dataOut w_in_reg_tmp = HObjList( HandshakedReg(AxiWriteAggregatorWriteTmpIntf) for _ in range(2)) for r in w_in_reg_tmp: r._updateParamsFrom(w_in_reg) r.ID_WIDTH = self.ID_WIDTH self.w_in_reg_tmp = w_in_reg_tmp w_i = w_in_reg_tmp[0].dataIn w_i.orig_request_addr(sra.addr[:self.CACHE_LINE_OFFSET_BITS]) w_i.orig_request_addr_eq(w_in_reg.addr._eq(w_i.orig_request_addr)) w_i.orig_request_id(sra.id) w_i.orig_request_valid(sra.vld) w_i.addr(w_in_reg.addr) w_i.data(w_in_reg.data) w_i.valid(w_in_reg.vld) StreamNode( [sra], [ooo_fifo.read_lookup, w_i], skipWhen={ sra: ~sra.vld }, # flush the pipeline if no request ).sync() # CLK_PERIOD 1 read_lookup_res = HsBuilder(self, ooo_fifo.read_lookup_res).buff(1).end StreamNode([read_lookup_res, w_in_reg_tmp[0].dataOut], [w_in_reg_tmp[1].dataIn]).sync() w_in_reg_tmp[1].dataIn( w_in_reg_tmp[0].dataOut, exclude=[w_in_reg_tmp[1].dataIn.vld, w_in_reg_tmp[1].dataIn.rd]) in_ram_flag = rename_signal(self, read_lookup_res.data & ooo_fifo.item_valid, "in_ram_flag") found_in_ram_flag = self._reg("found_in_ram_flag", def_val=0) If(read_lookup_res.vld & read_lookup_res.rd, found_in_ram_flag(in_ram_flag != 0)) ram_r = self.data_ram.port[2] ram_r.en.vld(found_in_ram_flag.next) ram_r.addr(oneHotToBin(self, in_ram_flag, "in_ram_index")) # CLK_PERIOD 2 srd = self.speculative_read_data w_in_reg_tmp_o = w_in_reg_tmp[1].dataOut StreamNode( [w_in_reg_tmp_o], [srd], # filter out pipeline flushes extraConds={ srd: w_in_reg_tmp_o.orig_request_valid }, skipWhen={ srd: ~w_in_reg_tmp_o.orig_request_valid }, ).sync() # read from in_tmp req has to be postponed so we can potentially load the data from ram first found_in_actual_w_in_reg = rename_signal( self, w_in_reg.vld & w_in_reg.addr._eq(w_in_reg_tmp_o.orig_request_addr), "spec_read_found_in_actual_w_in_reg") w_in_reg_tmp_1_o = w_in_reg_tmp[0].dataOut found_in_w_in_reg_1 = rename_signal( self, w_in_reg_tmp_1_o.vld & w_in_reg_tmp_1_o.valid & w_in_reg_tmp_1_o.addr._eq(w_in_reg_tmp_o.orig_request_addr), "spec_read_found_in_w_in_reg_1") found_in_write_tmp_reg_2 = rename_signal( self, w_in_reg_tmp_o.vld & w_in_reg_tmp_o.valid & w_in_reg_tmp_o.orig_request_addr_eq, "spec_read_found_in_write_tmp_reg_2") srd.id(w_in_reg_tmp_o.orig_request_id) If( found_in_actual_w_in_reg, # found in tmp register just now srd.data(w_in_reg.data), srd.resp(RESP_OKAY), srd.last(1), ).Elif( found_in_w_in_reg_1, # found in tmp register in clock cycle -2 srd.data(w_in_reg_tmp_1_o.data), srd.resp(RESP_OKAY), srd.last(1), ).Elif( found_in_write_tmp_reg_2, # found in tmp register in clock cycle -2 srd.data(w_in_reg_tmp_o.data), srd.resp(RESP_OKAY), srd.last(1), ).Elif( found_in_ram_flag, # found in write data memory srd.data(ram_r.dout), srd.resp(RESP_OKAY), srd.last(1), ).Else( # not found anywhere srd.data(None), srd.resp(RESP_EXOKAY), srd.last(1), )
def connectPartsOfWord(self, wordData_out: RtlSignal, tPart: Union[TransPart, ChoicesOfFrameParts], inPorts_out: List[Union[Handshaked, StreamNode]], lastInPorts_out: List[Union[Handshaked, StreamNode]])\ ->Tuple[Optional[RtlSignal], Optional[RtlSignal]]: """ Connect transactions parts to signal for word of output stream :param wordData_out: signal for word of output stream :param tPart: instance of TransPart or ChoicesOfFrameParts to connect :param inPorts_out: input interfaces to this transaction part :param lastInPorts_out: input interfaces for last parts of transactions :return: tuple (strb, keep) if strb/keep driven by input stream, else (None, None) """ tToIntf = self.dataIn._fieldsToInterfaces if isinstance(tPart, ChoicesOfFrameParts): # connect parts of union to output signal high, low = tPart.getBusWordBitRange() parentIntf = tToIntf[tPart.origin.parent.getFieldPath()] if parentIntf not in self._tmpRegsForSelect.keys(): sel = HsBuilder(self, parentIntf._select).buff().end self._tmpRegsForSelect[parentIntf] = sel inPortGroups = ExclusiveStreamGroups() lastInPortsGroups = ExclusiveStreamGroups() w = tPart.bit_length() # tuples (cond, part of data mux for dataOut) unionChoices = [] sk_stashes = [] # for all choices in union for choice in tPart: tmp = self._sig("union_tmp_", Bits(w)) intfOfChoice = tToIntf[choice.tmpl.getFieldPath()] _, _isSelected, isSelectValid = \ AxiS_frameParserFieldConnector.choiceIsSelected(self, intfOfChoice) unionChoices.append((_isSelected, wordData_out[high:low](tmp))) isSelected = _isSelected & isSelectValid # build meta for handshake logic sync inPortsNode = StreamNode() inPortGroups.append((isSelected, inPortsNode)) lastPortsNode = StreamNode() lastInPortsGroups.append((isSelected, lastPortsNode)) sk_stash = StrbKeepStash() # walk all parts in union choice start = tPart.startOfPart for choicePart in choice: if start != choicePart.startOfPart: # add padding because there is a hole in data _w = choicePart.startOfPart - start assert _w > 0, _w sk_stash.push((_w, 0), (_w, 0)) _strb, _keep = self.connectPartsOfWord( tmp, choicePart, inPortsNode.masters, lastPortsNode.masters) sk_stash.push(_strb, _keep) start = choicePart.endOfPart if start != tPart.endOfPart: # add padding because there is a hole after _w = tPart.endOfPart - start assert _w > 0, _w sk_stash.push((_w, 0), (_w, 0)) # store isSelected sig and strb/keep value for later strb/keep resolving sk_stashes.append((isSelected, sk_stash)) # generate data out mux SwitchLogic(unionChoices, default=wordData_out(None)) inPorts_out.append(inPortGroups) lastInPorts_out.append(lastInPortsGroups) # resolve strb/keep from strb/keep and isSelected of union members if w % 8 != 0: raise NotImplementedError(w) strb, keep = reduce_conditional_StrbKeepStashes(sk_stashes) else: # connect parts of fields to output signal high, low = tPart.getBusWordBitRange() if tPart.isPadding: wordData_out[high:low](None) else: intf = tToIntf[tPart.tmpl.getFieldPath()] fhigh, flow = tPart.getFieldBitRange() wordData_out[high:low](self.byteOrderCare( intf.data)[fhigh:flow]) inPorts_out.append(intf) if tPart.isLastPart(): lastInPorts_out.append(intf) w = tPart.bit_length() strb = int(not tPart.isPadding) keep = int(not tPart.canBeRemoved) return ((w, strb), (w, keep))
def connectPartsOfWord(self, wordData_out: RtlSignal, tPart: Union[TransPart, ChoicesOfFrameParts, StreamOfFramePars], inPorts_out: List[Union[Handshaked, StreamNode]], lastInPorts_out: List[Union[Handshaked, StreamNode]]): """ Connect transactions parts to signal for word of output stream :param wordData_out: signal for word of output stream :param tPart: instance of TransPart or ChoicesOfFrameParts to connect :param inPorts_out: input interfaces to this transaction part :param lastInPorts_out: input interfaces for last parts of transactions """ tToIntf = self.dataIn._fieldsToInterfaces if isinstance(tPart, ChoicesOfFrameParts): # connnect parts of union to output signal w = tPart.bit_length() high, low = tPart.getBusWordBitRange() parentIntf = tToIntf[tPart.origin.parent.origin] if parentIntf not in self._tmpRegsForSelect.keys(): sel = HsBuilder(self, parentIntf._select).buff().end self._tmpRegsForSelect[parentIntf] = sel inPortGroups = ExclusiveStreamGroups() lastInPortsGroups = ExclusiveStreamGroups() # tuples (cond, part of data mux for dataOut) unionChoices = [] # for all union choices for choice in tPart: tmp = self._sig("union_tmp_", Bits(w)) intfOfChoice = tToIntf[choice.tmpl.origin] _, isSelected, isSelectValid = AxiS_frameParser.choiceIsSelected( self, intfOfChoice) unionChoices.append((isSelected, wordData_out[high:low](tmp))) isSelected = isSelected & isSelectValid inPortsNode = StreamNode() lastPortsNode = StreamNode() inPortGroups.append((isSelected, inPortsNode)) lastInPortsGroups.append((isSelected, lastPortsNode)) # walk all parts in union choice for _tPart in choice: self.connectPartsOfWord(tmp, _tPart, inPortsNode.masters, lastPortsNode.masters) # generate data out mux SwitchLogic(unionChoices, default=wordData_out(None)) inPorts_out.append(inPortGroups) lastInPorts_out.append(lastInPortsGroups) elif isinstance(tPart, StreamOfFramePars): if len(tPart) != 1: raise NotImplementedError( "Structuralized streams not implemented yiet") p = tPart[0] intf = tToIntf[p.tmpl.origin] if int(intf.DATA_WIDTH) != wordData_out._dtype.bit_length(): raise NotImplementedError( "Dynamic resizing of streams not implemented yiet") if len(self._frames) > 1: raise NotImplementedError( "Dynamic splitting on frames not implemented yet") wordData_out(self.byteOrderCare(intf.data)) inPorts_out.append(intf) if tPart.isLastPart(): lastInPorts_out.append(intf) return intf.strb else: # connect parts of fields to output signal high, low = tPart.getBusWordBitRange() if tPart.isPadding: wordData_out[high:low](None) else: intf = tToIntf[tPart.tmpl.origin] fhigh, flow = tPart.getFieldBitRange() wordData_out[high:low](self.byteOrderCare( intf.data)[fhigh:flow]) inPorts_out.append(intf) if tPart.isLastPart(): lastInPorts_out.append(intf)