def __init__(self, i2s_resource, output_bit_depth=16, i2s_domain="i2s"): self.output_bit_depth = output_bit_depth self.i2s_resource = i2s_resource self.i2s_domain = i2s_domain self.l_output = BasicStream(output_bit_depth) self.r_output = BasicStream(output_bit_depth)
def __init__(self, input, output_width): self.input = input self.output_width = output_width self.word_alignment = StatusSignal(range(output_width)) self.output = BasicStream(output_width)
def test_packetizer_output_stream_contract(self): length_input = BasicStream(4) data_input = BasicStream(64) dut = StreamPacketizer(length_input, data_input) verify_stream_output_contract( dut, support_modules=(LegalStreamSource(data_input), LegalStreamSource(length_input)) )
def test_burster_data_output_stream_contract(self): data_input = BasicStream(64) address_input = BasicStream(32) dut = AxiWriterBurster(address_input, data_input) verify_stream_output_contract( dut, stream_output=dut.data_output, support_modules=(LegalStreamSource(data_input), LegalStreamSource(address_input)) )
def __init__(self, input: BasicStream, core_producer, fifo_depth=128): self.fifo_depth = fifo_depth self.input = input self.core_input = BasicStream(input.payload.shape()) self.core = core_producer(self.core_input) self.core_output = self.core.output self.output = self.input.clone() self.output.payload = Signal(len(self.core_output.payload)) @ DOWNWARDS
def test_basic(self): platform = SimPlatform() axi = AxiEndpoint(addr_bits=32, data_bits=64, lite=False, id_bits=12) data_stream = BasicStream(64) address_stream = BasicStream(32) write_sequence = [ (0, 1), (0, 2), (0, 3), (0, 4), (1, 5), (2, 6), *[(a, a) for a in range(10, 1000, 8)], (1000, 1), (1000, 2), (1000, 3), (1000, 4), (1001, 5), (1002, 6), ] golden_memory = {} for addr, data in write_sequence: golden_memory[addr] = data dut = AxiWriter(address_stream, data_stream, axi) def write_address_process(): for addr, data in write_sequence: yield from write_to_stream(address_stream, payload=addr) platform.add_process(write_address_process, "sync") def write_data_process(): for addr, data in write_sequence: yield from write_to_stream(data_stream, payload=data) platform.add_process(write_data_process, "sync") def axi_answer_process(): memory = {} while len(memory) < len(golden_memory): # print("m", len(memory), memory) written, accepted = (yield from answer_write_burst(axi)) print("w", len(written), written) memory.update(written) self.assertEqual(golden_memory, memory) platform.add_process(axi_answer_process, "sync") platform.add_sim_clock("sync", 100e6) platform.sim(dut)
class I2S_RX(Elaboratable): def __init__(self, i2s_resource, output_bit_depth=16, i2s_domain="i2s"): self.output_bit_depth = output_bit_depth self.i2s_resource = i2s_resource self.i2s_domain = i2s_domain self.l_output = BasicStream(output_bit_depth) self.r_output = BasicStream(output_bit_depth) def elaborate(self, platform): m = Module() i2s_domain = ClockDomain(self.i2s_domain) m.domains += i2s_domain m.d.comb += i2s_domain.clk.eq(self.i2s_resource.sck) l_buffer_input = BasicStream(self.output_bit_depth) r_buffer_input = BasicStream(self.output_bit_depth) delayed_ws = delay_by(self.i2s_resource.ws, 1, m) with m.FSM(): for i in range(self.output_bit_depth + 1): with m.State(f'bit_{i}'): with m.If(delayed_ws != self.i2s_resource.ws): m.next = "bit_0" with m.Else(): if i < self.output_bit_depth: m.next = f"bit_{i + 1}" if i < self.output_bit_depth: with m.If(delayed_ws): m.d.sync += r_buffer_input.payload[ self.output_bit_depth - i - 1].eq( self.i2s_resource.sd) with m.Else(): m.d.sync += l_buffer_input.payload[ self.output_bit_depth - i - 1].eq( self.i2s_resource.sd) if i == 0: with m.If(delayed_ws): m.d.comb += r_buffer_input.valid.eq(1) with m.Else(): m.d.comb += l_buffer_input.valid.eq(1) l_buffer = m.submodules.buffer_l = StreamBuffer(l_buffer_input) m.d.comb += self.l_output.connect_upstream(l_buffer.output) r_buffer = m.submodules.buffer_r = StreamBuffer(r_buffer_input) m.d.comb += self.r_output.connect_upstream(r_buffer.output) return DomainRenamer(self.i2s_domain)(m)
def __init__( self, address_source: BasicStream, axi=None, axi_data_width=64, ): self.address_source = address_source self.axi = axi self.output = BasicStream(axi_data_width, name="buffer_reader_output_stream") self.output.payload = Signal(axi_data_width) self.last_resp = StatusSignal(AxiResponse) self.error_count = StatusSignal(32)
def __init__(self, pins, width: int, ddr_domain, reset): self.pins = pins self.reset = reset self.input = BasicStream(width) self.idle = Signal(width) self.is_idle = Signal() self.ddr_domain = ddr_domain
def __init__(self, plugin, domain_name="sync"): self.plugin = plugin self.output = BasicStream(32) self.domain_name = domain_name self.trained = ControlSignal() self.valid = StatusSignal()
def elaborate(self, platform): m = Module() address_burster = m.submodules.address_burster = AxiReaderBurster( self.address_input, self.word_bytes, self.max_burst_length, self.burst_creation_timeout) burst_tee = m.submodules.burst_tee = StreamTee(address_burster.output) m.d.comb += self.address_output.connect_upstream( burst_tee.get_output()) burst_stream = burst_tee.get_output() packet_length_stream = BasicStream(burst_stream.burst_len.shape()) m.d.comb += packet_length_stream.valid.eq(burst_stream.valid) m.d.comb += burst_stream.ready.eq(packet_length_stream.ready) m.d.comb += packet_length_stream.payload.eq(burst_stream.burst_len) data_fifo = m.submodules.data_fifo = BufferedSyncStreamFIFO( self.data_input, self.data_fifo_depth) stream_packetizer = m.submodules.stream_packetizer = StreamPacketizer( packet_length_stream, data_fifo.output) m.d.comb += self.data_output.connect_upstream(stream_packetizer.output, allow_partial=True) m.d.comb += self.data_output.id.eq(self.data_output.id.reset) m.d.comb += self.data_output.byte_strobe.eq(-1) return m
def __init__(self, address_input: BasicStream, memory: Memory): assert len(address_input.payload) == bits_for(memory.depth) self.address_input = address_input self.memory = memory self.output = address_input.clone() self.output.payload = Signal(memory.width)
class GenericMetadataWrapper(Elaboratable): def __init__(self, input: BasicStream, core_producer, fifo_depth=128): self.fifo_depth = fifo_depth self.input = input self.core_input = BasicStream(input.payload.shape()) self.core = core_producer(self.core_input) self.core_output = self.core.output self.output = self.input.clone() self.output.payload = Signal(len(self.core_output.payload)) @ DOWNWARDS def elaborate(self, platform): m = Module() m.submodules.core = self.core tee = m.submodules.tee = StreamTee(self.input) m.d.comb += self.core_input.connect_upstream(tee.get_output(), allow_partial=True) metadata_fifo_input = Stream() for name, s in self.input.out_of_band_signals.items(): setattr(metadata_fifo_input, name, Signal.like(s) @ DOWNWARDS) m.d.comb += metadata_fifo_input.connect_upstream(tee.get_output(), allow_partial=True) metadata_fifo = m.submodules.metadata_fifo = BufferedSyncStreamFIFO( metadata_fifo_input, self.fifo_depth) combiner = m.submodules.combiner = StreamCombiner( self.core_output, metadata_fifo.output) m.d.comb += self.output.connect_upstream(combiner.output) return m
def test_gearbox_12_to_48_to_64(self): m = Module() platform = SimPlatform() input = BasicStream(12) tee = m.submodules.tee = StreamTee(input) gear_12_to_48 = m.submodules.gear_12_to_48 = StreamGearbox(tee.get_output(), 48) gear_48_to_64 = m.submodules.gear_48_to_64 = StreamGearbox(gear_12_to_48.output, 64) gear_12_to_64 = m.submodules.gear_12_to_64 = StreamGearbox(tee.get_output(), 64) def writer(): yield Passive() random.seed(0) while True: yield from write_to_stream(input, payload=random.randrange(0, 2**12)) platform.add_process(writer, "sync") def reader(): for _ in range(100): a = yield from read_from_stream(gear_12_to_64.output) b = yield from read_from_stream(gear_48_to_64.output) print(f"{a:064b}") self.assertEqual(a, b) platform.add_process(reader, "sync") platform.add_sim_clock("sync", 100e6) platform.sim(m)
def elaborate(self, platform): m = Module() m.submodules.core = self.core last_fifo_input = BasicStream(self.last_rle_bits) last_fifo = m.submodules.last_fifo = BufferedSyncStreamFIFO( last_fifo_input, self.last_fifo_depth) overflow_word = (2**self.last_rle_bits - 1) rle_input_counter = StatusSignal(self.last_rle_bits) with m.If(self.input.valid & last_fifo_input.ready): m.d.comb += self.core_input.valid.eq(1) m.d.comb += self.core_input.payload.eq(self.input.payload) with m.If(self.core_input.ready): m.d.comb += self.input.ready.eq(1) with m.If(self.input.last | (rle_input_counter == overflow_word - 1)): with m.If(~self.input.last & (rle_input_counter == overflow_word - 1)): m.d.comb += last_fifo_input.payload.eq(overflow_word) with m.Else(): m.d.comb += last_fifo_input.payload.eq( rle_input_counter) m.d.comb += last_fifo_input.valid.eq(1) m.d.sync += rle_input_counter.eq(0) with m.Else(): m.d.sync += rle_input_counter.eq(rle_input_counter + 1) rle_output_counter = StatusSignal(self.last_rle_bits) with m.If(self.core_output.valid): m.d.comb += self.output.valid.eq(1) m.d.comb += self.output.payload.eq(self.core_output.payload) overflow = (last_fifo.output.payload == overflow_word) & ( rle_output_counter == (overflow_word - 1)) with m.If(( (rle_output_counter == last_fifo.output.payload) | overflow) & last_fifo.output.valid): with m.If(~overflow): m.d.comb += self.output.last.eq(1) with m.If(self.output.ready): m.d.sync += rle_output_counter.eq(0) m.d.comb += last_fifo.output.ready.eq(1) m.d.comb += self.core_output.ready.eq(1) with m.Elif((rle_output_counter > last_fifo.output.payload) & last_fifo.output.valid): with m.If(self.output.ready): m.d.comb += self.core_output.ready.eq(1) m.d.sync += self.error.eq(self.error + 1) with m.Else(): with m.If(self.output.ready): m.d.comb += self.core_output.ready.eq(1) m.d.sync += rle_output_counter.eq(rle_output_counter + 1) return m
def __init__(self, input: BasicStream, target_width): self.input = input self.output = input.clone(name="gearbox_output") self.output.payload = Signal(target_width) @ DOWNWARDS self.input_width = len(self.input.payload) self.output_width = target_width self.division_factor = self.input_width / target_width assert target_width < self.input_width assert self.division_factor % 1 == 0 self.division_factor = int(self.division_factor)
def __init__(self, input: PacketizedStream, packet_len): self.input = input self.output = BasicStream(input.payload.shape()) # we calculate everything in bytes to make it easier to reason about buffer_size = 2048 * 4 blanking = buffer_size aligned_len = ceil((packet_len + blanking) / buffer_size) * buffer_size print("ft60x paddnig:", (aligned_len - packet_len), (aligned_len - packet_len) // 4) self.padding = ControlSignal(16, reset=(aligned_len - packet_len) // 4) self.frame_len = StatusSignal(32) self.frame_len_changed = StatusSignal(32)
def test_basic(self): platform = SimPlatform() memory = {i: i + 100 for i in range(1000)} read_sequence = [ 0, 100, 108, 116, 2, 7, *[i + 100 for i in range(0, 400, 8)], 0, 100, 108, 116, 2, 7, ] golden_read_result = [memory[addr] for addr in read_sequence] axi = AxiEndpoint(addr_bits=32, data_bits=64, lite=False, id_bits=12) address_stream = BasicStream(32) dut = AxiReader(address_stream, axi) def write_address_process(): for addr in read_sequence: yield from write_to_stream(address_stream, payload=addr) platform.add_process(write_address_process, "sync") def read_data_process(): read_result = [] while len(read_result) < len(golden_read_result): read = yield from read_from_stream(dut.output) read_result.append(read) self.assertEqual(read_result, golden_read_result) platform.add_process(read_data_process, "sync") def axi_answer_process(): yield Passive() while True: yield from answer_read_burst(axi, memory) platform.add_process(axi_answer_process, "sync") platform.add_sim_clock("sync", 100e6) platform.sim(dut)
def elaborate(self, platform): m = Module() cw = ControlChannelWord(self.control_lane) lane_top_streams_buffered = [] for i, signal in enumerate(self.top_lanes): stream = BasicStream(self.n_bits) m.d.comb += stream.payload.eq(signal) m.d.comb += stream.valid.eq(cw.data_valid) fifo = m.submodules[f"fifo_top{i}"] = BufferedSyncStreamFIFO( stream, depth=128 * (self.lines_to_buffer + 1)) lane_top_streams_buffered.append(fifo.output) return m
def __init__(self, input: PacketizedStream, core_producer, last_fifo_depth=3, last_rle_bits=10): self.last_fifo_depth = last_fifo_depth self.last_rle_bits = last_rle_bits assert hasattr(input, "last") self.input = input self.core_input = BasicStream(input.payload.shape()) self.core = core_producer(self.core_input) self.core_output = self.core.output self.error = StatusSignal(32) self.output = PacketizedStream(len(self.core_output.payload))
class InputGearbox(Elaboratable): def __init__(self, input, output_width): self.input = input self.output_width = output_width self.word_alignment = StatusSignal(range(output_width)) self.output = BasicStream(output_width) def elaborate(self, platform): m = Module() gearbox = m.submodules.gearbox = StreamGearbox(self.input, self.output_width) window = m.submodules.window = StreamWindow(gearbox.output, window_words=2) select = m.submodules.select = StreamSelect( window.output, output_width=self.output_width) m.d.comb += self.output.connect_upstream(select.output) return m
class AxiReader(Elaboratable): def __init__( self, address_source: BasicStream, axi=None, axi_data_width=64, ): self.address_source = address_source self.axi = axi self.output = BasicStream(axi_data_width, name="buffer_reader_output_stream") self.output.payload = Signal(axi_data_width) self.last_resp = StatusSignal(AxiResponse) self.error_count = StatusSignal(32) def elaborate(self, platform): m = Module() axi = if_none_get_zynq_hp_port(self.axi, m, platform) assert len(self.output.payload) == axi.data_bits assert len(self.address_source.payload) == axi.addr_bits for fifo_signal_name in [ "read_address_fifo_level", "read_data_fifo_level" ]: if hasattr(axi, fifo_signal_name): axi_fifo_signal = axi[fifo_signal_name] fifo_signal = StatusSignal(axi_fifo_signal.shape(), name=f"axi_{fifo_signal_name}") m.d.comb += fifo_signal.eq(axi_fifo_signal) setattr(self, f"axi_{fifo_signal_name}", fifo_signal) burster = m.submodules.burster = AxiReaderBurster( self.address_source, data_bytes=axi.data_bytes) m.d.comb += axi.read_address.connect_upstream(burster.output) m.d.comb += self.output.connect_upstream(axi.read_data, allow_partial=True) return m
def elaborate(self, platform): m = Module() self.delayf = m.submodules.delayf = DelayF(self.pin.i) iddr = m.submodules.iddr = DomainRenamer(self.qdr_domain)(IDDRX2F( self.delayf.o, self.ddr_domain)) iddr_stream = BasicStream(4) m.d.comb += iddr_stream.valid.eq(1) m.d.comb += iddr_stream.payload.eq(iddr.output) gearbox = m.submodules.gearbox = DomainRenamer(self.qdr_domain)( StreamGearbox(iddr_stream, target_width=10)) fifo = m.submodules.fifo = BufferedAsyncStreamFIFO( gearbox.output, 32, i_domain=self.qdr_domain, o_domain="sync") window = m.submodules.window = StreamWindow(fifo.output, window_words=2) self.select = select = m.submodules.select = StreamSelect( window.output, output_width=10) m.d.comb += select.output.ready.eq(1) with m.If(~select.output.valid): # ths should never happen if the clock domains are correctly set up m.d.sync += self.not_valid_cnt.eq(self.not_valid_cnt + 1) m.d.comb += self.raw_word.eq(select.output.payload) tmds = m.submodules.tmds = TmdsDecoder(self.raw_word ^ Repl(self.invert, 10)) m.d.comb += self.data.eq(tmds.data) m.d.comb += self.data_enable.eq(tmds.data_enable) m.d.comb += self.control.eq(tmds.control) blanking_ctr = Signal.like(self.blanking_threshold) with m.If(~self.data_enable): with m.If(blanking_ctr < self.blanking_threshold): m.d.sync += blanking_ctr.eq(blanking_ctr + 1) with m.If(blanking_ctr == (self.blanking_threshold - 1)): m.d.sync += self.blankings_hit.eq(self.blankings_hit + 1) with m.Else(): m.d.sync += blanking_ctr.eq(0) return m
def test_gearbox_3_to_7(self): input = BasicStream(3) dut = StreamGearbox(input, 7) def writer(): yield from write_to_stream(input, payload=0b001) yield from write_to_stream(input, payload=0b010) yield from write_to_stream(input, payload=0b100) yield from write_to_stream(input, payload=0b011) yield from write_to_stream(input, payload=0b110) yield from write_to_stream(input, payload=0b111) yield from write_to_stream(input, payload=0b000) def reader(): self.assertEqual((yield from read_from_stream(dut.output)), 0b0_010_001) self.assertEqual((yield from read_from_stream(dut.output)), 0b10_011_10) self.assertEqual((yield from read_from_stream(dut.output)), 0b000_111_1) platform = SimPlatform() platform.add_sim_clock("sync", 100e6) platform.add_process(writer, "sync") platform.add_process(reader, "sync") platform.sim(dut)
def test_dont_loose_data(self): input = BasicStream(16) dut = StreamGearbox(input, 8) def writer(): for i in range(0, 100, 2): yield from write_to_stream(input, payload=(((i + 1) << 8) | i)) if i % 7 == 0: yield from do_nothing() def reader(): for i in range(100): got = (yield from read_from_stream(dut.output, extract="payload")) print(got) self.assertEqual(got, i) if i % 3 == 0: yield from do_nothing() platform = SimPlatform() platform.add_sim_clock("sync", 100e6) platform.add_process(writer, "sync") platform.add_process(reader, "sync") platform.sim(dut)
def __init__(self, width, count_if_not_ready=False): self.output = BasicStream(width, name="counter_stream") self.count_if_not_ready = ControlSignal(reset=count_if_not_ready)
def test_output_stream_contract(self): input = BasicStream(8) verify_stream_output_contract(SimpleStreamGearbox(input, 4), support_modules=(LegalStreamSource(input),))
def test_output_stream_contract(self): input = BasicStream(7) verify_stream_output_contract(StreamGearbox(input, 3))
def test_reader_stream_output(self): axi = AxiEndpoint(addr_bits=32, data_bits=64, lite=False, id_bits=12) verify_stream_output_contract(AxiReader(BasicStream(32), axi), support_modules=(LegalStreamSource( axi.read_data), ))
def test_burster_stream_output(self): i = BasicStream(32) verify_stream_output_contract(AxiReaderBurster(i), support_modules=(LegalStreamSource(i), ))