def __init__(self, dram_port, hres=800, vres=600, base=0x00000000, fifo_depth=65536, clock_domain="sys", clock_faster_than_sys=False): self.vtg_sink = vtg_sink = stream.Endpoint(video_timing_layout) self.source = source = stream.Endpoint(video_data_layout) self.underflow = Signal() # # # # Video DMA. from litedram.frontend.dma import LiteDRAMDMAReader self.submodules.dma = LiteDRAMDMAReader(dram_port, fifo_depth=fifo_depth//(dram_port.data_width//8), fifo_buffered=True) self.dma.add_csr( default_base = base, default_length = hres*vres*32//8, # 32-bit RGB-444 default_enable = 0, default_loop = 1 ) # If DRAM Data Width > 32-bit and Video clock is faster than sys_clk: if (dram_port.data_width > 32) and clock_faster_than_sys: # Do Clock Domain Crossing first... self.submodules.cdc = stream.ClockDomainCrossing([("data", dram_port.data_width)], cd_from="sys", cd_to=clock_domain) self.comb += self.dma.source.connect(self.cdc.sink) # ... and then Data-Width Conversion. self.submodules.conv = stream.Converter(dram_port.data_width, 32) self.comb += self.cdc.source.connect(self.conv.sink) video_pipe_source = self.conv.source # Elsif DRAM Data Widt < 32-bit or Video clock is slower than sys_clk: else: # Do Data-Width Conversion first... self.submodules.conv = stream.Converter(dram_port.data_width, 32) self.comb += self.dma.source.connect(self.conv.sink) # ... and then Clock Domain Crossing. self.submodules.cdc = stream.ClockDomainCrossing([("data", 32)], cd_from="sys", cd_to=clock_domain) self.comb += self.conv.source.connect(self.cdc.sink) self.comb += If(dram_port.data_width < 32, # FIXME. self.cdc.sink.data[ 0: 8].eq(self.conv.source.data[16:24]), self.cdc.sink.data[16:24].eq(self.conv.source.data[ 0: 8]), ) video_pipe_source = self.cdc.source # Video Generation. self.comb += [ vtg_sink.ready.eq(1), If(vtg_sink.valid & vtg_sink.de, video_pipe_source.connect(source, keep={"valid", "ready"}), vtg_sink.ready.eq(source.valid & source.ready), ), vtg_sink.connect(source, keep={"de", "hsync", "vsync"}), source.r.eq(video_pipe_source.data[16:24]), source.g.eq(video_pipe_source.data[ 8:16]), source.b.eq(video_pipe_source.data[ 0: 8]), ] # Underflow. self.comb += self.underflow.eq(~source.valid)
def __init__(self, pads, mode="master"): self.refclk = Signal() # # # # In Master mode, generate the linerate/10 clock. Slave will re-multiply it. if mode == "master": converter = stream.Converter(40, 8) self.submodules += converter self.comb += [ converter.sink.valid.eq(1), converter.source.ready.eq(1), converter.sink.data.eq( Replicate(Signal(10, reset=0b1111100000), 4)), ] self.specials += [ Instance("OSERDESE3", p_DATA_WIDTH=8, p_INIT=0, p_IS_CLK_INVERTED=0, p_IS_CLKDIV_INVERTED=0, p_IS_RST_INVERTED=0, o_OQ=self.refclk, i_RST=ResetSignal("sys"), i_CLK=ClockSignal("sys4x"), i_CLKDIV=ClockSignal("sys"), i_D=converter.source.data), DifferentialOutput(self.refclk, pads.clk_p, pads.clk_n) ] # In Slave mode, multiply the clock provided by Master with a PLL/MMCM elif mode == "slave": self.specials += DifferentialInput(pads.clk_p, pads.clk_n, self.refclk)
def __init__(self, cmd=False, data=False, data_width=1, skip_start_bit=False): assert cmd or data self.pads_in = pads_in = stream.Endpoint(_sdpads_layout) self.source = source = stream.Endpoint([("data", 8)]) # # # pads_in_data = pads_in.cmd.i[: data_width] if cmd else pads_in.data.i[: data_width] print(len(pads_in_data)) # Xfer starts when data == 0 start = Signal() run = Signal() self.comb += start.eq(pads_in_data == 0) self.sync += If(pads_in.valid & pads_in.ready, run.eq(start | run)) # Convert data to 8-bit stream converter = stream.Converter(data_width, 8, reverse=True) buf = stream.Buffer([("data", 8)]) self.submodules += converter, buf self.comb += [ converter.sink.valid.eq(pads_in.valid & (run if skip_start_bit else (start | run))), converter.sink.data.eq(pads_in_data), pads_in.ready.eq(converter.sink.ready), converter.source.connect(buf.sink), buf.source.connect(source) ]
def __init__(self, pads, mode="master"): self.refclk = Signal() # # # # In Master mode, generate the linerate/10 clock. Slave will re-multiply it. if mode == "master": converter = stream.Converter(40, 8) self.submodules += converter self.comb += [ converter.sink.valid.eq(1), converter.source.ready.eq(1), converter.sink.data.eq(Replicate(Signal(10, reset=0b1111100000), 4)), ] self.specials += [ Instance("OSERDESE2", p_DATA_WIDTH=8, p_TRISTATE_WIDTH=1, p_DATA_RATE_OQ="DDR", p_DATA_RATE_TQ="BUF", p_SERDES_MODE="MASTER", o_OQ=self.refclk, i_OCE=1, i_RST=ResetSignal("sys"), i_CLK=ClockSignal("sys4x"), i_CLKDIV=ClockSignal("sys"), i_D1=converter.source.data[0], i_D2=converter.source.data[1], i_D3=converter.source.data[2], i_D4=converter.source.data[3], i_D5=converter.source.data[4], i_D6=converter.source.data[5], i_D7=converter.source.data[6], i_D8=converter.source.data[7] ), DifferentialOutput(self.refclk, pads.clk_p, pads.clk_n) ] # In Slave mode, multiply the clock provided by Master with a PLL/MMCM elif mode == "slave": self.specials += DifferentialInput(pads.clk_p, pads.clk_n, self.refclk)
def __init__(self, bus, endianness, fifo_depth=32): self.bus = bus self.sink = stream.Endpoint([("data", 8)]) # # # # Submodules fifo = stream.SyncFIFO([("data", 8)], fifo_depth) converter = stream.Converter(8, bus.data_width, reverse=True) self.submodules += fifo, converter self.submodules.dma = WishboneDMAWriter(bus, with_csr=True, endianness=endianness) # Flow start = Signal() connect = Signal() self.comb += start.eq(self.sink.valid & self.sink.first) self.sync += [ If(~self.dma._enable.storage, connect.eq(0)).Elif(start, connect.eq(1)) ] self.comb += [ If(self.dma._enable.storage & (start | connect), self.sink.connect(fifo.sink)).Else(self.sink.ready.eq(1)), fifo.source.connect(converter.sink), converter.source.connect(self.dma.sink), ]
def __init__(self, phy_dw, with_scrambling=True): self.bitslip_value = bitslip_value = Signal(6) self.sink = sink = stream.Endpoint([("data", phy_dw)]) self.source = source = stream.Endpoint([("data", 32)]) self.idle = idle = Signal() self.comma = comma = Signal() # # # # converter self.submodules.converter = converter = stream.Converter(phy_dw, 40) # bitslip self.submodules.bitslip = bitslip = _Bitslip() self.comb += bitslip.value.eq(bitslip_value) # line coding self.submodules.decoder = decoder = _8b10bDecoder() # descrambler if with_scrambling: self.submodules.descrambler = descrambler = Descrambler() # dataflow self.comb += [ sink.connect(converter.sink), converter.source.connect(bitslip.sink), bitslip.source.connect(decoder.sink) ] if with_scrambling: self.comb += [ decoder.source.connect(descrambler.sink), descrambler.source.connect(source) ] else: self.comb += [ decoder.source.connect(source, omit={"d", "k"}), source.data.eq(decoder.source.d) ] # idle decoding idle_timer = WaitTimer(32) self.submodules += idle_timer self.sync += [ If( converter.source.valid, idle_timer.wait.eq((converter.source.data == 0) | (converter.source.data == (2**40 - 1)))), idle.eq(idle_timer.done) ] # comma decoding self.sync += \ If(decoder.source.valid, comma.eq((decoder.source.k == 1) & (decoder.source.d == K(28, 5))) )
def __init__(self, dram_port, dw=32, fifo_depth=512): self.sink = stream.Endpoint([("data", dw)]) # # # DMA.__init__(self, "write", dram_port, fifo_depth) converter = stream.Converter(dw, dram_port.dw, reverse=False) self.submodules += converter self.comb += [ self.sink.connect(converter.sink), converter.source.connect(self.endpoint) ]
def __init__(self, phy_dw, with_scrambling=False): self.shift = shift = Signal(6) self.sink = sink = stream.Endpoint([("data", phy_dw)]) self.source = source = stream.Endpoint([("data", 32)]) self.idle = idle = Signal() self.comma = comma = Signal() # # # # Aligner self.submodules.aligner = aligner = RXAligner(phy_dw, shift) # Converter self.submodules.converter = converter = stream.Converter(phy_dw, 40) # Line Coding self.submodules.decoder = decoder = StreamDecoder(nwords=4) # Descrambler if with_scrambling: self.submodules.descrambler = descrambler = Descrambler() # Dataflow self.comb += [ sink.connect(aligner.sink), aligner.source.connect(converter.sink), converter.source.connect(decoder.sink), ] if with_scrambling: self.comb += decoder.source.connect(descrambler.sink) self.comb += descrambler.source.connect(source) else: self.comb += decoder.source.connect(source, omit={"d", "k"}) self.comb += source.data.eq(decoder.source.d) # Decode Idle idle_timer = WaitTimer(32) self.submodules += idle_timer self.sync += If( converter.source.valid, idle_timer.wait.eq((converter.source.data == 0) | (converter.source.data == (2**40 - 1)))) self.comb += idle.eq(idle_timer.done) # Decode Comma self.sync += If( decoder.source.valid, comma.eq((decoder.source.k == 1) & (decoder.source.d == K(28, 5))))
def __init__(self, dram_port, hres=800, vres=600, base=0x00000000, clock_domain="sys"): self.vtg_sink = vtg_sink = stream.Endpoint(video_timing_layout) self.source = source = stream.Endpoint(video_data_layout) # # # # Video DMA. from litedram.frontend.dma import LiteDRAMDMAReader self.submodules.dma = LiteDRAMDMAReader( dram_port, fifo_depth=2048, fifo_buffered=True) # FIXME: Adjust/Expose. self.dma.add_csr( default_base=base, default_length=hres * vres * 32 // 8, # 32-bit RGB-444 default_enable=0, default_loop=1) # FIXME: Make sure it will work for all DRAM's data-width/all Video resolutions. # Video Data-Width Converter. self.submodules.conv = stream.Converter(dram_port.data_width, 32) self.comb += self.dma.source.connect(self.conv.sink) # Video CDC. self.submodules.cdc = stream.ClockDomainCrossing([("data", 32)], cd_from="sys", cd_to=clock_domain) self.comb += self.conv.source.connect(self.cdc.sink) # Video Generation. self.comb += [ vtg_sink.ready.eq(1), If( vtg_sink.valid & vtg_sink.de, self.cdc.source.connect(source, keep={"valid", "ready"}), vtg_sink.ready.eq(source.valid & source.ready), ), vtg_sink.connect(source, keep={"de", "hsync", "vsync"}), source.r.eq(self.cdc.source.data[16:24]), source.g.eq(self.cdc.source.data[8:16]), source.b.eq(self.cdc.source.data[0:8]), ]
def __init__(self, phy_dw, with_scrambling=False): self.idle = idle = Signal() self.comma = comma = Signal() self.sink = sink = stream.Endpoint([("data", 32)]) self.source = source = stream.Endpoint([("data", phy_dw)]) # # # # Scrambler if with_scrambling: self.submodules.scrambler = scrambler = Scrambler() # Line coding self.submodules.encoder = encoder = StreamEncoder(nwords=4) # Converter self.submodules.converter = converter = stream.Converter(40, phy_dw) # Dataflow if with_scrambling: self.comb += sink.connect(scrambler.sink) self.comb += scrambler.source.connect(encoder.sink) else: self.comb += sink.connect(encoder.sink, omit={"data"}), self.comb += encoder.sink.d.eq(sink.data) self.comb += encoder.source.connect(converter.sink) self.comb += converter.source.connect(source) # Send K28.5 if comma asserted. self.comb += If( comma, sink.ready.eq(0), encoder.sink.valid.eq(1), encoder.sink.k.eq(0b1), encoder.sink.d.eq(K(28, 5)), ) # Send Idle if idle asserted. self.comb += If( idle, sink.ready.eq(0), converter.sink.valid.eq(1), converter.sink.data.eq(0), )
def __init__(self, bus, endianness, fifo_depth=32): self.source = stream.Endpoint([("data", 8)]) # # # # Submodules self.submodules.dma = WishboneDMAReader(bus, with_csr=True, endianness=endianness) converter = stream.Converter(bus.data_width, 8, reverse=True) fifo = stream.SyncFIFO([("data", 8)], fifo_depth) self.submodules += converter, fifo # Flow self.comb += [ self.dma.source.connect(converter.sink), converter.source.connect(fifo.sink), fifo.source.connect(self.source), ]
def __init__(self, dram_port): self.shoot = CSR() self.done = CSRStatus() self.base = CSRStorage(32) self.length = CSRStorage(32) self.source = source = stream.Endpoint([("data", 16)]) # # # self.submodules.dma = dma = LiteDRAMDMAReader(dram_port) fsm = FSM(reset_state="IDLE") self.submodules += fsm shift = log2_int(dram_port.dw // 8) base = Signal(dram_port.aw) length = Signal(dram_port.aw) offset = Signal(dram_port.aw) self.comb += [ base.eq(self.base.storage[shift:]), length.eq(self.length.storage[shift:]) ] fsm.act( "IDLE", self.done.status.eq(1), If(self.shoot.re & self.shoot.r, NextValue(offset, 0), NextState("RUN"))) fsm.act( "RUN", dma.sink.valid.eq(1), If(dma.sink.ready, NextValue(offset, offset + 1), If(offset == (length - 1), NextState("IDLE")))) self.comb += dma.sink.address.eq(base + offset) self.submodules.converter = stream.Converter(dram_port.dw, 16, reverse=True) self.comb += [ self.dma.source.connect(self.converter.sink), self.converter.source.connect(self.source) ]
def __init__(self, phy_dw, with_scrambling=True): self.idle = idle = Signal() self.comma = comma = Signal() self.sink = sink = stream.Endpoint([("data", 32)]) self.source = source = stream.Endpoint([("data", phy_dw)]) # # # # scrambler if with_scrambling: self.submodules.scrambler = scrambler = Scrambler() # line coding self.submodules.encoder = encoder = _8b10bEncoder() # converter self.submodules.converter = converter = stream.Converter(40, phy_dw) # dataflow if with_scrambling: self.comb += [ sink.connect(scrambler.sink), If(comma, encoder.sink.valid.eq(1), encoder.sink.k.eq(1), encoder.sink.d.eq(K(28, 5))).Else( scrambler.source.connect(encoder.sink)) ] else: self.comb += [ If(comma, encoder.sink.valid.eq(1), encoder.sink.k.eq(1), encoder.sink.d.eq(K(28, 5))).Else( sink.connect(encoder.sink, omit={"data"}), encoder.sink.d.eq(sink.data)), ] self.comb += [ If(idle, converter.sink.valid.eq(1), converter.sink.data.eq(0)).Else( encoder.source.connect(converter.sink), ), converter.source.connect(source) ]
def __init__(self, bus, port, endianness="little"): self.bus = bus self.port = port self.sector = CSRStorage(48) self.base = CSRStorage(64) self.start = CSR() self.done = CSRStatus() self.error = CSRStatus() # # # dma_bytes = bus.data_width // 8 port_bytes = port.dw // 8 count = Signal(max=logical_sector_size // min(dma_bytes, port_bytes)) # DMA dma = WishboneDMAReader(bus, with_csr=False, endianness=endianness) self.submodules.dma = dma # Sector buffer buf = stream.SyncFIFO([("data", port.dw)], logical_sector_size // dma_bytes) self.submodules.buf = buf # Converter conv = stream.Converter(nbits_from=bus.data_width, nbits_to=port.dw) self.submodules.conv = conv # Connect DMA to Sector Buffer self.comb += dma.source.connect(buf.sink) # Connect Sector Buffer to Converter self.comb += buf.source.connect(conv.sink) # Control FSM self.submodules.fsm = fsm = FSM(reset_state="IDLE") fsm.act( "IDLE", If(self.start.re, NextValue(count, 0), NextValue(self.error.status, 0), NextState("READ-DATA-DMA")).Else(self.done.status.eq(1)), conv.source.ready.eq(1)) fsm.act( "READ-DATA-DMA", # Read Sector data over DMA. dma.sink.valid.eq(1), dma.sink.address.eq(self.base.storage[int(log2(dma_bytes)):] + count), If( dma.sink.valid & dma.sink.ready, NextValue(count, count + 1), If(count == (logical_sector_size // dma_bytes - 1), NextValue(count, 0), NextState("SEND-CMD-AND-DATA")))) fsm.act( "SEND-CMD-AND-DATA", # Send write command/data for 1 Sector. port.sink.valid.eq(1), port.sink.last.eq(count == (logical_sector_size // port_bytes - 1)), port.sink.write.eq(1), port.sink.sector.eq(self.sector.storage), port.sink.count.eq(1), port.sink.data.eq(reverse_bytes(conv.source.data)), If(port.sink.ready, conv.source.ready.eq(1), NextValue(count, count + 1), If(port.sink.last, NextState("WAIT-ACK"))), # Monitor errors port.source.ready.eq(1), If( port.source.valid & port.source.ready, If( port.source.failed, NextValue(self.error.status, 1), NextState("IDLE"), ))) fsm.act( "WAIT-ACK", port.source.ready.eq(1), If(port.source.valid, If( port.source.failed, NextValue(self.error.status, 1), ), NextState("IDLE")))
def __init__(self, pads, sys_clk_freq, clock_domain="sys", clk_freq=148.5e6, refclk=None): assert sys_clk_freq >= clk_freq self.sink = sink = stream.Endpoint(video_data_layout) # # # from liteiclink.serdes.gtp_7series import GTPQuadPLL, GTP # Always ack Sink, no backpressure. self.comb += sink.ready.eq(1) # Clocking + Differential Signaling. pads_clk = Signal() self.specials += DDROutput(i1=1, i2=0, o=pads_clk, clk=ClockSignal(clock_domain)) self.specials += Instance("OBUFDS", i_I=pads_clk, o_O=pads.clk_p, o_OB=pads.clk_n) # GTP Quad PLL. if refclk is None: # No RefClk provided, use the Video Clk as GTP RefClk. refclk = ClockSignal(clock_domain) elif isinstance(refclk, Record): # Differential RefCLk provided, add an IBUFDS_GTE2. refclk_se = Signal() self.specials += Instance("IBUFDS_GTE2", i_CEB = 0, i_I = refclk.p, i_IB = refclk.n, o_O = refclk_se ) refclk = refclk_se self.submodules.pll = pll = GTPQuadPLL(refclk, clk_freq, 1.485e9) # Encode/Serialize Datas. for color in ["r", "g", "b"]: # TMDS Encoding. encoder = ClockDomainsRenamer(clock_domain)(TMDSEncoder()) self.submodules += encoder self.comb += encoder.d.eq(getattr(sink, color)) self.comb += encoder.c.eq(Cat(sink.hsync, sink.vsync) if color == "r" else 0) self.comb += encoder.de.eq(sink.de) # 10:20 (SerDes has a minimal 20:1 Serialization ratio). converter = ClockDomainsRenamer(clock_domain)(stream.Converter(10, 20)) self.submodules += converter self.comb += converter.sink.valid.eq(1) self.comb += converter.sink.data.eq(encoder.out) # Clock Domain Crossing (video_clk --> gtp_tx) cdc = stream.ClockDomainCrossing([("data", 20)], cd_from=clock_domain, cd_to=f"gtp{color}_tx") self.submodules += cdc self.comb += converter.source.connect(cdc.sink) self.comb += cdc.source.ready.eq(1) # No backpressure. # 20:1 Serialization + Differential Signaling. c2d = {"r": 2, "g": 1, "b": 0} class GTPPads: def __init__(self, p, n): self.p = p self.n = n tx_pads = GTPPads(p=getattr(pads, f"data{c2d[color]}_p"), n=getattr(pads, f"data{c2d[color]}_n")) # FIXME: Find a way to avoid RX pads. rx_pads = GTPPads(p=getattr(pads, f"rx{c2d[color]}_p"), n=getattr(pads, f"rx{c2d[color]}_n")) gtp = GTP(pll, tx_pads, rx_pads=rx_pads, sys_clk_freq=sys_clk_freq, tx_polarity = 1, # FIXME: Specific to Decklink Mini 4K, make it configurable. tx_buffer_enable = True, rx_buffer_enable = True, clock_aligner = False ) setattr(self.submodules, f"gtp{color}", gtp) self.comb += gtp.tx_produce_pattern.eq(1) self.comb += gtp.tx_pattern.eq(cdc.source.data)
def __init__(self, ddr_wr_port, ddr_rd_port, udp_port, adc_source, adc_dw): SIZE = 1024 * 1024 self.fifo_full = CSRStatus(reset=0) self.fifo_error = CSRStatus(reset=0) self.fifo_load = CSRStorage(reset=0) self.fifo_read = CSRStorage(reset=0) self.fifo_size = CSRStorage(32, reset=SIZE) self.dst_ip = CSRStorage(32, reset=convert_ip("192.168.1.114")) self.dst_port = CSRStorage(16, reset=7778) self.fifo_counter = fifo_counter = Signal(24) self.load_fifo = load_fifo = Signal() dw = ddr_wr_port.data_width print( f"Write port: A ({ddr_wr_port.address_width})/ D ({ddr_wr_port.data_width})" ) print( f"Read port: A ({ddr_rd_port.address_width})/ D ({ddr_rd_port.data_width})" ) print(f"dw: {dw}; adc_dw: {adc_dw}") self.submodules.dram_fifo = dram_fifo = LiteDRAMFIFO( data_width=dw, base=0, depth=SIZE * (dw // 8), # liteDRAM expects this in bytes write_port=ddr_wr_port, read_port=ddr_rd_port, ) self.adc_data = adc_data = Signal(dw) DW_RATIO = dw // adc_dw log_dw_ratio = log2_int(DW_RATIO) word_count = Signal(log_dw_ratio) word_count_d = Signal(log_dw_ratio) self.sync += [ If(adc_source.valid, adc_data.eq(Cat(adc_data[adc_dw:], adc_source.data)), word_count.eq(word_count + 1)), word_count_d.eq(word_count), ] self.comb += [ dram_fifo.sink.valid.eq((word_count == 0) & (word_count_d != 0) & load_fifo), dram_fifo.sink.data.eq(adc_data) ] fifo_size = Signal(32) self.sync += [ fifo_size.eq(self.fifo_size.storage), If(self.fifo_load.re & self.fifo_load.storage, fifo_counter.eq(0), load_fifo.eq(1)), If(load_fifo & adc_source.valid, self.fifo_full.status.eq(0), self.fifo_error.status.eq(~dram_fifo.dram_fifo.ctrl.writable), fifo_counter.eq(fifo_counter + 1)), If((fifo_counter == fifo_size - 1) & adc_source.valid, load_fifo.eq(0), self.fifo_full.status.eq(1)), ] # fifo --> stride converter self.submodules.stride_converter = sc = stream.Converter( dw, udp_port.dw) self.read_from_dram_fifo = read_from_dram_fifo = Signal() self.comb += [dram_fifo.source.connect(sc.sink)] self.receive_count = receive_count = Signal(24) self.sync += [ If(dram_fifo.source.valid & dram_fifo.source.ready, receive_count.eq(receive_count + 1)).Elif( read_from_dram_fifo == 0, receive_count.eq(0)) ] # --> udp fragmenter --> self.submodules.udp_fragmenter = udp_fragmenter = UDPFragmenter( udp_port.dw) self.sync += read_from_dram_fifo.eq(self.fifo_read.storage) self.comb += If( read_from_dram_fifo, # TODO: There is a bug somewhere in the converter, # its source.last somehow gets set, no idea why. That signal is of no real use # for the fragmenter anyways, so we live without it sc.source.connect(udp_fragmenter.sink, omit={'total_size', 'last'})) # TODO: 8 should be adcstream data width // 8 self.comb += udp_fragmenter.sink.length.eq( fifo_size << log2_int(adc_dw // 8)) self.comb += udp_fragmenter.source.connect(udp_port.sink) self.comb += [ # param udp_port.sink.src_port.eq(4321), udp_port.sink.dst_port.eq(self.dst_port.storage), udp_port.sink.ip_address.eq(self.dst_ip.storage), # udp_port.sink.ip_address.eq(convert_ip("192.168.88.101")), # payload udp_port.sink.error.eq(0) ]
def __init__(self, ddr_wr_port, ddr_rd_port, udp_port): SIZE = 1024 * 1024 SIZE = 1024 self.fifo_full = CSRStatus(reset=0) self.fifo_error = CSRStatus(reset=0) self.fifo_load = CSRStorage( reset=0) # Load the coefficients in memory to the ROI Summer self.fifo_read = CSRStorage(reset=0) self.fifo_size = CSRStorage(32, reset=SIZE) self.dst_ip = CSRStorage(32, reset=convert_ip("192.168.1.114")) self.dst_port = CSRStorage(16, reset=7778) dw = 64 print( f"Write port: A ({ddr_wr_port.address_width})/ D ({ddr_wr_port.data_width})" ) print( f"Read port: A ({ddr_rd_port.address_width})/ D ({ddr_rd_port.data_width})" ) self.submodules.dram_fifo = dram_fifo = LiteDRAMFIFO( data_width=dw, base=0, depth=SIZE, write_port=ddr_wr_port, read_port=ddr_rd_port, with_bypass=True, ) # self.mf = mf = Signal(reset=0) # mf == More Fragments # self.fragment_offset = fragment_offset = Signal(13, reset=0) # self.identification = identification = Signal(16, reset=0) self.submodules.adcs = adcs = ADCStream(1, dw) self.fifo_counter = fifo_counter = Signal(24) self.load_fifo = load_fifo = Signal() # adc --> buffer_fifo self.submodules.buffer_fifo = buffer_fifo = stream.SyncFIFO( stream.EndpointDescription([("data", dw)]), 256, buffered=True) # buffer_fifo --> dram_fifo fifo_size = Signal(32) self.sync += [ fifo_size.eq(self.fifo_size.storage), If(self.fifo_load.re & self.fifo_load.storage, fifo_counter.eq(0), load_fifo.eq(1)), If(load_fifo & adcs.source.valid, self.fifo_full.status.eq(0), self.fifo_error.status.eq(~dram_fifo.dram_fifo.ctrl.writable), fifo_counter.eq(fifo_counter + 1)), If((fifo_counter == fifo_size - 1) & adcs.source.valid, load_fifo.eq(0), self.fifo_full.status.eq(1)), ] self.comb += [ buffer_fifo.sink.data.eq(adcs.source.data), buffer_fifo.sink.valid.eq(adcs.source.valid & load_fifo), buffer_fifo.source.connect(dram_fifo.sink), ] # fifo --> stride converter self.submodules.stride_converter = sc = stream.Converter( dw, udp_port.dw) self.read_from_dram_fifo = read_from_dram_fifo = Signal() self.comb += [dram_fifo.source.connect(sc.sink)] self.receive_count = receive_count = Signal(24) self.sync += [ If(dram_fifo.source.valid & dram_fifo.source.ready, receive_count.eq(receive_count + 1)).Elif( read_from_dram_fifo == 0, receive_count.eq(0)) ] # --> udp fragmenter --> self.submodules.udp_fragmenter = udp_fragmenter = UDPFragmenter( udp_port.dw) self.sync += read_from_dram_fifo.eq(self.fifo_read.storage) self.comb += If( read_from_dram_fifo, # TODO: There is a bug somewhere in the converter, # its source.last somehow gets set, no idea why. That signal is of no real use # for the fragmenter anyways, so we live without it sc.source.connect(udp_fragmenter.sink, omit={'total_size', 'last'})) # TODO: 8 should be adcstream data width // 8 self.comb += udp_fragmenter.sink.length.eq(fifo_size << log2_int(dw // 8)) self.comb += udp_fragmenter.source.connect(udp_port.sink) self.comb += [ # param udp_port.sink.src_port.eq(4321), udp_port.sink.dst_port.eq(self.dst_port.storage), udp_port.sink.ip_address.eq(self.dst_ip.storage), # udp_port.sink.ip_address.eq(convert_ip("192.168.88.101")), # payload udp_port.sink.error.eq(0) ] # debug self.first_sample, self.last_sample = Signal(16), Signal(16) self.sync += [ If(fifo_counter == 1, self.first_sample.eq(adcs.source.data[:16])), If(fifo_counter == SIZE - 2, self.last_sample.eq(adcs.source.data[:16])), ]
def __init__(self, dram_port, hres=800, vres=600, base=0x00000000, fifo_depth=65536, clock_domain="sys", clock_faster_than_sys=False, format="rgb888"): self.vtg_sink = vtg_sink = stream.Endpoint(video_timing_layout) self.source = source = stream.Endpoint(video_data_layout) self.underflow = Signal() self.depth = depth = { "rgb888" : 32, "rgb565" : 16 }[format] # # # # Video DMA. from litedram.frontend.dma import LiteDRAMDMAReader self.submodules.dma = LiteDRAMDMAReader(dram_port, fifo_depth=fifo_depth//(dram_port.data_width//8), fifo_buffered=True) self.dma.add_csr( default_base = base, default_length = hres*vres*depth//8, # 32-bit RGB-888 or 16-bit RGB-565 default_enable = 0, default_loop = 1 ) # If DRAM Data Width > depth and Video clock is faster than sys_clk: if (dram_port.data_width > depth) and clock_faster_than_sys: # Do Clock Domain Crossing first... self.submodules.cdc = stream.ClockDomainCrossing([("data", dram_port.data_width)], cd_from="sys", cd_to=clock_domain) self.comb += self.dma.source.connect(self.cdc.sink) # ... and then Data-Width Conversion. self.submodules.conv = ClockDomainsRenamer(clock_domain)(stream.Converter(dram_port.data_width, depth)) self.comb += self.cdc.source.connect(self.conv.sink) video_pipe_source = self.conv.source # Elsif DRAM Data Width <= depth or Video clock is slower than sys_clk: else: # Do Data-Width Conversion first... self.submodules.conv = stream.Converter(dram_port.data_width, depth) self.comb += self.dma.source.connect(self.conv.sink) # ... and then Clock Domain Crossing. self.submodules.cdc = stream.ClockDomainCrossing([("data", depth)], cd_from="sys", cd_to=clock_domain) self.comb += self.conv.source.connect(self.cdc.sink) if (dram_port.data_width < depth) and (depth == 32): # FIXME. self.comb += [ self.cdc.sink.data[ 0: 8].eq(self.conv.source.data[16:24]), self.cdc.sink.data[16:24].eq(self.conv.source.data[ 0: 8]), ] video_pipe_source = self.cdc.source # Video Generation. self.comb += [ vtg_sink.ready.eq(1), If(vtg_sink.valid & vtg_sink.de, video_pipe_source.connect(source, keep={"valid", "ready"}), vtg_sink.ready.eq(source.valid & source.ready), ), vtg_sink.connect(source, keep={"de", "hsync", "vsync"}), ] if (depth == 32): self.comb += [ source.r.eq(video_pipe_source.data[16:24]), source.g.eq(video_pipe_source.data[ 8:16]), source.b.eq(video_pipe_source.data[ 0: 8]), ] else: # depth == 16 self.comb += [ source.r.eq(Cat(Signal(3, reset = 0), video_pipe_source.data[ 0: 5])), source.g.eq(Cat(Signal(2, reset = 0), video_pipe_source.data[ 5:11])), source.b.eq(Cat(Signal(3, reset = 0), video_pipe_source.data[11:16])), ] # Underflow. self.comb += self.underflow.eq(~source.valid)
def __init__(self, platform, with_hdmi_in=False): sys_clk_freq = int(81e6) # SoCSDRAM --------------------------------------------------------------------------------- SoCSDRAM.__init__(self, platform, clk_freq=sys_clk_freq, integrated_rom_size=0x8000) # CRG -------------------------------------------------------------------------------------- self.submodules.crg = _CRG(platform, sys_clk_freq) # DDR3 SDRAM ------------------------------------------------------------------------------- if not self.integrated_main_ram_size: self.submodules.ddrphy = ECP5DDRPHY(platform.request("ddram"), sys_clk_freq=sys_clk_freq) self.add_csr("ddrphy") self.add_constant("ECP5DDRPHY", None) self.comb += self.crg.stop.eq(self.ddrphy.init.stop) sdram_module = MT41K64M16(sys_clk_freq, "1:2") self.register_sdram(self.ddrphy, geom_settings=sdram_module.geom_settings, timing_settings=sdram_module.timing_settings) # HDMI In ---------------------------------------------------------------------------------- if with_hdmi_in: from litedram.frontend.fifo import LiteDRAMFIFO hdmi_layout = [("de", 1), ("hsync", 1), ("vsync", 1), ("r", 8), ("g", 8), ("b", 8)] hdmi_pads = platform.request("hdmi_in") self.clock_domains.cd_hdmi = ClockDomain() self.comb += self.cd_hdmi.clk.eq(hdmi_pads.pclk) # FIXME: Check hdmi_clk freq vs sys_clk freq cdc = stream.AsyncFIFO(hdmi_layout, 4) cdc = ClockDomainsRenamer({"write": "hdmi", "read": "sys"})(cdc) converter = stream.Converter(32, 128) self.submodules += cdc, converter fifo_base = 0x00100000 # FIXME: Add control fifo_depth = 0x00100000 # FIXME: Add control fifo = LiteDRAMFIFO( data_width=128, base=fifo_base, depth=fifo_depth, write_port=self.sdram.crossbar.get_port(mode="write"), write_threshold=fifo_depth - 32, read_port=self.sdram.crossbar.get_port(mode="read"), read_threshold=32) self.submodules += fifo self.sync.hdmi += [ cdc.sink.valid.eq(1), # FIXME: Add control cdc.sink.de.eq(hdmi_pads.de), cdc.sink.hsync.eq(hdmi_pads.hsync), cdc.sink.vsync.eq(hdmi_pads.vsync), cdc.sink.r.eq(hdmi_pads.r), cdc.sink.g.eq(hdmi_pads.g), cdc.sink.b.eq(hdmi_pads.b), ] self.comb += cdc.source.connect(converter.sink, keep={"valid", "ready"}) self.comb += converter.sink.data.eq(cdc.source.payload.raw_bits()) self.comb += converter.source.connect(fifo.sink) self.comb += fifo.source.ready.eq( 1) # FIXME: to FX3, always ready for now
def __init__(self, port, bus, endianness="little"): self.port = port self.bus = bus self.sector = CSRStorage(48) self.base = CSRStorage(64) self.start = CSR() self.done = CSRStatus() self.error = CSRStatus() # # # port_bytes = port.dw // 8 dma_bytes = bus.data_width // 8 count = Signal(max=logical_sector_size // dma_bytes) # Sector buffer buf = stream.SyncFIFO([("data", port.dw)], logical_sector_size // port_bytes) self.submodules.buf = buf # Converter conv = stream.Converter(nbits_from=port.dw, nbits_to=bus.data_width) self.submodules.conv = conv # Connect Port to Sector Buffer self.comb += port.source.connect( buf.sink, keep={"valid", "ready", "last", "data"}) # Connect Sector Buffer to Converter self.comb += buf.source.connect(conv.sink) # DMA dma = WishboneDMAWriter(bus, with_csr=False, endianness=endianness) self.submodules.dma = dma # Control FSM self.submodules.fsm = fsm = FSM(reset_state="IDLE") fsm.act( "IDLE", If(self.start.re, NextValue(count, 0), NextValue(self.error.status, 0), NextState("SEND-CMD")).Else(self.done.status.eq(1)), conv.source.ready.eq(1)) fsm.act( "SEND-CMD", # Send read command for 1 Sector. port.sink.valid.eq(1), port.sink.last.eq(1), port.sink.read.eq(1), port.sink.sector.eq(self.sector.storage), port.sink.count.eq(1), If(port.sink.ready, NextState("RECEIVE-DATA-DMA"))) fsm.act( "RECEIVE-DATA-DMA", # Connect Converter to DMA. dma.sink.valid.eq(conv.source.valid), dma.sink.last.eq(conv.source.last), dma.sink.address.eq(self.base.storage[int(log2(dma_bytes)):] + count), dma.sink.data.eq(reverse_bytes(conv.source.data)), conv.source.ready.eq(dma.sink.ready), If(dma.sink.valid & dma.sink.ready, NextValue(count, count + 1), If(dma.sink.last, NextState("IDLE"))), # Monitor errors If( port.source.valid & port.source.ready, If( port.source.failed, NextValue(self.error.status, 1), NextState("IDLE"), )))
def __init__(self, dram_port, upd_clut_fifo=None, hres=800, vres=600, base=0x00000000, fifo_depth=65536, clock_domain="sys", clock_faster_than_sys=False, hwcursor=False, upd_overlay_fifo=False, upd_omap_fifo=False): clut = Array( Array(Signal(8, reset=(255 - i)) for i in range(0, 256)) for j in range(0, 3)) upd_clut_fifo_dout = Record(cmap_layout) self.comb += upd_clut_fifo_dout.raw_bits().eq(upd_clut_fifo.dout) if (hwcursor): upd_omap_fifo_dout = Record(omap_layout) self.comb += upd_omap_fifo_dout.raw_bits().eq(upd_omap_fifo.dout) print( f"FRAMEBUFFER: dram_port.data_width = {dram_port.data_width}, {hres}x{vres}, 0x{base:x}, in {clock_domain}, clock_faster_than_sys={clock_faster_than_sys}" ) vga_sync = getattr(self.sync, clock_domain) vga_sync += [ If( upd_clut_fifo.readable, upd_clut_fifo.re.eq(1), clut[upd_clut_fifo_dout.color][upd_clut_fifo_dout.address].eq( upd_clut_fifo_dout.data), ).Else(upd_clut_fifo.re.eq(0), ) ] if (hwcursor): self.vtg_sink = vtg_sink = stream.Endpoint( video_timing_hwcursor_layout) overlay = Array( Array( Array(Signal(1) for x in range(0, 32)) for y in range(0, 32)) for i in range(0, 2)) omap = Array( Array(Signal(8, reset=(255 - i)) for i in range(0, 4)) for j in range(0, 3)) vga_sync += [ If( upd_overlay_fifo.readable, upd_overlay_fifo.re.eq(1), [ overlay[upd_overlay_fifo.dout[0]][ upd_overlay_fifo.dout[1:6]][x].eq( upd_overlay_fifo.dout[6 + x]) for x in range(0, 32) ], ).Else(upd_overlay_fifo.re.eq(0), ) ] vga_sync += [ If( upd_omap_fifo.readable, upd_omap_fifo.re.eq(1), omap[upd_omap_fifo_dout.color] [upd_omap_fifo_dout.address].eq(upd_omap_fifo_dout.data), ).Else(upd_omap_fifo.re.eq(0), ) ] else: self.vtg_sink = vtg_sink = stream.Endpoint(video_timing_layout) self.source = source = stream.Endpoint(video_data_layout) self.underflow = Signal() #source_buf_ready = Signal() source_buf_valid = Signal() source_buf_de = Signal() source_buf_hsync = Signal() source_buf_vsync = Signal() data_buf = Signal(8) if (hwcursor): hwcursor_buf = Signal() hwcursorx_buf = Signal(5) hwcursory_buf = Signal(5) #source_out_ready = Signal() source_out_valid = Signal() source_out_de = Signal() source_out_hsync = Signal() source_out_vsync = Signal() source_out_r = Signal(8) source_out_g = Signal(8) source_out_b = Signal(8) # # # # Video DMA. from litedram.frontend.dma import LiteDRAMDMAReader self.submodules.dma = LiteDRAMDMAReader(dram_port, fifo_depth=fifo_depth // (dram_port.data_width // 8), fifo_buffered=True) self.dma.add_csr( default_base=base, default_length=hres * vres * 8 // 8, # 8-bit PseudoColor default_enable=0, default_loop=1) # If DRAM Data Width > 8-bit and Video clock is faster than sys_clk: if (dram_port.data_width > 8) and clock_faster_than_sys: # Do Clock Domain Crossing first... self.submodules.cdc = stream.ClockDomainCrossing( [("data", dram_port.data_width)], cd_from="sys", cd_to=clock_domain) self.comb += self.dma.source.connect(self.cdc.sink) # ... and then Data-Width Conversion. self.submodules.conv = ClockDomainsRenamer({"sys": clock_domain})( stream.Converter(dram_port.data_width, 8)) self.comb += self.cdc.source.connect(self.conv.sink) video_pipe_source = self.conv.source # Elsif DRAM Data Widt < 8-bit or Video clock is slower than sys_clk: else: # Do Data-Width Conversion first... self.submodules.conv = stream.Converter(dram_port.data_width, 8) self.comb += self.dma.source.connect(self.conv.sink) # ... and then Clock Domain Crossing. self.submodules.cdc = stream.ClockDomainCrossing( [("data", 8)], cd_from="sys", cd_to=clock_domain) self.comb += self.conv.source.connect(self.cdc.sink) video_pipe_source = self.cdc.source # Video Generation. self.comb += [ vtg_sink.ready.eq(1), If( vtg_sink.valid & vtg_sink.de, source_buf_valid.eq(video_pipe_source.valid), #video_pipe_source.ready.eq(source_buf_ready),# ready flow the other way video_pipe_source.connect( source, keep={"ready"} ), # source.ready is set to 1 by the sink anyway, bypass the cycle delay #vtg_sink.ready.eq(source_buf_valid & source_buf_ready), vtg_sink.ready.eq(source_buf_valid & source.ready), ), source_buf_de.eq(vtg_sink.de), source_buf_hsync.eq(vtg_sink.hsync), source_buf_vsync.eq(vtg_sink.vsync), data_buf.eq(video_pipe_source.data), ] if (hwcursor): self.comb += [ hwcursor_buf.eq(vtg_sink.hwcursor), hwcursorx_buf.eq(vtg_sink.hwcursorx), hwcursory_buf.eq(vtg_sink.hwcursory), ] if (hwcursor): source_mid_valid = Signal() source_mid_de = Signal() source_mid_hsync = Signal() source_mid_vsync = Signal() data_mid = Signal(8) hwcursor_color_idx = Signal(2) # first cycle, buffer everything and look up the cursor overlay color vga_sync += [ source_mid_de.eq(source_buf_de), source_mid_hsync.eq(source_buf_hsync), source_mid_vsync.eq(source_buf_vsync), source_mid_valid.eq(source_buf_valid), data_mid.eq(data_buf), If( hwcursor_buf, hwcursor_color_idx.eq( Cat(overlay[0][hwcursory_buf][hwcursorx_buf], overlay[1][hwcursory_buf][hwcursorx_buf])), ).Else(hwcursor_color_idx.eq(0), ) ] #second cycle, produce the pixel by doing CLUT lookup vga_sync += [ source_out_de.eq(source_mid_de), source_out_hsync.eq(source_mid_hsync), source_out_vsync.eq(source_mid_vsync), source_out_valid.eq(source_mid_valid), #source_buf_ready.eq(source_out_ready), # ready flow the other way If( hwcursor_color_idx != 0, source_out_r.eq(omap[0][hwcursor_color_idx]), source_out_g.eq(omap[1][hwcursor_color_idx]), source_out_b.eq(omap[2][hwcursor_color_idx]), ).Elif(source_mid_de, source_out_r.eq(clut[0][data_mid]), source_out_g.eq(clut[1][data_mid]), source_out_b.eq(clut[2][data_mid])).Else( source_out_r.eq(0), source_out_g.eq(0), source_out_b.eq(0)) ] else: vga_sync += [ source_out_de.eq(source_buf_de), source_out_hsync.eq(source_buf_hsync), source_out_vsync.eq(source_buf_vsync), source_out_valid.eq(source_buf_valid), #source_buf_ready.eq(source_out_ready), # ready flow the other way If(source_buf_de, source_out_r.eq(clut[0][data_buf]), source_out_g.eq(clut[1][data_buf]), source_out_b.eq(clut[2][data_buf])).Else( source_out_r.eq(0), source_out_g.eq(0), source_out_b.eq(0)) ] self.comb += [ source.de.eq(source_out_de), source.hsync.eq(source_out_hsync), source.vsync.eq(source_out_vsync), source.valid.eq(source_out_valid), #source_out_ready.eq(source.ready), # ready flow the other way source.r.eq(source_out_r), source.g.eq(source_out_g), source.b.eq(source_out_b), ] # Underflow. self.comb += self.underflow.eq(~source.valid)
def __init__(self, endpoint, data_width=32, id_width=1): self.axi = axi.AXIInterface(data_width=data_width, id_width=id_width) # # # aw_id = Signal(id_width) ar_id = Signal(id_width) r_len = Signal(8) desc_rd = stream.Endpoint(descriptor_layout()) desc_wr = stream.Endpoint(descriptor_layout()) port_rd = endpoint.crossbar.get_master_port(read_only=True) port_wr = endpoint.crossbar.get_master_port(write_only=True) # AXI Write Path --------------------------------------------------------------------------- # DMA / FIFO / Converter self.submodules.dma_wr = dma_wr = LitePCIeDMAWriter(endpoint=endpoint, port=port_wr, with_table=False) self.submodules.fifo_wr = fifo_wr = stream.SyncFIFO( descriptor_layout(), 16) self.submodules.conv_wr = conv_wr = stream.Converter( nbits_from=data_width, nbits_to=endpoint.phy.data_width) # Flow self.comb += [ desc_wr.connect(fifo_wr.sink), fifo_wr.source.connect(dma_wr.desc_sink), conv_wr.source.connect(dma_wr.sink), ] # FSM (Convert AXI Write Requests to LitePCIe's DMA Descriptors). self.comb += desc_wr.address.eq( self.axi.aw.addr) # Start address (byte addressed) self.comb += desc_wr.length.eq( (self.axi.aw.len + 1) * (data_width // 8)) # Transfer length (in bytes) self.submodules.fsm_wr = fsm_wr = FSM(reset_state="WRITE-IDLE") fsm_wr.act( "WRITE-IDLE", self.axi.aw.ready.eq(desc_wr.ready), desc_wr.valid.eq(self.axi.aw.valid), If( self.axi.aw.valid & self.axi.aw.ready, NextValue(aw_id, self.axi.aw.id), # Save id to use it on b channel. NextState("WRITE-MONITOR"), )) self.comb += [ conv_wr.sink.data.eq(self.axi.w.data), conv_wr.sink.last.eq(self.axi.w.last), ] fsm_wr.act( "WRITE-MONITOR", conv_wr.sink.valid.eq(self.axi.w.valid), self.axi.w.ready.eq(conv_wr.sink.ready), If( self.axi.w.valid & self.axi.w.ready & self.axi.w.last, NextState("WRITE-RESP"), )) self.comb += [ self.axi.b.id.eq(aw_id), self.axi.b.resp.eq(0), ] fsm_wr.act( "WRITE-RESP", self.axi.b.valid.eq(1), If( self.axi.b.ready, NextState("WRITE-IDLE"), # Write done )) # AXI Read Path ---------------------------------------------------------------------------- # DMA / FIFO / Converter self.submodules.dma_rd = dma_rd = LitePCIeDMAReader(endpoint=endpoint, port=port_rd, with_table=False) self.submodules.fifo_rd = fifo_rd = stream.SyncFIFO( descriptor_layout(), 16) self.submodules.conv_rd = conv_rd = stream.Converter( nbits_from=endpoint.phy.data_width, nbits_to=data_width) # Flow self.comb += [ desc_rd.connect(fifo_rd.sink), fifo_rd.source.connect(dma_rd.desc_sink), dma_rd.source.connect(conv_rd.sink), ] # FSM (Convert AXI Read Requests to LitePCIe's DMA Descriptors). self.comb += desc_rd.address.eq( self.axi.ar.addr) # Starting address (byte addressed) self.comb += desc_rd.length.eq( (self.axi.ar.len + 1) * (data_width // 8)) # Transfer length (in bytes) self.submodules.fsm_rd = fsm_rd = FSM(reset_state="READ-IDLE") fsm_rd.act( "READ-IDLE", self.axi.ar.ready.eq(desc_rd.ready), desc_rd.valid.eq(self.axi.ar.valid), If( self.axi.ar.valid & self.axi.ar.ready, NextValue(ar_id, self.axi.ar.id), # Save id to use it on r channel. NextValue(r_len, self.axi.ar.len), NextState("READ-MONITOR"), )) self.comb += [ self.axi.r.data.eq(conv_rd.source.data), self.axi.r.last.eq(r_len == 0), # We need to provide the same id that was provided on aw channel for the duration of the transfer. self.axi.r.id.eq(ar_id), self.axi.r.resp.eq(0), ] fsm_rd.act( "READ-MONITOR", self.axi.r.valid.eq(conv_rd.source.valid), conv_rd.source.ready.eq(self.axi.r.ready), If( self.axi.r.ready & self.axi.r.valid, NextValue(r_len, r_len - 1), If( self.axi.r. last, # Check if we finished the whole AXI transaction. NextState("READ-IDLE"), )))