def _impl(self): if not self.IGNORE_DATA_LOSE: assert self.IN_FREQ <= self.OUT_FREQ in_clk_rst_n = self.dataIn_clk, self.dataIn_rst_n out_clk_rst_n = self.dataOut_clk, self.dataOut_rst_n in_vld, out_vld = (self.get_valid_signal(self.dataIn), self.get_valid_signal(self.dataOut)) b_cntrl = SignalCdcBuilder(in_vld, in_clk_rst_n, out_clk_rst_n, 0, name_prefix="") b_cntrl.add_in_reg() for _ in range(3): b_cntrl.add_out_reg() out_data_en = b_cntrl.path[-2] out_vld(b_cntrl.path[-1]) in_data = packIntf(self.dataIn, exclude=[in_vld]) b_data = SignalCdcBuilder(in_data, in_clk_rst_n, out_clk_rst_n, self.DATA_RESET_VAL, name_prefix="") b_data.add_in_reg() b_data.add_out_reg(en=out_data_en) connectPacked(b_data.path[-1], self.dataOut, exclude=[out_vld])
def _connect_fifo_in(self): rd = self.get_ready_signal vld = self.get_valid_signal din = self.dataIn fIn = self.fifo.dataIn wr_en = ~fIn.wait rd(din)(wr_en) if fIn.DATA_WIDTH > 0: fIn.data(packIntf(din, exclude=[vld(din), rd(din)])) fIn.en(vld(din) & wr_en)
def _connect_fifo_in(self): rd = self.get_ready_signal vld = self.get_valid_signal din = self.dataIn fIn = self.fifo.dataIn wr_en = ~fIn.wait rd(din)(wr_en) fIn.discard(self.dataIn_discard) fIn.commit(din.valid & din.last) fIn.data(packIntf(din, exclude=[vld(din), rd(din)])) fIn.en(vld(din) & wr_en)
def _impl(self, clks: Optional[Tuple[Clk, Clk]]=None): """ :clks: optional tuple (inClk, outClk) """ rd = self.getRd vld = self.getVld # connect clock and resets if clks is None: propagateClkRstn(self) inClk, outClk = (None, None) else: propagateRstn(self) inClk, outClk = clks self.fifo.dataIn_clk(inClk) self.fifo.dataOut_clk(outClk) # to fifo fIn = self.fifo.dataIn din = self.dataIn wr_en = ~fIn.wait rd(din)(wr_en) fIn.data(packIntf(din, exclude=[vld(din), rd(din)])) fIn.en(vld(din) & wr_en) # from fifo fOut = self.fifo.dataOut dout = self.dataOut out_vld = self._reg("out_vld", defVal=0, clk=outClk) vld(dout)(out_vld) connectPacked(fOut.data, dout, exclude=[vld(dout), rd(dout)]) fOut.en((rd(dout) | ~out_vld) & ~fOut.wait) If(rd(dout) | ~out_vld, out_vld(~fOut.wait) ) if self.EXPORT_SIZE: sizeTmp = self._sig("sizeTmp", self.size._dtype) connect(self.fifo.size, sizeTmp, fit=True) If(out_vld, self.size(sizeTmp + 1) ).Else( connect(self.fifo.size, self.size, fit=True) )
def _impl(self, clks: Optional[Tuple[Clk, Clk]] = None): """ :clks: optional tuple (inClk, outClk) """ rd = self.getRd vld = self.getVld # connect clock and resets if clks is None: propagateClkRstn(self) inClk, outClk = (None, None) else: propagateRstn(self) inClk, outClk = clks self.fifo.dataIn_clk(inClk) self.fifo.dataOut_clk(outClk) # to fifo fIn = self.fifo.dataIn din = self.dataIn wr_en = ~fIn.wait rd(din)(wr_en) fIn.data(packIntf(din, exclude=[vld(din), rd(din)])) fIn.en(vld(din) & wr_en) # from fifo fOut = self.fifo.dataOut dout = self.dataOut out_vld = self._reg("out_vld", defVal=0, clk=outClk) vld(dout)(out_vld) connectPacked(fOut.data, dout, exclude=[vld(dout), rd(dout)]) fOut.en((rd(dout) | ~out_vld) & ~fOut.wait) If(rd(dout) | ~out_vld, out_vld(~fOut.wait)) if self.EXPORT_SIZE: sizeTmp = self._sig("sizeTmp", self.size._dtype) connect(self.fifo.size, sizeTmp, fit=True) If(out_vld, self.size(sizeTmp + 1)).Else( connect(self.fifo.size, self.size, fit=True))
def ar_dispatch(self): """ Send read request on AXI and store transaction in to state array and ooo_fifo for later wake up """ ooo_fifo = self.ooo_fifo ar = self.m.ar din = self.dataIn assert din.addr._dtype.bit_length() == self.ADDR_WIDTH - self.ADDR_OFFSET_W, ( din.addr._dtype.bit_length(), self.ADDR_WIDTH, self.ADDR_OFFSET_W) dataIn_reg = HandshakedReg(din.__class__) dataIn_reg._updateParamsFrom(din) self.dataIn_reg = dataIn_reg StreamNode( [din], [dataIn_reg.dataIn, ooo_fifo.write_confirm] ).sync() dataIn_reg.dataIn(din, exclude=[din.rd, din.vld]) ar_node = StreamNode( [dataIn_reg.dataOut, ooo_fifo.read_execute], [ar] ) ar_node.sync() state_arr = self.state_array state_write = state_arr.port[0] state_write.en(ar_node.ack()) state_write.addr(ooo_fifo.read_execute.index) din_data = dataIn_reg.dataOut state_write.din(packIntf(din_data, exclude=[din_data.rd, din_data.vld])) ar.id(ooo_fifo.read_execute.index) ar.addr(Concat(din_data.addr, Bits(self.ADDR_OFFSET_W).from_py(0))) self._axi_addr_defaults(ar, 1)
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)