def elaborate(self, platform): m = Module() sink = StreamEndpoint.like(self.input_stream, is_sink=True, name="ft601_sink") m.d.comb += sink.connect(self.input_stream) ft = self.ft_601_resource m.d.comb += ft.be.oe.eq(1) m.d.comb += ft.be.o.eq(0b1111) # everything we write is valid m.d.comb += ft.oe.eq(0) # we are driving the data bits all the time m.d.comb += ft.data.oe.eq(1) m.d.comb += platform.request("led", 0).eq(ft.write) if self.safe_to_begin_new_transaction is None: m.d.comb += ft.data.o.eq(sink.payload) m.d.comb += sink.ready.eq(ft.txe) m.d.comb += ft.write.eq(sink.valid) else: in_transaction = Signal() m.d.sync += in_transaction.eq(ft.write) with m.If(in_transaction): m.d.comb += ft.write.eq(sink.valid & ft.txe) m.d.comb += sink.ready.eq(ft.txe) with m.Else(): m.d.comb += ft.write.eq(sink.valid & self.safe_to_begin_new_transaction) m.d.comb += sink.ready.eq(ft.txe & self.safe_to_begin_new_transaction) m.d.comb += ft.data.o.eq(sink.payload) return m
def elaborate(self, platform: ZynqSocPlatform): m = Module() platform.ps7.fck_domain(requested_frequency=200e6) m.d.comb += ResetSignal().eq(self.reset) ring_buffer = RingBufferAddressStorage(buffer_size=0x1200000, n=4) stream_source = StreamEndpoint(64, is_sink=False, has_last=True) m.d.comb += self.data_ready.eq(stream_source.ready) m.d.comb += stream_source.valid.eq(self.data_valid) clock_signal = Signal() m.d.comb += clock_signal.eq(ClockSignal()) axi_slave = platform.ps7.get_axi_hp_slave(clock_signal) axi_writer = m.submodules.axi_writer = AxiBufferWriter(ring_buffer, stream_source, axi_slave=axi_slave) with m.If(axi_writer.stream_source.ready & axi_writer.stream_source.valid): m.d.sync += self.data_counter.eq(self.data_counter + 1) m.d.comb += stream_source.payload.eq(Cat(self.data_counter, self.data_counter+1000)) with m.If((stream_source.valid) & (axi_writer.words_written < (self.to_write >> int(math.log2(axi_slave.data_bytes))))): m.d.sync += self.perf_counter.eq(self.perf_counter+1) return m
def elaborate(self, platform): m = Module() sink = StreamEndpoint.like(self.input, is_sink=True, name="plugin_module_streamer_sink") m.d.comb += sink.connect(self.input) m.d.comb += self.plugin_lvds.valid.eq(sink.valid & ~self.do_training) m.d.comb += sink.ready.eq(1) m.d.comb += self.plugin_lvds.clk_word.eq(ClockSignal()) for i in range(4): value = Signal() m.submodules["lane{}".format(i)] = DDRSerializer( self.plugin_lvds["lvds{}".format(i)], value, ddr_clockdomain=self.bitclk_domain) with m.If(self.plugin_lvds.valid): m.d.comb += value.eq(sink.payload[0 + (i * 8):8 + (i * 8)]) with m.Else(): m.d.comb += value.eq(self.training_pattern) return m
def test_buffer_change(self, data_len=50): axi = AxiEndpoint(addr_bits=32, data_bits=64, master=False, lite=False, id_bits=12) ringbuffer = RingBufferAddressStorage(0x1000, 2, base_address=0) stream_source = StreamEndpoint(64, is_sink=False, has_last=True) dut = AxiBufferWriter(ringbuffer, stream_source, axi, fifo_depth=data_len) def testbench(): gold = {} gold_gen = { "current_buffer": 0, "current_address": ringbuffer.buffer_base_list[0] } def change_buffer(): gold_gen["current_buffer"] = (gold_gen["current_buffer"] + 1) % len( ringbuffer.buffer_base_list) gold_gen["current_address"] = ringbuffer.buffer_base_list[ gold_gen["current_buffer"]] yield stream_source.last.eq(1) def put_data(data): gold[gold_gen["current_address"]] = data gold_gen["current_address"] += axi.data_bytes yield stream_source.valid.eq(1) yield stream_source.payload.eq(data) # first, fill in some data: for i in range(data_len): yield from put_data(i) # yield dut.change_buffer.eq(0) yield from change_buffer() yield yield stream_source.valid.eq(0) memory = {} accepted = 0 while accepted < data_len: memory_fragment, accepted_frag = (yield from answer_write_burst(axi)) memory.update(memory_fragment) accepted += accepted_frag yield self.assertEqual(gold, memory) self.assertFalse((yield dut.error)) platform = SimPlatform() platform.add_sim_clock("sync", 100e6) platform.sim(dut, testbench)
def elaborate(self, platform): m = Module() hdmi = m.submodules.hdmi = Hdmi(self.hdmi_plugin, self.modeline) in_pix_domain = DomainRenamer("pix") addr_gen = m.submodules.addr_gen = in_pix_domain( AddressGenerator(self.ring_buffer)) m.d.comb += addr_gen.next_frame.eq(hdmi.timing_generator.vsync) m.d.comb += addr_gen.line_words_read.eq(hdmi.timing_generator.width) reader = m.submodules.reader = in_pix_domain( AxiBufferReader(addr_gen.output)) output = StreamEndpoint.like(reader.output, is_sink=True, name="hdmi_reader_output_sink") m.d.comb += output.connect(reader.output) ctr = Signal(range(4)) with m.If(ctr == 3): m.d.comb += output.ready.eq(1) m.d.pix += ctr.eq(0) with m.Else(): m.d.pix += ctr.eq(ctr + 1) value = Signal(8) for i in range(4): with m.If(ctr == i): m.d.comb += value.eq(output.payload[i * 12:i * 12 + 8]) m.d.comb += hdmi.rgb.r.eq(value) m.d.comb += hdmi.rgb.g.eq(value) m.d.comb += hdmi.rgb.b.eq(value) return m
def __init__(self, plugin): """ This module needs to run in the word clock domain of the bus. """ self.plugin = plugin self.output = StreamEndpoint(32, is_sink=False, has_last=False) self.ready = StatusSignal()
def __init__( self, address_source: StreamEndpoint, axi_slave=None, axi_data_width=64 ): assert address_source.has_last is False self.address_source = address_source self.axi_slave = axi_slave self.output = StreamEndpoint(axi_data_width, is_sink=False, has_last=False) self.last_resp = StatusSignal(Response) self.error_count = StatusSignal(32)
def __init__(self, streams): self._streams = streams self.has_last = self._streams[0].has_last assert not any(self.has_last is not other.has_last for other in self._streams) width = sum(len(stream.payload) for stream in self._streams) self.output = StreamEndpoint(width, is_sink=False, has_last=self.has_last) self.different_last_error = StatusSignal() self.different_valid_error = StatusSignal()
def test_smoke(self): m = Module() platform = SimPlatform() platform.add_sim_clock("sync", 50e6) platform.add_sim_clock("ft601", 100e6) ft601 = Ft601FakeResource() counter_source = StreamEndpoint(32, is_sink=False, has_last=False) m.d.sync += counter_source.payload.eq(counter_source.payload + 1) m.d.comb += counter_source.valid.eq(1) m.submodules.dut = FT601StreamSink(ft601, counter_source) def testbench(): read = [] for i in range(3): yield ft601.txe.eq(1) written = 0 began = False while True: if not began: if (yield ft601.write): began = True if began: if (yield ft601.write): written += 1 read.append((yield ft601.data.o)) else: yield ft601.txe.eq(0) break if written == 2048: yield ft601.txe.eq(0) break yield yield assert written == 2048 for i in range(200): yield assert (yield ft601.write ) == 0, "write was high in idle cycle {}".format(i) # validate the received data print(read) last = 0 for v in read: assert v == last last += 1 platform.sim(m, (testbench, "ft601"))
def __init__(self, input: StreamEndpoint, depth: int, buffered=True, fwtf=False): assert input.is_sink is False self.input = input self.output = StreamEndpoint.like(input, name="stream_fifo_output") self.depth = depth self.buffered = buffered self.fwtf = fwtf self.max_w_level = StatusSignal(range(depth)) self.overflow_cnt = StatusSignal(32) self.underrun_cnt = StatusSignal(32) self.r_level = StatusSignal(range(depth + 1)) self.w_level = StatusSignal(range(depth + 1))
def elaborate(self, platform): m = Module() input_sink = StreamEndpoint.like(self.input, is_sink=True, name="stream_fifo_input") m.d.comb += input_sink.connect(self.input) if input_sink.has_last: fifo_data = Cat(input_sink.payload, input_sink.last) else: fifo_data = input_sink.payload if self.buffered: assert not self.fwtf fifo = m.submodules.fifo = SyncFIFOBuffered(width=len(fifo_data), depth=self.depth) else: fifo = m.submodules.fifo = SyncFIFO(width=len(fifo_data), depth=self.depth, fwft=self.fwtf) m.d.comb += self.r_level.eq(fifo.r_level) m.d.comb += self.w_level.eq(fifo.w_level) with m.If(self.w_level > self.max_w_level): m.d.sync += self.max_w_level.eq(self.w_level) m.d.comb += input_sink.ready.eq(fifo.w_rdy) m.d.comb += fifo.w_data.eq(fifo_data) m.d.comb += fifo.w_en.eq(input_sink.valid) with m.If(input_sink.valid & (~input_sink.ready)): m.d.sync += self.overflow_cnt.eq(self.overflow_cnt + 1) with m.If(self.output.ready & (~self.output.valid)): m.d.sync += self.underrun_cnt.eq(self.underrun_cnt + 1) if self.output.has_last: m.d.comb += Cat(self.output.payload, self.output.last).eq(fifo.r_data) else: m.d.comb += self.output.payload.eq(fifo.r_data) m.d.comb += self.output.valid.eq(fifo.r_rdy) m.d.comb += fifo.r_en.eq(self.output.ready) return m
def __init__( self, ringbuffer: RingBufferAddressStorage, max_line_width=5000, address_width=32, data_width=64, ): self.next_frame = Signal() self.line_words_total = ControlSignal(32, reset=2304 // 4) self.line_words_read = StatusSignal(32) self.ringbuffer = ringbuffer self.address_width = address_width self.data_width = data_width self.max_line_width = max_line_width self.output = StreamEndpoint(address_width, is_sink=False, has_last=False)
def __init__(self, input, depth, r_domain, w_domain, buffered=True, exact_depth=False): assert input.is_sink is False self.input = input self.output = StreamEndpoint.like(input, name="stream_fifo_output") self.r_domain = r_domain self.w_domain = w_domain self.depth = depth self.exact_depth = exact_depth self.buffered = buffered self.overflow_cnt = StatusSignal(32) self.underrun_cnt = StatusSignal(32) self.r_level = StatusSignal(range(depth + 1)) self.w_level = StatusSignal(range(depth + 1))
def elaborate(self, platform): m = Module() plugin = platform.request("plugin_stream_input") rx = m.submodules.rx = PluginModuleStreamerRx(plugin) counter = Signal(24) m.d.sync += counter.eq(counter + 1) jtag_analyze = StreamEndpoint(32, is_sink=False, has_last=False) m.d.comb += jtag_analyze.payload.eq(Cat(platform.jtag_signals, counter[0:21])) m.d.comb += jtag_analyze.valid.eq(1) in_domain = DomainRenamer("wclk_in") counter = m.submodules.counter = in_domain(CounterStreamSource(32)) ft601 = platform.request("ft601") m.submodules.ft601 = in_domain(FT601StreamSink(ft601, jtag_analyze)) return m
def elaborate(self, platform): m = Module() input_sink = StreamEndpoint.like(self.input, is_sink=True, name="stream_fifo_input") m.d.comb += input_sink.connect(self.input) if input_sink.has_last: fifo_data = Cat(input_sink.payload, input_sink.last) else: fifo_data = input_sink.payload fifo_type = AsyncFIFOBuffered if self.buffered else AsyncFIFO fifo = m.submodules.fifo = fifo_type(width=len(fifo_data), depth=self.depth, r_domain=self.r_domain, w_domain=self.w_domain, exact_depth=self.exact_depth) m.d.comb += self.r_level.eq(fifo.r_level) m.d.comb += self.w_level.eq(fifo.w_level) m.d.comb += input_sink.ready.eq(fifo.w_rdy) m.d.comb += fifo.w_data.eq(fifo_data) m.d.comb += fifo.w_en.eq(input_sink.valid) with m.If(input_sink.valid & (~input_sink.ready)): m.d[self.w_domain] += self.overflow_cnt.eq(self.overflow_cnt + 1) with m.If(self.output.ready & (~self.output.valid)): m.d[self.r_domain] += self.underrun_cnt.eq(self.underrun_cnt + 1) if self.output.has_last: m.d.comb += Cat(self.output.payload, self.output.last).eq(fifo.r_data) else: m.d.comb += self.output.payload.eq(fifo.r_data) m.d.comb += self.output.valid.eq(fifo.r_rdy) m.d.comb += fifo.r_en.eq(self.output.ready) return m
def test_sim_asnyc_stream_fifo(self): m = Module() input = StreamEndpoint(32, is_sink=False, has_last=False) fifo = m.submodules.fifo = AsyncStreamFifo(input, 1024, r_domain="sync", w_domain="sync", buffered=False) def testbench(): for i in range(10): yield from write_to_stream(input, i) # async fifos need some time yield yield assert (yield fifo.r_level) == 10 for i in range(10): assert (yield from read_from_stream(fifo.output)) == i simulator = Simulator(m) simulator.add_clock(1 / 100e6, domain="sync") simulator.add_sync_process(testbench, domain="sync") simulator.run()
def test_basic(self, data_len=50): axi = AxiEndpoint(addr_bits=32, data_bits=64, master=False, lite=False, id_bits=12) ringbuffer = RingBufferAddressStorage(0x1000, 2, base_address=0) stream_source = StreamEndpoint(64, is_sink=False, has_last=True) dut = AxiBufferWriter(ringbuffer, stream_source, axi, fifo_depth=data_len) def testbench(): # first, fill in some data: for i in range(data_len): yield stream_source.payload.eq(i) yield stream_source.valid.eq(1) yield yield stream_source.valid.eq(0) memory = {} while len(memory) < 50: memory.update((yield from answer_write_burst(axi))[0]) self.assertEqual( { ringbuffer.buffer_base_list[0] + i * axi.data_bytes: i for i in range(50) }, memory) self.assertFalse((yield dut.error)) platform = SimPlatform() platform.add_sim_clock("sync", 100e6) platform.sim(dut, testbench)
def elaborate(self, platform): m = Module() if self.axi_slave is not None: assert not self.axi_slave.is_lite assert not self.axi_slave.is_master axi_slave = self.axi_slave else: clock_signal = Signal() m.d.comb += clock_signal.eq(ClockSignal()) axi_slave = platform.ps7.get_axi_hp_slave(clock_signal) axi = AxiEndpoint.like(axi_slave, master=True) m.d.comb += axi.connect_slave(axi_slave) assert len(self.output.payload) == axi.data_bits address_stream = StreamEndpoint.like(self.address_source, is_sink=True, name="address_sink") m.d.comb += address_stream.connect(self.address_source) assert len(address_stream.payload) == axi.addr_bits # we dont generate bursts for now m.d.comb += axi.read_address.valid.eq(address_stream.valid) m.d.comb += axi.read_address.value.eq(address_stream.payload) m.d.comb += address_stream.ready.eq(axi.read_address.ready) m.d.comb += axi.read_address.burst_len.eq(0) m.d.comb += axi.read_data.ready.eq(self.output.ready) m.d.comb += axi.read_data.last.eq(1) m.d.comb += self.output.valid.eq(axi.read_data.valid) m.d.comb += self.output.payload.eq(axi.read_data.value) m.d.sync += self.last_resp.eq(axi.read_data.resp) with m.If(axi.read_data.valid & (axi.read_data.resp != Response.OKAY)): m.d.sync += self.error_count.eq(self.error_count + 1) return m
def elaborate(self, platform): m = Module() highest_bit = 0 for i, stream in enumerate(self._streams): sink = StreamEndpoint.like( stream, is_sink=True, name="stream_combiner_sink_{}".format(i)) sink.connect(stream) m.d.comb += stream.ready.eq(self.output.ready) m.d.comb += self.output.payload[highest_bit:highest_bit + len(stream.payload)].eq( stream.payload) highest_bit += len(stream.payload) m.d.comb += self.output.valid.eq(stream.valid) with m.If(self.output.valid != stream.valid): m.d.sync += self.different_valid_error.eq(1) if self.has_last: m.d.comb += self.output.last.eq(stream.last) with m.If(self.output.last != stream.last): m.d.sync += self.different_last_error.eq(1) return m
def __init__(self, width): self.output = StreamEndpoint(width, is_sink=False, has_last=False)
def elaborate(self, platform): m = Module() if self.axi_slave is not None: assert not self.axi_slave.is_lite assert not self.axi_slave.is_master axi_slave = self.axi_slave else: clock_signal = Signal() m.d.comb += clock_signal.eq(ClockSignal()) axi_slave = platform.ps7.get_axi_hp_slave(clock_signal) axi = AxiEndpoint.like(axi_slave, master=True) m.d.comb += axi.connect_slave(axi_slave) address_generator = m.submodules.address_generator = AddressGenerator( self.ringbuffer, axi.addr_bits, max_incr=self.max_burst_length * axi.data_bytes ) data_fifo = m.submodules.data_fifo = SyncStreamFifo(self.stream_source, depth=self.fifo_depth, buffered=False) data = StreamEndpoint.like(data_fifo.output, is_sink=True, name="data_sink") m.d.comb += data.connect(data_fifo.output) assert len(data.payload) <= axi.data_bits # we do not currently care about the write responses m.d.comb += axi.write_response.ready.eq(1) current_burst_length_minus_one = Signal(range(self.max_burst_length)) with m.FSM(): def idle_state(): # having the idle state in a function is a hack to be able to duplicate its logic m.d.comb += self.state.eq(0) m.d.sync += self.burst_position.eq(0) m.d.comb += address_generator.request.eq(1) with m.If(address_generator.valid & data.valid): # we are doing a full transaction next_burst_length = Signal(range(self.max_burst_length + 1)) m.d.comb += next_burst_length.eq(nMax(data_fifo.r_level, self.max_burst_length)) m.d.sync += current_burst_length_minus_one.eq(next_burst_length - 1) m.d.sync += address_generator.inc.eq(mul_by_pot(next_burst_length, axi.data_bytes)) m.next = "ADDRESS" with m.State("IDLE"): idle_state() with m.State("ADDRESS"): m.d.comb += self.state.eq(1) m.d.comb += axi.write_address.value.eq(address_generator.addr) m.d.comb += axi.write_address.burst_len.eq(current_burst_length_minus_one) m.d.comb += axi.write_address.burst_type.eq(BurstType.INCR) m.d.comb += axi.write_address.valid.eq(1) with m.If(axi.write_address.ready): m.next = "TRANSFER_DATA" m.d.comb += data.ready.eq(1) m.d.comb += address_generator.done.eq(1) def last_logic(): # shared between TRANSFER_DATA and FLUSH with m.If(self.burst_position == current_burst_length_minus_one): m.d.comb += axi.write_data.last.eq(1) m.next = "IDLE" idle_state() with m.State("TRANSFER_DATA"): m.d.comb += self.state.eq(2) with m.If(data.last): m.d.sync += self.buffers_written.eq(self.buffers_written + 1) m.d.comb += address_generator.change_buffer.eq(1) m.next = "FLUSH" m.d.comb += axi.write_data.value.eq(data.payload) m.d.comb += axi.write_data.valid.eq(1) with m.If(axi.write_data.ready): m.d.sync += self.words_written.eq(self.words_written + 1) m.d.sync += self.burst_position.eq(self.burst_position + 1) with m.If((self.burst_position < current_burst_length_minus_one) & ~data.last): m.d.comb += data.ready.eq(1) with m.If((~data.valid)): # we have checked this earlier so this should never be a problem m.d.sync += self.error.eq(1) last_logic() with m.State("FLUSH"): m.d.comb += axi.write_data.byte_strobe.eq(0) m.d.comb += axi.write_data.valid.eq(1) with m.If(axi.write_data.ready): m.d.sync += self.words_written.eq(self.words_written + 1) m.d.sync += self.burst_position.eq(self.burst_position + 1) last_logic() return m