def get_port(self, udp_port, dw=8): if udp_port in self.users.keys(): raise ValueError("Port {0:#x} already assigned".format(udp_port)) user_port = LiteEthUDPUserPort(dw) internal_port = LiteEthUDPUserPort(8) if dw != 8: converter = stream.StrideConverter( eth_udp_user_description(user_port.dw), eth_udp_user_description(8)) self.submodules += converter self.comb += [ user_port.sink.connect(converter.sink), converter.source.connect(internal_port.sink) ] converter = stream.StrideConverter( eth_udp_user_description(8), eth_udp_user_description(user_port.dw)) self.submodules += converter self.comb += [ internal_port.source.connect(converter.sink), converter.source.connect(user_port.source) ] self.users[udp_port] = internal_port else: self.users[udp_port] = user_port return user_port
def __init__(self, with_converter=False): self.submodules.host = Host(64, root_id, endpoint_id, phy_debug=False, chipset_debug=False, chipset_split=True, chipset_reordering=True, host_debug=True) self.submodules.endpoint = LitePCIeEndpoint(self.host.phy, max_pending_requests=8, with_reordering=True) self.submodules.dma_reader = LitePCIeDMAReader(self.endpoint, self.endpoint.crossbar.get_master_port(read_only=True)) self.submodules.dma_writer = LitePCIeDMAWriter(self.endpoint, self.endpoint.crossbar.get_master_port(write_only=True)) if with_converter: self.submodules.up_converter = stream.StrideConverter(dma_layout(16), dma_layout(64)) self.submodules.down_converter = stream.StrideConverter(dma_layout(64), dma_layout(16)) self.submodules += stream.Pipeline(self.dma_reader, self.down_converter, self.up_converter, self.dma_writer) else: self.comb += self.dma_reader.source.connect(self.dma_writer.sink) self.submodules.msi = LitePCIeMSI(2) self.comb += [ self.msi.irqs[log2_int(DMA_READER_IRQ)].eq(self.dma_reader.irq), self.msi.irqs[log2_int(DMA_WRITER_IRQ)].eq(self.dma_writer.irq) ] self.submodules.irq_handler = InterruptHandler(debug=False) self.comb += self.msi.source.connect(self.irq_handler.sink)
def __init__(self, port_from, port_to, reverse=False): assert port_from.clock_domain == port_to.clock_domain assert port_from.data_width > port_to.data_width assert port_from.mode == port_to.mode if port_from.data_width % port_to.data_width: raise ValueError("Ratio must be an int") # # # ratio = port_from.data_width//port_to.data_width mode = port_from.mode counter = Signal(max=ratio) counter_reset = Signal() counter_ce = Signal() self.sync += \ If(counter_reset, counter.eq(0) ).Elif(counter_ce, counter.eq(counter + 1) ) self.submodules.fsm = fsm = FSM(reset_state="IDLE") fsm.act("IDLE", counter_reset.eq(1), If(port_from.cmd.valid, NextState("CONVERT") ) ) fsm.act("CONVERT", port_to.cmd.valid.eq(1), port_to.cmd.we.eq(port_from.cmd.we), port_to.cmd.addr.eq(port_from.cmd.addr*ratio + counter), If(port_to.cmd.ready, counter_ce.eq(1), If(counter == ratio - 1, port_from.cmd.ready.eq(1), NextState("IDLE") ) ) ) if mode == "write" or mode == "both": wdata_converter = stream.StrideConverter( port_from.wdata.description, port_to.wdata.description, reverse=reverse) self.submodules += wdata_converter self.submodules += stream.Pipeline( port_from.wdata, wdata_converter, port_to.wdata) if mode == "read" or mode == "both": rdata_converter = stream.StrideConverter( port_to.rdata.description, port_from.rdata.description, reverse=reverse) self.submodules += rdata_converter self.submodules += stream.Pipeline( port_to.rdata, rdata_converter, port_from.rdata)
def __init__(self, wishbone, port, base_address=0x00000000): wishbone_data_width = len(wishbone.dat_w) port_data_width = 2**int(log2(len( port.wdata.data))) # Round to lowest power 2 assert wishbone_data_width >= port_data_width # # # adr_offset = base_address >> log2_int(port.data_width // 8) # Write Datapath --------------------------------------------------------------------------- wdata_converter = stream.StrideConverter( [("data", wishbone_data_width), ("we", wishbone_data_width // 8)], [("data", port_data_width), ("we", port_data_width // 8)], ) self.submodules += wdata_converter self.comb += [ wdata_converter.sink.valid.eq(wishbone.cyc & wishbone.stb & wishbone.we), wdata_converter.sink.data.eq(wishbone.dat_w), wdata_converter.sink.we.eq(wishbone.sel), wdata_converter.source.connect(port.wdata) ] # Read Datapath ---------------------------------------------------------------------------- rdata_converter = stream.StrideConverter( [("data", port_data_width)], [("data", wishbone_data_width)], ) self.submodules += rdata_converter self.comb += [ port.rdata.connect(rdata_converter.sink), rdata_converter.source.ready.eq(1), wishbone.dat_r.eq(rdata_converter.source.data), ] # Control ---------------------------------------------------------------------------------- ratio = wishbone_data_width // port_data_width count = Signal(max=max(ratio, 2)) self.submodules.fsm = fsm = FSM(reset_state="CMD") fsm.act( "CMD", port.cmd.valid.eq(wishbone.cyc & wishbone.stb), port.cmd.we.eq(wishbone.we), port.cmd.addr.eq(wishbone.adr * ratio + count - adr_offset), If( port.cmd.valid & port.cmd.ready, NextValue(count, count + 1), If( count == (ratio - 1), NextValue(count, 0), If(wishbone.we, NextState("WAIT-WRITE")).Else(NextState("WAIT-READ"))))) fsm.act( "WAIT-WRITE", If(wdata_converter.sink.ready, wishbone.ack.eq(1), NextState("CMD"))) fsm.act( "WAIT-READ", If(rdata_converter.source.valid, wishbone.ack.eq(1), NextState("CMD")))
def __init__(self, axi_from, axi_to): dw_from = len(axi_from.r.data) dw_to = len(axi_to.r.data) ratio = int(dw_to//dw_from) assert dw_from*ratio == dw_to # # # # Note: Assuming size of "axi_from" burst >= "axi_to" data_width. # Write path ------------------------------------------------------------------------------- # AW Channel. self.comb += [ axi_from.aw.connect(axi_to.aw, omit={"len", "size"}), axi_to.aw.len.eq( axi_from.aw.len >> log2_int(ratio)), axi_to.aw.size.eq(axi_from.aw.size + log2_int(ratio)), ] # W Channel. w_converter = stream.StrideConverter( description_from = [("data", dw_from), ("strb", dw_from//8)], description_to = [("data", dw_to), ("strb", dw_to//8)], ) self.submodules += w_converter self.comb += axi_from.w.connect(w_converter.sink, omit={"id"}) self.comb += w_converter.source.connect(axi_to.w) self.comb += axi_to.w.id.eq(axi_from.w.id) # B Channel. self.comb += axi_to.b.connect(axi_from.b) # Read path -------------------------------------------------------------------------------- # AR Channel. self.comb += [ axi_from.ar.connect(axi_to.ar, omit={"len", "size"}), axi_to.ar.len.eq( axi_from.ar.len >> log2_int(ratio)), axi_to.ar.size.eq(axi_from.ar.size + log2_int(ratio)), ] # R Channel. r_converter = stream.StrideConverter( description_from = [("data", dw_to)], description_to = [("data", dw_from)], ) self.submodules += r_converter self.comb += axi_to.r.connect(r_converter.sink, omit={"id", "resp"}) self.comb += r_converter.source.connect(axi_from.r) self.comb += axi_from.r.resp.eq(axi_to.r.resp) self.comb += axi_from.r.id.eq(axi_to.r.id)
def get_port(self, udp_port, dw=8, cd="sys"): if udp_port in self.users.keys(): raise ValueError("Port {0:#x} already assigned".format(udp_port)) user_port = LiteEthUDPUserPort(dw) internal_port = LiteEthUDPUserPort(self.dw) # TX # --- # CDC. self.submodules.tx_cdc = tx_cdc = stream.ClockDomainCrossing( layout=eth_udp_user_description(user_port.dw), cd_from=cd, cd_to="sys") self.comb += user_port.sink.connect(tx_cdc.sink) # Data-Width Conversion. self.submodules.tx_converter = tx_converter = stream.StrideConverter( description_from=eth_udp_user_description(user_port.dw), description_to=eth_udp_user_description(self.dw)) self.comb += tx_cdc.source.connect(tx_converter.sink) # Interface. self.comb += tx_converter.source.connect(internal_port.sink) # RX # -- # Data-Width Conversion. self.submodules.rx_converter = rx_converter = stream.StrideConverter( description_from=eth_udp_user_description(self.dw), description_to=eth_udp_user_description(user_port.dw)) self.comb += internal_port.source.connect(rx_converter.sink) # CDC. self.submodules.rx_cdc = rx_cdc = stream.ClockDomainCrossing( layout=eth_udp_user_description(user_port.dw), cd_from="sys", cd_to=cd) self.comb += rx_converter.source.connect(rx_cdc.sink) # Interface. self.comb += rx_cdc.source.connect(user_port.source) # Expose/Return User Port. # ------------------------ self.users[udp_port] = internal_port return user_port
def __init__(self, port_from, port_to, reverse=False): assert port_from.clock_domain == port_to.clock_domain assert port_from.data_width > port_to.data_width assert port_from.mode == port_to.mode if port_from.data_width % port_to.data_width: raise ValueError("Ratio must be an int") # # # ratio = port_from.data_width//port_to.data_width mode = port_from.mode count = Signal(max=ratio) self.submodules.fsm = fsm = FSM(reset_state="IDLE") fsm.act("IDLE", NextValue(count, 0), If(port_from.cmd.valid, NextState("CONVERT") ) ) fsm.act("CONVERT", port_to.cmd.valid.eq(1), port_to.cmd.we.eq(port_from.cmd.we), port_to.cmd.addr.eq(port_from.cmd.addr*ratio + count), If(port_to.cmd.ready, NextValue(count, count + 1), If(count == (ratio - 1), port_from.cmd.ready.eq(1), NextState("IDLE") ) ) ) if mode in ["write", "both"]: wdata_converter = stream.StrideConverter( description_from = port_from.wdata.description, description_to = port_to.wdata.description, reverse = reverse) self.submodules += wdata_converter self.submodules += stream.Pipeline(port_from.wdata, wdata_converter, port_to.wdata) if mode in ["read", "both"]: rdata_converter = stream.StrideConverter( description_from = port_to.rdata.description, description_to = port_from.rdata.description, reverse = reverse) self.submodules += rdata_converter self.submodules += stream.Pipeline( port_to.rdata, rdata_converter, port_from.rdata)
def __init__(self, clock_domain="sys", phy_dw=16): self.sink = stream.Endpoint([("data", phy_dw), ("ctrl", phy_dw//8)]) self.source = stream.Endpoint([("data", 32), ("ctrl", 4)]) # # # converter = stream.StrideConverter( [("data", phy_dw), ("ctrl", phy_dw//8)], [("data", 32), ("ctrl", 4)], reverse=False) converter = stream.BufferizeEndpoints({"sink": stream.DIR_SINK})(converter) converter = ClockDomainsRenamer(clock_domain)(converter) self.submodules.converter = converter cdc = stream.AsyncFIFO([("data", 32), ("ctrl", 4)], 8, buffered=True) cdc = ClockDomainsRenamer({"write": clock_domain, "read": "sys"})(cdc) self.submodules.cdc = cdc skip_remover = RXSKPRemover() self.submodules.skip_remover = skip_remover word_aligner = RXWordAligner() word_aligner = stream.BufferizeEndpoints({"source": stream.DIR_SOURCE})(word_aligner) self.submodules.word_aligner = word_aligner self.comb += [ self.sink.connect(converter.sink), converter.source.connect(cdc.sink), cdc.source.connect(skip_remover.sink), skip_remover.source.connect(word_aligner.sink), word_aligner.source.connect(self.source), ]
def __init__(self, clock_domain="sys", phy_dw=16): self.sink = stream.Endpoint([("data", 32), ("ctrl", 4)]) self.source = stream.Endpoint([("data", phy_dw), ("ctrl", phy_dw // 8)]) # # # # Clock compensation skip_inserter = TXSKPInserter() self.submodules += skip_inserter # Clock domain crossing cdc = stream.AsyncFIFO([("data", 32), ("ctrl", 4)], 8, buffered=True) cdc = ClockDomainsRenamer({"write": "sys", "read": clock_domain})(cdc) self.submodules.cdc = cdc # Data-width adaptation converter = stream.StrideConverter([("data", 32), ("ctrl", 4)], [("data", phy_dw), ("ctrl", phy_dw // 8)], reverse=False) converter = stream.BufferizeEndpoints({"source": stream.DIR_SOURCE})(converter) converter = ClockDomainsRenamer(clock_domain)(converter) self.submodules.converter = converter # Flow self.comb += [ self.sink.connect(skip_inserter.sink), skip_inserter.source.connect(cdc.sink), cdc.source.connect(converter.sink), converter.source.connect(self.source) ]
def __init__(self, phy, phy_cd): assert len(phy.source.data) in [16, 32] self.sink = sink = stream.Endpoint([("data", len(phy.source.data)), ("ctrl", len(phy.source.ctrl))]) self.source = source = stream.Endpoint([("data", 32), ("ctrl", 4)]) # # # use_ebuf = (len(phy.source.data) == 32) if use_ebuf: ebuf = ElasticBuffer(len(phy.source.data) + len(phy.source.ctrl), 4, phy_cd, "jesd") self.submodules.ebuf = ebuf self.comb += [ sink.ready.eq(1), ebuf.din[:32].eq(sink.data), ebuf.din[32:].eq(sink.ctrl), source.valid.eq(1), source.data.eq(ebuf.dout[:32]), source.ctrl.eq(ebuf.dout[32:]) ] else: converter = stream.StrideConverter( [("data", len(phy.source.data)), ("ctrl", len(phy.source.ctrl))], [("data", 32), ("ctrl", 4)], reverse=False) converter = ClockDomainsRenamer(phy_cd)(converter) self.submodules += converter cdc = stream.AsyncFIFO([("data", 32), ("ctrl", 4)], 4) cdc = ClockDomainsRenamer({"write": phy_cd, "read": "jesd"})(cdc) self.submodules += cdc self.comb += [ sink.connect(converter.sink), converter.source.connect(cdc.sink), cdc.source.connect(source) ]
def get_port(self, udp_port, dw=8, cd="sys"): if udp_port in self.users.keys(): raise ValueError("Port {0:#x} already assigned".format(udp_port)) user_port = LiteEthUDPUserPort(dw) internal_port = LiteEthUDPUserPort(8) # tx tx_stream = user_port.sink if cd is not "sys": tx_cdc = stream.AsyncFIFO(eth_udp_user_description(user_port.dw), 4) tx_cdc = ClockDomainsRenamer({"write": cd, "read": "sys"})(tx_cdc) self.submodules += tx_cdc self.comb += tx_stream.connect(tx_cdc.sink) tx_stream = tx_cdc.source if dw != 8: tx_converter = stream.StrideConverter( eth_udp_user_description(user_port.dw), eth_udp_user_description(8)) self.submodules += tx_converter self.comb += tx_stream.connect(tx_converter.sink) tx_stream = tx_converter.source self.comb += tx_stream.connect(internal_port.sink) # rx rx_stream = internal_port.source if dw != 8: rx_converter = stream.StrideConverter( eth_udp_user_description(8), eth_udp_user_description(user_port.dw)) self.submodules += rx_converter self.comb += rx_stream.connect(rx_converter.sink) rx_stream = rx_converter.source if cd is not "sys": rx_cdc = stream.AsyncFIFO(eth_udp_user_description(user_port.dw), 4) rx_cdc = ClockDomainsRenamer({"write": "sys", "read": cd})(rx_cdc) self.submodules += rx_cdc self.comb += rx_stream.connect(rx_cdc.sink) rx_stream = rx_cdc.source self.comb += rx_stream.connect(user_port.source) self.users[udp_port] = internal_port return user_port
def __init__(self, port_from, port_to, reverse=False): assert port_from.clock_domain == port_to.clock_domain assert port_from.data_width < port_to.data_width assert port_from.mode == port_to.mode assert port_from.mode == "write" if port_to.data_width % port_from.data_width: raise ValueError("Ratio must be an int") # # # ratio = port_to.data_width // port_from.data_width we = Signal() address = Signal(port_to.address_width) counter = Signal(max=ratio) counter_reset = Signal() counter_ce = Signal() self.sync += \ If(counter_reset, counter.eq(0) ).Elif(counter_ce, counter.eq(counter + 1) ) self.submodules.fsm = fsm = FSM(reset_state="IDLE") fsm.act( "IDLE", port_from.cmd.ready.eq(1), If(port_from.cmd.valid, counter_ce.eq(1), NextValue(we, port_from.cmd.we), NextValue(address, port_from.cmd.addr), NextState("RECEIVE"))) fsm.act( "RECEIVE", port_from.cmd.ready.eq(1), If(port_from.cmd.valid, counter_ce.eq(1), If(counter == ratio - 1, NextState("GENERATE")))) fsm.act("GENERATE", port_to.cmd.valid.eq(1), port_to.cmd.we.eq(we), port_to.cmd.addr.eq(address[log2_int(ratio):]), If(port_to.cmd.ready, NextState("IDLE"))) wdata_converter = stream.StrideConverter(port_from.wdata.description, port_to.wdata.description, reverse=reverse) self.submodules += wdata_converter self.submodules += stream.Pipeline(port_from.wdata, wdata_converter, port_to.wdata)
def __init__(self, dw, cd_ratio): self.sink = stream.Endpoint(core_layout(dw)) self.source = stream.Endpoint(core_layout(dw * cd_ratio)) # # # self.submodules.buffer = stream.Buffer(core_layout(dw)) self.submodules.trigger = FrontendTrigger(dw) self.submodules.subsampler = FrontendSubSampler(dw) self.submodules.converter = stream.StrideConverter( core_layout(dw, 1), core_layout(dw * cd_ratio, cd_ratio)) self.submodules.fifo = ClockDomainsRenamer({ "write": "sys", "read": "new_sys" })(stream.AsyncFIFO(core_layout(dw * cd_ratio, cd_ratio), 8)) self.submodules.pipeline = stream.Pipeline(self.sink, self.buffer, self.trigger, self.subsampler, self.converter, self.fifo, self.source)
def __init__(self, platform, with_cpu=True, with_sdram=True, with_etherbone=True, with_gtp=True, gtp_connector="pcie", gtp_refclk="pcie", gtp_linerate=5e9, with_gtp_bist=True, with_gtp_freqmeter=True, with_record=True): sys_clk_freq = int(100e6) # SoCSDRAM --------------------------------------------------------------------------------- SoCSDRAM.__init__( self, platform, sys_clk_freq, cpu_type="vexriscv" if with_cpu else None, csr_data_width=32, with_uart=with_cpu, uart_name="crossover", integrated_rom_size=0x8000 if with_cpu else 0x0000, integrated_main_ram_size=0x1000 if not with_sdram else 0x0000, ident="PCIe Analyzer LiteX SoC", ident_version=True) # CRG -------------------------------------------------------------------------------------- self.submodules.crg = _CRG(platform, sys_clk_freq) # DDR3 SDRAM ------------------------------------------------------------------------------- if not self.integrated_main_ram_size: self.submodules.ddrphy = s7ddrphy.A7DDRPHY( platform.request("ddram"), memtype="DDR3", nphases=4, sys_clk_freq=sys_clk_freq) self.add_csr("ddrphy") sdram_module = K4B2G1646F(sys_clk_freq, "1:4") self.register_sdram(self.ddrphy, geom_settings=sdram_module.geom_settings, timing_settings=sdram_module.timing_settings) # Etherbone -------------------------------------------------------------------------------- if with_etherbone: # ethphy self.submodules.ethphy = LiteEthPHYRMII( clock_pads=self.platform.request("eth_clocks"), pads=self.platform.request("eth")) self.add_csr("ethphy") # ethcore self.submodules.ethcore = LiteEthUDPIPCore( phy=self.ethphy, mac_address=0x10e2d5000000, ip_address="192.168.1.50", clk_freq=self.clk_freq) # etherbone self.submodules.etherbone = LiteEthEtherbone( self.ethcore.udp, 1234) self.add_wb_master(self.etherbone.wishbone.bus) # timing constraints self.platform.add_period_constraint(self.ethphy.crg.cd_eth_rx.clk, 1e9 / 50e6) self.platform.add_period_constraint(self.ethphy.crg.cd_eth_tx.clk, 1e9 / 50e6) self.platform.add_false_path_constraints( self.crg.cd_sys.clk, self.ethphy.crg.cd_eth_rx.clk, self.ethphy.crg.cd_eth_tx.clk) # GTP RefClk ------------------------------------------------------------------------------- if with_gtp: assert gtp_refclk in ["pcie", "internal"] if gtp_refclk == "pcie": refclk = Signal() refclk_freq = 100e6 refclk_pads = platform.request("pcie_refclk") self.specials += Instance("IBUFDS_GTE2", i_CEB=0, i_I=refclk_pads.p, i_IB=refclk_pads.n, o_O=refclk) else: refclk = Signal() refclk_freq = 100e6 self.comb += refclk.eq(ClockSignal("clk100")) platform.add_platform_command( "set_property SEVERITY {{Warning}} [get_drc_checks REQP-49]" ) # GTP PLL ---------------------------------------------------------------------------------- if with_gtp: qpll = GTPQuadPLL(refclk, refclk_freq, gtp_linerate) print(qpll) self.submodules += qpll # GTPs ------------------------------------------------------------------------------------- if with_gtp: for i in range(2): tx_pads = platform.request(gtp_connector + "_tx", i) rx_pads = platform.request(gtp_connector + "_rx", i) gtp = GTP(qpll, tx_pads, rx_pads, sys_clk_freq, data_width=20, clock_aligner=False, tx_buffer_enable=True, rx_buffer_enable=True) gtp.add_stream_endpoints() setattr(self.submodules, "gtp" + str(i), gtp) platform.add_period_constraint(gtp.cd_tx.clk, 1e9 / gtp.tx_clk_freq) platform.add_period_constraint(gtp.cd_rx.clk, 1e9 / gtp.rx_clk_freq) self.platform.add_false_path_constraints( self.crg.cd_sys.clk, gtp.cd_tx.clk, gtp.cd_rx.clk) # GTPs FreqMeters -------------------------------------------------------------------------- if with_gtp_freqmeter: self.submodules.gtp0_tx_freq = FreqMeter(ClockSignal("gtp0_tx")) self.submodules.gtp0_rx_freq = FreqMeter(ClockSignal("gtp0_rx")) self.submodules.gtp1_tx_freq = FreqMeter(ClockSignal("gtp1_tx")) self.submodules.gtp1_rx_freq = FreqMeter(ClockSignal("gtp1_rx")) self.add_csr("gtp0_tx_freq") self.add_csr("gtp0_rx_freq") self.add_csr("gtp1_tx_freq") self.add_csr("gtp1_rx_freq") # GTPs BIST -------------------------------------------------------------------------------- if with_gtp_bist: self.submodules.gtp0_tx_bist = GTPTXBIST(self.gtp0, "gtp0_tx") self.submodules.gtp0_rx_bist = GTPRXBIST(self.gtp0, "gtp0_rx") self.submodules.gtp1_tx_bist = GTPTXBIST(self.gtp1, "gtp1_tx") self.submodules.gtp1_rx_bist = GTPRXBIST(self.gtp1, "gtp1_rx") self.add_csr("gtp0_tx_bist") self.add_csr("gtp0_rx_bist") self.add_csr("gtp1_tx_bist") self.add_csr("gtp1_rx_bist") # Record ----------------------------------------------------------------------------------- # FIXME: use better data/ctrl packing (or separate recorders) if with_record: # Convert RX stream from 16-bit@250MHz to 64-bit@sys_clk rx_converter = stream.StrideConverter([("data", 16), ("ctrl", 2)], [("data", 96), ("ctrl", 12)], reverse=False) rx_converter = ClockDomainsRenamer("gtp0_rx")(rx_converter) self.submodules.rx_converter = rx_converter rx_cdc = stream.AsyncFIFO([("data", 96), ("ctrl", 12)], 8, buffered=True) rx_cdc = ClockDomainsRenamer({ "write": "gtp0_rx", "read": "sys" })(rx_cdc) self.submodules.rx_cdc = rx_cdc # RX DMA Recorder self.submodules.rx_dma_recorder = LiteDRAMDMAWriter( self.sdram.crossbar.get_port("write", 128)) self.rx_dma_recorder.add_csr() self.add_csr("rx_dma_recorder") self.comb += [ gtp.source.connect(rx_converter.sink), rx_converter.source.connect(rx_cdc.sink), self.rx_dma_recorder.sink.valid.eq(rx_cdc.source.valid), self.rx_dma_recorder.sink.data[0:96].eq(rx_cdc.source.data), self.rx_dma_recorder.sink.data[96:108].eq(rx_cdc.source.ctrl), ]
def __init__(self, phy): self.sink = stream.Endpoint([("data", 32)]) self.source = stream.Endpoint([("data", 32)]) self.argument = CSRStorage(32) self.command = CSRStorage(32) self.send = CSR() self.response = CSRStatus(128) self.cmdevt = CSRStatus(4) self.dataevt = CSRStatus(4) self.blocksize = CSRStorage(16) self.blockcount = CSRStorage(32) self.timeout = CSRStorage(32, reset=2**16) # # # argument = Signal(32) command = Signal(32) response = Signal(136) cmdevt = Signal(4) dataevt = Signal(4) blocksize = Signal(16) blockcount = Signal(32) timeout = Signal(32) # sys to sd cdc self.specials += [ MultiReg(self.argument.storage, argument, "sd"), MultiReg(self.command.storage, command, "sd"), MultiReg(self.blocksize.storage, blocksize, "sd"), MultiReg(self.blockcount.storage, blockcount, "sd"), MultiReg(self.timeout.storage, timeout, "sd"), ] # sd to sys cdc response_cdc = BusSynchronizer(136, "sd", "sys") cmdevt_cdc = BusSynchronizer(4, "sd", "sys") dataevt_cdc = BusSynchronizer(4, "sd", "sys") self.submodules += response_cdc, cmdevt_cdc, dataevt_cdc self.comb += [ response_cdc.i.eq(response), self.response.status.eq(response_cdc.o[:128]), cmdevt_cdc.i.eq(cmdevt), self.cmdevt.status.eq(cmdevt_cdc.o), dataevt_cdc.i.eq(dataevt), self.dataevt.status.eq(dataevt_cdc.o) ] self.submodules.new_command = PulseSynchronizer("sys", "sd") self.comb += self.new_command.i.eq(self.send.re) self.comb += phy.cfg.timeout.eq(timeout) self.comb += phy.cfg.blocksize.eq(blocksize) self.submodules.crc7_inserter = crc7_inserter = ClockDomainsRenamer( "sd")(CRC(9, 7, 40)) self.submodules.crc16_inserter = crc16_inserter = ClockDomainsRenamer( "sd")(CRCUpstreamInserter()) self.submodules.crc16_checker = crc16_checker = ClockDomainsRenamer( "sd")(CRCDownstreamChecker()) self.submodules.upstream_cdc = ClockDomainsRenamer({ "write": "sys", "read": "sd" })(stream.AsyncFIFO(self.sink.description, 4)) self.submodules.downstream_cdc = ClockDomainsRenamer({ "write": "sd", "read": "sys" })(stream.AsyncFIFO(self.source.description, 4)) self.submodules.upstream_converter = ClockDomainsRenamer("sd")( stream.StrideConverter([('data', 32)], [('data', 8)], reverse=True)) self.submodules.downstream_converter = ClockDomainsRenamer("sd")( stream.StrideConverter([('data', 8)], [('data', 32)], reverse=True)) self.comb += [ self.sink.connect(self.upstream_cdc.sink), self.upstream_cdc.source.connect(self.upstream_converter.sink), self.upstream_converter.source.connect(crc16_inserter.sink), crc16_checker.source.connect(self.downstream_converter.sink), self.downstream_converter.source.connect(self.downstream_cdc.sink), self.downstream_cdc.source.connect(self.source) ] cmd_type = Signal(2) cmd_count = Signal(3) cmd_done = Signal() cmd_error = Signal() cmd_timeout = Signal() data_type = Signal(2) data_count = Signal(32) data_done = Signal() data_error = Signal() data_timeout = Signal() self.comb += [ cmd_type.eq(command[0:2]), data_type.eq(command[5:7]), cmdevt.eq(Cat(cmd_done, cmd_error, cmd_timeout, 0)), # FIXME cmd response CRC. dataevt.eq( Cat(data_done, data_error, data_timeout, ~crc16_checker.valid)), crc7_inserter.val.eq(Cat(argument, command[8:14], 1, 0)), crc7_inserter.clr.eq(1), crc7_inserter.enable.eq(1), ] self.submodules.fsm = fsm = ClockDomainsRenamer("sd")(FSM()) fsm.act( "IDLE", NextValue(cmd_done, 1), NextValue(data_done, 1), NextValue(cmd_count, 0), NextValue(data_count, 0), If(self.new_command.o, NextValue(cmd_done, 0), NextValue(cmd_error, 0), NextValue(cmd_timeout, 0), NextValue(data_done, 0), NextValue(data_error, 0), NextValue(data_timeout, 0), NextState("CMD"))) fsm.act( "CMD", phy.cmdw.sink.valid.eq(1), Case( cmd_count, { 0: phy.cmdw.sink.data.eq(Cat(command[8:14], 1, 0)), 1: phy.cmdw.sink.data.eq(argument[24:32]), 2: phy.cmdw.sink.data.eq(argument[16:24]), 3: phy.cmdw.sink.data.eq(argument[8:16]), 4: phy.cmdw.sink.data.eq(argument[0:8]), 5: [ phy.cmdw.sink.data.eq(Cat(1, crc7_inserter.crc)), phy.cmdw.sink.last.eq( cmd_type == SDCARD_CTRL_RESPONSE_NONE) ] }), If( phy.cmdw.sink.valid & phy.cmdw.sink.ready, NextValue(cmd_count, cmd_count + 1), If( cmd_count == (6 - 1), If(cmd_type == SDCARD_CTRL_RESPONSE_NONE, NextValue(cmd_done, 1), NextState("IDLE")).Else(NextState("CMD-RESPONSE"))))) fsm.act( "CMD-RESPONSE", phy.cmdr.sink.valid.eq(1), phy.cmdr.sink.last.eq(data_type == SDCARD_CTRL_DATA_TRANSFER_NONE), If( cmd_type == SDCARD_CTRL_RESPONSE_LONG, phy.cmdr.sink.length.eq(17) # 136bits ).Else(phy.cmdr.sink.length.eq(6) # 48bits ), If( phy.cmdr.source.valid, phy.cmdr.source.ready.eq(1), If(phy.cmdr.source.status == SDCARD_STREAM_STATUS_TIMEOUT, NextValue(cmd_timeout, 1), NextState("IDLE")).Elif( phy.cmdr.source.last, If(data_type == SDCARD_CTRL_DATA_TRANSFER_WRITE, NextState("DATA-WRITE")).Elif( data_type == SDCARD_CTRL_DATA_TRANSFER_READ, NextState("DATA-READ")).Else(NextState("IDLE")), ).Else( NextValue(response, Cat(phy.cmdr.source.data, response))))) fsm.act( "DATA-WRITE", crc16_inserter.source.connect(phy.dataw.sink), If( phy.dataw.sink.valid & phy.dataw.sink.last & phy.dataw.sink.ready, NextValue(data_count, data_count + 1), If(data_count == (blockcount - 1), NextState("IDLE"))), phy.datar.source.ready.eq(1), If( phy.datar.source.valid, If( phy.datar.source.status != SDCARD_STREAM_STATUS_DATAACCEPTED, NextValue(data_error, 1)))) fsm.act( "DATA-READ", phy.datar.sink.valid.eq(1), phy.datar.sink.last.eq(data_count == (blockcount - 1)), phy.datar.source.ready.eq(1), If( phy.datar.source.valid, If( phy.datar.source.status == SDCARD_STREAM_STATUS_OK, phy.datar.source.connect(crc16_checker.sink, omit={"status"}), If(phy.datar.source.last & phy.datar.source.ready, NextValue(data_count, data_count + 1), If(data_count == (blockcount - 1), NextState("IDLE")))).Elif( phy.datar.source.status == SDCARD_STREAM_STATUS_TIMEOUT, NextValue(data_timeout, 1), NextValue(data_count, 0), phy.datar.source.ready.eq(1), NextState("IDLE"))))
def __init__(self, phy): self.sink = stream.Endpoint([("data", 32)]) self.source = stream.Endpoint([("data", 32)]) self.argument = CSRStorage(32) self.command = CSRStorage(32) self.response = CSRStatus(120) self.cmdevt = CSRStatus(32) self.dataevt = CSRStatus(32) self.blocksize = CSRStorage(16) self.blockcount = CSRStorage(32) self.datatimeout = CSRStorage(32, reset=2**16) self.cmdtimeout = CSRStorage(32, reset=2**16) self.datawcrcclear = CSRStorage() self.datawcrcvalids = CSRStatus(32) self.datawcrcerrors = CSRStatus(32) # # # argument = Signal(32) command = Signal(32) response = Signal(120) cmdevt = Signal(32) dataevt = Signal(32) blocksize = Signal(16) blockcount = Signal(32) datatimeout = Signal(32) cmdtimeout = Signal(32) # sys to sd cdc self.specials += [ MultiReg(self.argument.storage, argument, "sd"), MultiReg(self.command.storage, command, "sd"), MultiReg(self.blocksize.storage, blocksize, "sd"), MultiReg(self.blockcount.storage, blockcount, "sd"), MultiReg(self.datatimeout.storage, datatimeout, "sd"), MultiReg(self.cmdtimeout.storage, cmdtimeout, "sd") ] # sd to sys cdc response_cdc = BusSynchronizer(120, "sd", "sys") cmdevt_cdc = BusSynchronizer(32, "sd", "sys") dataevt_cdc = BusSynchronizer(32, "sd", "sys") self.submodules += response_cdc, cmdevt_cdc, dataevt_cdc self.comb += [ response_cdc.i.eq(response), self.response.status.eq(response_cdc.o), cmdevt_cdc.i.eq(cmdevt), self.cmdevt.status.eq(cmdevt_cdc.o), dataevt_cdc.i.eq(dataevt), self.dataevt.status.eq(dataevt_cdc.o) ] self.submodules.new_command = PulseSynchronizer("sys", "sd") self.comb += self.new_command.i.eq(self.command.re) self.comb += [ phy.cfg.blocksize.eq(blocksize), phy.cfg.datatimeout.eq(datatimeout), phy.cfg.cmdtimeout.eq(cmdtimeout), phy.dataw.crc_clear.eq(self.datawcrcclear.storage), self.datawcrcvalids.status.eq(phy.dataw.crc_valids), self.datawcrcerrors.status.eq(phy.dataw.crc_errors) ] self.submodules.crc7inserter = ClockDomainsRenamer("sd")(CRC(9, 7, 40)) self.submodules.crc7checker = ClockDomainsRenamer("sd")(CRCChecker( 9, 7, 120)) self.submodules.crc16inserter = ClockDomainsRenamer("sd")( CRCUpstreamInserter()) self.submodules.crc16checker = ClockDomainsRenamer("sd")( CRCDownstreamChecker()) self.submodules.upstream_cdc = ClockDomainsRenamer({ "write": "sys", "read": "sd" })(stream.AsyncFIFO(self.sink.description, 4)) self.submodules.downstream_cdc = ClockDomainsRenamer({ "write": "sd", "read": "sys" })(stream.AsyncFIFO(self.source.description, 4)) self.submodules.upstream_converter = ClockDomainsRenamer("sd")( stream.StrideConverter([('data', 32)], [('data', 8)], reverse=True)) self.submodules.downstream_converter = ClockDomainsRenamer("sd")( stream.StrideConverter([('data', 8)], [('data', 32)], reverse=True)) self.comb += [ self.sink.connect(self.upstream_cdc.sink), self.upstream_cdc.source.connect(self.upstream_converter.sink), self.upstream_converter.source.connect(self.crc16inserter.sink), self.crc16checker.source.connect(self.downstream_converter.sink), self.downstream_converter.source.connect(self.downstream_cdc.sink), self.downstream_cdc.source.connect(self.source) ] self.submodules.fsm = fsm = ClockDomainsRenamer("sd")(FSM()) csel = Signal(max=6) waitresp = Signal(2) dataxfer = Signal(2) cmddone = Signal(reset=1) datadone = Signal(reset=1) blkcnt = Signal(32) pos = Signal(2) cerrtimeout = Signal() cerrcrc_en = Signal() derrtimeout = Signal() derrwrite = Signal() derrread_en = Signal() self.comb += [ waitresp.eq(command[0:2]), dataxfer.eq(command[5:7]), cmdevt.eq( Cat(cmddone, C(0, 1), cerrtimeout, cerrcrc_en & ~self.crc7checker.valid)), dataevt.eq( Cat(datadone, derrwrite, derrtimeout, derrread_en & ~self.crc16checker.valid)), self.crc7inserter.val.eq(Cat(argument, command[8:14], 1, 0)), self.crc7inserter.clr.eq(1), self.crc7inserter.enable.eq(1), self.crc7checker.val.eq(response) ] ccases = {} # To send command and CRC ccases[0] = phy.sink.data.eq(Cat(command[8:14], 1, 0)) for i in range(4): ccases[i + 1] = phy.sink.data.eq(argument[24 - 8 * i:32 - 8 * i]) ccases[5] = [ phy.sink.data.eq(Cat(1, self.crc7inserter.crc)), phy.sink.last.eq(waitresp == SDCARD_CTRL_RESPONSE_NONE) ] fsm.act( "IDLE", NextValue(pos, 0), If(self.new_command.o, NextValue(cmddone, 0), NextValue(cerrtimeout, 0), NextValue(cerrcrc_en, 0), NextValue(datadone, 0), NextValue(derrtimeout, 0), NextValue(derrwrite, 0), NextValue(derrread_en, 0), NextValue(response, 0), NextState("SEND_CMD"))) fsm.act( "SEND_CMD", phy.sink.valid.eq(1), phy.sink.cmd_data_n.eq(1), phy.sink.rd_wr_n.eq(0), Case(csel, ccases), If( phy.sink.valid & phy.sink.ready, If(csel < 5, NextValue(csel, csel + 1)).Else( NextValue(csel, 0), If(waitresp == SDCARD_CTRL_RESPONSE_NONE, NextValue(cmddone, 1), NextState("IDLE")).Else(NextValue(cerrcrc_en, 1), NextState("RECV_RESP"))))) fsm.act( "RECV_RESP", phy.sink.valid.eq(1), phy.sink.cmd_data_n.eq(1), phy.sink.rd_wr_n.eq(1), phy.sink.last.eq(dataxfer == SDCARD_CTRL_DATA_TRANSFER_NONE), If( waitresp == SDCARD_CTRL_RESPONSE_SHORT, phy.sink.data.eq(5) # (5+1)*8 == 48bits ).Elif( waitresp == SDCARD_CTRL_RESPONSE_LONG, phy.sink.data.eq(16) # (16+1)*8 == 136bits ), If( phy.source.valid, # Wait for resp or timeout coming from phy phy.source.ready.eq(1), If(phy.source.status == SDCARD_STREAM_STATUS_TIMEOUT, NextValue(cerrtimeout, 1), NextValue(cmddone, 1), NextValue(datadone, 1), NextState("IDLE")).Elif( phy.source.last, # Check response CRC NextValue(self.crc7checker.check, phy.source.data[1:8]), NextValue(cmddone, 1), If(dataxfer == SDCARD_CTRL_DATA_TRANSFER_READ, NextValue(derrread_en, 1), NextState("RECV_DATA")).Elif( dataxfer == SDCARD_CTRL_DATA_TRANSFER_WRITE, NextState("SEND_DATA")).Else( NextValue(datadone, 1), NextState("IDLE")), ).Else( NextValue(response, Cat(phy.source.data, response[0:112]))))) fsm.act( "RECV_DATA", phy.sink.valid.eq(1), phy.sink.cmd_data_n.eq(0), phy.sink.rd_wr_n.eq(1), phy.sink.last.eq(blkcnt == (blockcount - 1)), phy.sink.data.eq(0), # Read 1 block If( phy.source.valid, phy.source.ready.eq(1), If( phy.source.status == SDCARD_STREAM_STATUS_OK, self.crc16checker.sink.data.eq( phy.source.data), # Manual connect streams except ctrl self.crc16checker.sink.valid.eq(phy.source.valid), self.crc16checker.sink.last.eq(phy.source.last), phy.source.ready.eq(self.crc16checker.sink.ready), If( phy.source.last & phy.source.ready, # End of block If(blkcnt < (blockcount - 1), NextValue(blkcnt, blkcnt + 1), NextState("RECV_DATA")).Else( NextValue(blkcnt, 0), NextValue(datadone, 1), NextState("IDLE")))).Elif( phy.source.status == SDCARD_STREAM_STATUS_TIMEOUT, NextValue(derrtimeout, 1), NextValue(blkcnt, 0), NextValue(datadone, 1), phy.source.ready.eq(1), NextState("IDLE")))) fsm.act( "SEND_DATA", phy.sink.valid.eq(self.crc16inserter.source.valid), phy.sink.cmd_data_n.eq(0), phy.sink.rd_wr_n.eq(0), phy.sink.last.eq(self.crc16inserter.source.last), phy.sink.data.eq(self.crc16inserter.source.data), self.crc16inserter.source.ready.eq(phy.sink.ready), If( self.crc16inserter.source.valid & self.crc16inserter.source.last & self.crc16inserter.source.ready, If(blkcnt < (blockcount - 1), NextValue(blkcnt, blkcnt + 1)).Else(NextValue(blkcnt, 0), NextValue(datadone, 1), NextState("IDLE"))), If( phy.source.valid, phy.source.ready.eq(1), If(phy.source.status != SDCARD_STREAM_STATUS_DATAACCEPTED, NextValue(derrwrite, 1))))
def __init__(self, port_from, port_to, reverse=False): assert port_from.clock_domain == port_to.clock_domain assert port_from.data_width < port_to.data_width assert port_from.mode == port_to.mode if port_to.data_width % port_from.data_width: raise ValueError("Ratio must be an int") # # # ratio = port_to.data_width // port_from.data_width mode = port_from.mode # Command ---------------------------------------------------------------------------------- # Defines cmd type and the chunks that have been requested for the current port_to command. sel = Signal(ratio) cmd_buffer = stream.SyncFIFO([("sel", ratio), ("we", 1)], 0) self.submodules += cmd_buffer # Store last received command. cmd_addr = Signal.like(port_from.cmd.addr) cmd_we = Signal() cmd_last = Signal() # Indicates that we need to proceed to the next port_to command. next_cmd = Signal() addr_changed = Signal() # Signals that indicate that write/read convertion has finished. wdata_finished = Signal() rdata_finished = Signal() # Used to prevent reading old memory value if previous command has written the same address. read_lock = Signal() read_unlocked = Signal() rw_collision = Signal() # Different order depending on read/write: # - read: new -> cmd -> fill -> commit -> new # - write: new -> fill -> commit -> cmd -> new # For writes we have to send the command at the end to prevent situations when, during # a burst, LiteDRAM expects data (wdata_ready=1) but write converter is still converting. self.submodules.fsm = fsm = FSM() fsm.act( "NEW", port_from.cmd.ready.eq(port_from.cmd.valid & ~read_lock), If( port_from.cmd.ready, NextValue(cmd_addr, port_from.cmd.addr), NextValue(cmd_we, port_from.cmd.we), NextValue(cmd_last, port_from.cmd.last), NextValue(sel, 1 << port_from.cmd.addr[:log2_int(ratio)]), If( port_from.cmd.we, NextState("FILL"), ).Else(NextState("CMD"), ))) fsm.act( "CMD", port_to.cmd.valid.eq(1), port_to.cmd.we.eq(cmd_we), port_to.cmd.addr.eq(cmd_addr[log2_int(ratio):]), If(port_to.cmd.ready, If(cmd_we, NextState("NEW")).Else(NextState("FILL")))) fsm.act( "FILL", If(next_cmd, NextState("COMMIT")). Else( # Acknowledge incomming commands, while filling `sel`. port_from.cmd.ready.eq(port_from.cmd.valid), NextValue(cmd_last, port_from.cmd.last), If( port_from.cmd.valid, NextValue(sel, sel | 1 << port_from.cmd.addr[:log2_int(ratio)])))) fsm.act( "COMMIT", cmd_buffer.sink.valid.eq(1), cmd_buffer.sink.sel.eq(sel), cmd_buffer.sink.we.eq(cmd_we), If(cmd_buffer.sink.ready, If(cmd_we, NextState("CMD")).Else(NextState("NEW")))) self.comb += [ cmd_buffer.source.ready.eq(wdata_finished | rdata_finished), addr_changed.eq(cmd_addr[log2_int(ratio):] != port_from.cmd.addr[log2_int(ratio):]), # Collision happens on write to read transition when address does not change. rw_collision.eq(cmd_we & (port_from.cmd.valid & ~port_from.cmd.we) & ~addr_changed), # Go to the next command if one of the following happens: # - port_to address changes. # - cmd type changes. # - we received all the `ratio` commands. # - this is the last command in a sequence. # - master requests a flush (even after the command has been sent). next_cmd.eq(addr_changed | (cmd_we != port_from.cmd.we) | (sel == 2**ratio - 1) | cmd_last | port_from.flush), ] self.sync += [ # Block sending read command if we have just written to that address If( wdata_finished, read_lock.eq(0), read_unlocked.eq(1), ).Elif(rw_collision & ~port_to.cmd.valid & ~read_unlocked, read_lock.eq(1)), If(port_from.cmd.valid & port_from.cmd.ready, read_unlocked.eq(0)) ] # Read Datapath ---------------------------------------------------------------------------- if mode in ["read", "both"]: # Queue received data not to loose it when it comes too fast. rdata_fifo = stream.SyncFIFO(port_to.rdata.description, ratio - 1) rdata_converter = stream.StrideConverter( description_from=port_to.rdata.description, description_to=port_from.rdata.description, reverse=reverse) self.submodules += rdata_fifo, rdata_converter # Shift register with a bitmask of current chunk. rdata_chunk = Signal(ratio, reset=1) rdata_chunk_valid = Signal() self.sync += \ If(rdata_converter.source.valid & rdata_converter.source.ready, rdata_chunk.eq(Cat(rdata_chunk[ratio-1], rdata_chunk[:ratio-1])) ) self.comb += [ # port_to -> rdata_fifo -> rdata_converter -> port_from port_to.rdata.connect(rdata_fifo.sink), rdata_fifo.source.connect(rdata_converter.sink), rdata_chunk_valid.eq( (cmd_buffer.source.sel & rdata_chunk) != 0), If( cmd_buffer.source.valid & ~cmd_buffer.source.we, # If that chunk is valid we send it to the user port and wait for ready. If(rdata_chunk_valid, port_from.rdata.valid.eq(rdata_converter.source.valid), port_from.rdata.data.eq(rdata_converter.source.data), rdata_converter.source.ready.eq(port_from.rdata.ready)). Else( # If this chunk was not requested in `sel`, ignore it. rdata_converter.source.ready.eq(1)), rdata_finished.eq(rdata_converter.source.valid & rdata_converter.source.ready & rdata_chunk[ratio - 1])), ] # Write Datapath --------------------------------------------------------------------------- if mode in ["write", "both"]: # Queue write data not to miss it when the lower chunks haven't been reqested. wdata_fifo = stream.SyncFIFO(port_from.wdata.description, ratio - 1) wdata_buffer = stream.SyncFIFO(port_to.wdata.description, 1) wdata_converter = stream.StrideConverter( description_from=port_from.wdata.description, description_to=port_to.wdata.description, reverse=reverse) self.submodules += wdata_converter, wdata_fifo, wdata_buffer # Shift register with a bitmask of current chunk. wdata_chunk = Signal(ratio, reset=1) wdata_chunk_valid = Signal() self.sync += \ If(wdata_converter.sink.valid & wdata_converter.sink.ready, wdata_chunk.eq(Cat(wdata_chunk[ratio-1], wdata_chunk[:ratio-1])) ) # Replicate `sel` bits to match the width of port_to.wdata.we. wdata_sel = Signal.like(port_to.wdata.we) if reverse: wdata_sel_parts = [ Replicate(cmd_buffer.source.sel[i], port_to.wdata.we.nbits // sel.nbits) for i in reversed(range(ratio)) ] else: wdata_sel_parts = [ Replicate(cmd_buffer.source.sel[i], port_to.wdata.we.nbits // sel.nbits) for i in range(ratio) ] self.sync += \ If(cmd_buffer.source.valid & cmd_buffer.source.we & wdata_chunk[ratio - 1], wdata_sel.eq(Cat(wdata_sel_parts)) ) self.comb += [ # port_from -> wdata_fifo -> wdata_converter port_from.wdata.connect(wdata_fifo.sink), wdata_buffer.source.connect(port_to.wdata), wdata_chunk_valid.eq( (cmd_buffer.source.sel & wdata_chunk) != 0), If( cmd_buffer.source.valid & cmd_buffer.source.we, # When the current chunk is valid, read it from wdata_fifo. If( wdata_chunk_valid, wdata_converter.sink.valid.eq(wdata_fifo.source.valid), wdata_converter.sink.data.eq(wdata_fifo.source.data), wdata_converter.sink.we.eq(wdata_fifo.source.we), wdata_fifo.source.ready.eq(wdata_converter.sink.ready), ). Else( # If chunk is not valid, send any data and do not advance fifo. wdata_converter.sink.valid.eq(1), ), ), wdata_buffer.sink.valid.eq(wdata_converter.source.valid), wdata_buffer.sink.data.eq(wdata_converter.source.data), wdata_buffer.sink.we.eq(wdata_converter.source.we & wdata_sel), wdata_converter.source.ready.eq(wdata_buffer.sink.ready), wdata_finished.eq(wdata_converter.sink.valid & wdata_converter.sink.ready & wdata_chunk[ratio - 1]), ]
def __init__(self, layout, depth, base, crossbar, read_threshold=None, write_threshold=None, preserve_first_last=True): self.sink = sink = stream.Endpoint(layout) self.source = source = stream.Endpoint(layout) # # # # preserve first and last fields if preserve_first_last: self.submodules.pack = _FLPack(layout) self.submodules.unpack = _FLUnpack(layout) self.comb += [ sink.connect(self.pack.sink), self.unpack.source.connect(source), ] fifo_in = self.pack.source fifo_out = self.unpack.sink else: fifo_in = sink fifo_out = source native_width = crossbar.controller.data_width dw = len(fifo_in.payload) if dw <= native_width: if native_width % dw: raise ValueError("Ratio must be an int") ctrl_ratio = native_width // dw ctrl_depth = ((depth - 1) // ctrl_ratio) + 1 fifo_depth = ctrl_ratio else: raise NotImplementedError("Only upconverter support for now") # use native controller width read_port = crossbar.get_port(mode="read") write_port = crossbar.get_port(mode="write") if read_threshold is None: read_threshold = 0 if write_threshold is None: write_threshold = ctrl_depth # ctrl counts blocks in native width self.submodules.ctrl = _LiteDRAMFIFOCtrl(base, ctrl_depth, read_threshold, write_threshold) self.submodules.writer = _LiteDRAMFIFOWriter(write_port, self.ctrl) self.submodules.reader = _LiteDRAMFIFOReader(read_port, self.ctrl) # router chooses bypass or dram self.submodules.router = _LiteDRAMFIFORouter(dw, fifo_depth, self.ctrl) self.submodules.conv_w = stream.StrideConverter( fifo_in.description, self.writer.sink.description) self.submodules.conv_r = stream.StrideConverter( self.reader.source.description, fifo_out.description) self.comb += [ # bypass fifo_in.connect(self.router.sink0), self.router.source0.connect(fifo_out), # dram self.router.source1.connect(self.conv_w.sink), self.conv_w.source.connect(self.writer.sink), self.reader.source.connect(self.conv_r.sink), self.conv_r.source.connect(self.router.sink1), ]
def __init__(self, port_from, port_to, reverse=False): assert port_from.clock_domain == port_to.clock_domain assert port_from.data_width < port_to.data_width assert port_from.mode == port_to.mode assert port_from.mode == "read" if port_to.data_width % port_from.data_width: raise ValueError("Ratio must be an int") # # # ratio = port_to.data_width//port_from.data_width # cmd cmd_buffer = stream.SyncFIFO([("sel", ratio)], 4) self.submodules += cmd_buffer counter = Signal(max=ratio) counter_ce = Signal() self.sync += \ If(counter_ce, counter.eq(counter + 1) ) self.comb += \ If(port_from.cmd.valid, If(counter == 0, port_to.cmd.valid.eq(1), port_to.cmd.addr.eq(port_from.cmd.addr[log2_int(ratio):]), port_from.cmd.ready.eq(port_to.cmd.ready), counter_ce.eq(port_to.cmd.ready) ).Else( port_from.cmd.ready.eq(1), counter_ce.eq(1) ) ) # TODO: fix sel self.comb += \ If(port_to.cmd.valid & port_to.cmd.ready, cmd_buffer.sink.valid.eq(1), cmd_buffer.sink.sel.eq(2**ratio-1) ) # datapath rdata_buffer = stream.Buffer(port_to.rdata.description) rdata_converter = stream.StrideConverter( port_to.rdata.description, port_from.rdata.description, reverse=reverse) self.submodules += rdata_buffer, rdata_converter rdata_chunk = Signal(ratio, reset=1) rdata_chunk_valid = Signal() self.sync += \ If(rdata_converter.source.valid & rdata_converter.source.ready, rdata_chunk.eq(Cat(rdata_chunk[ratio-1], rdata_chunk[:ratio-1])) ) self.comb += [ port_to.rdata.connect(rdata_buffer.sink), rdata_buffer.source.connect(rdata_converter.sink), rdata_chunk_valid.eq((cmd_buffer.source.sel & rdata_chunk) != 0), If(port_from.flush, rdata_converter.source.ready.eq(1) ).Elif(cmd_buffer.source.valid, If(rdata_chunk_valid, port_from.rdata.valid.eq(rdata_converter.source.valid), port_from.rdata.data.eq(rdata_converter.source.data), rdata_converter.source.ready.eq(port_from.rdata.ready) ).Else( rdata_converter.source.ready.eq(1) ) ), cmd_buffer.source.ready.eq( rdata_converter.source.ready & rdata_chunk[ratio-1]) ]