Exemplo n.º 1
0
    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)
Exemplo n.º 2
0
    def test_dont_loose_last_16_to_4(self):
        input = PacketizedStream(16)
        dut = StreamGearbox(input, 4)

        def writer():
            last_count_gold = 0
            for i in range(50):
                last = (i % 5 == 0)
                last_count_gold += last
                yield from write_to_stream(input, payload=0, last=(i % 5 == 0))
                if i % 3 == 0:
                    yield from do_nothing()
            self.assertEqual(last_count_gold, 10)

        def reader():
            last_count = 0
            for i in range(200):
                last_count += (yield from read_from_stream(dut.output, extract="last"))
                if i % 10 == 0:
                    yield from do_nothing()
            self.assertEqual(last_count, 10)

        platform = SimPlatform()
        platform.add_sim_clock("sync", 100e6)
        platform.add_process(writer, "sync")
        platform.add_process(reader, "sync")
        platform.sim(dut)
Exemplo n.º 3
0
    def elaborate(self, platform):
        m = Module()

        word_domain = f'{self.domain_prefix}_word'
        ddr_domain = f'{self.domain_prefix}_ddr'

        clock_phy = m.submodules.clock_phy = MipiClockRxPhy(
            self.clock_pin, ddr_domain)
        lane_phys = [
            CsiWordAligner(pin, ddr_domain, self.in_packet)
            for pin in self.data_pins
        ]
        for i, phy in enumerate(lane_phys):
            m.submodules[f'lane_{i + 1}_phy'] = phy

        # training of multiple lanes:
        # if some (but not all) lanes assert maybe_first_packet_byte we disable the training logic for the ones that asserted maybe_first_packet_byte
        # and let the others continue their Training. This however can lead to endless loops (when some lane is trained on not the sync pattern but some
        # other piece of data). To reduce the likeliness that this happens we only re-enable the training logic if the training did not work after a timeout
        # (measured in assertions of maybe_first_packet_byte)
        timeout = 27
        timeout_ctr = Signal(range(timeout))

        def reset_successive_training():
            m.d.sync += timeout_ctr.eq(0)
            for l in lane_phys:
                m.d.sync += l.enable_train_logic.eq(1)

        mfpb = [l.maybe_first_packet_byte for l in lane_phys]
        with m.If(~self.in_packet
                  & nAll(mfpb)):  # we completed training successfully
            reset_successive_training()
        with m.Elif(~self.in_packet & nAny(mfpb) & ~nAll(
                l.maybe_first_packet_byte | l.enable_train_logic
                for l in lane_phys)):  # we are certainly not on the right path
            reset_successive_training()
        with m.Elif(~self.in_packet & nAny(mfpb) & (timeout_ctr < timeout)):
            m.d.sync += timeout_ctr.eq(timeout_ctr + 1)
            for l in lane_phys:
                with m.If(l.maybe_first_packet_byte & nAny(
                        l.maybe_first_packet_byte & ~l.enable_train_logic
                        for l in lane_phys)):
                    m.d.sync += l.enable_train_logic.eq(0)
        with m.Elif(~self.in_packet & nAny(mfpb)):
            reset_successive_training()

        gearbox_input = PacketizedFirstStream(8 * len(lane_phys))
        m.d.comb += gearbox_input.first.eq(nAll(mfpb))
        for i, l in enumerate(lane_phys):
            m.d.comb += gearbox_input.payload[i * 8:(i + 1) * 8].eq(l.output)
        gearbox = m.submodules.gearbox = StreamGearbox(gearbox_input,
                                                       target_width=32)
        m.d.comb += self.output.connect_upstream(gearbox.output)

        return m
Exemplo n.º 4
0
    def test_gearbox_8_to_4_last(self):
        input = PacketizedStream(8)
        dut = StreamGearbox(input, 4)

        def writer():
            yield from write_to_stream(input, payload=0b00_10_00_01, last=1)
            yield from write_to_stream(input, payload=0b10_00_01_00, last=0)

        def reader():
            self.assertEqual((yield from read_from_stream(dut.output, extract=("payload", "last"))), (0b0001, 0))
            self.assertEqual((yield from read_from_stream(dut.output, extract=("payload", "last"))), (0b0010, 1))
            self.assertEqual((yield from read_from_stream(dut.output, extract=("payload", "last"))), (0b0100, 0))
            self.assertEqual((yield from read_from_stream(dut.output, extract=("payload", "last"))), (0b1000, 0))

        platform = SimPlatform()
        platform.add_sim_clock("sync", 100e6)
        platform.add_process(writer, "sync")
        platform.add_process(reader, "sync")
        platform.sim(dut)
Exemplo n.º 5
0
    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)
Exemplo n.º 6
0
        def test_gearbox(input_width, output_width):
            input = PacketizedStream(input_width)
            m = Module()
            fifo_in = m.submodules.fifo_in = BufferedSyncStreamFIFO(input, 100)
            gearbox = m.submodules.gearbox = StreamGearbox(fifo_in.output, output_width)
            fifo_out = m.submodules.fifo_out = BufferedSyncStreamFIFO(gearbox.output, 100)

            input_data, output_data = gold_gen(input_width, output_width)

            def writer():
                for v in input_data:
                    yield from write_to_stream(input, payload=v)

            def reader():
                for i, v in enumerate(output_data):
                    read = (yield from read_from_stream(fifo_out.output))
                    self.assertEqual(read, v)

            platform = SimPlatform()
            platform.add_sim_clock("sync", 100e6)
            platform.add_process(writer, "sync")
            platform.add_process(reader, "sync")
            platform.sim(m)
Exemplo n.º 7
0
    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)
Exemplo n.º 8
0
 def test_output_stream_contract(self):
     input = BasicStream(7)
     verify_stream_output_contract(StreamGearbox(input, 3))
Exemplo n.º 9
0
    def elaborate(self, platform):
        m = Module()

        gearbox = m.submodules.gearbox = StreamGearbox(
            self.input, target_width=len(self.output.payload))

        def repack_to_lanes(packet):
            values = [
                packet[i * 8:(i + 1) * 8] for i in range(len(packet) // 8)
            ]
            if self.num_lanes == 1:
                pass
            elif self.num_lanes == 2:
                values = [
                    Cat(values[0:2]),
                    Cat(values[2:4]),
                ]
            elif self.num_lanes == 4:
                values = Cat(values)
            else:
                raise AssertionError("Invalid number of lanes!")
            return [(v, i == len(values) - 1) for i, v in enumerate(values)]

        def short_packet_words(type, payload=Const(0, 16)):
            data_id = DataIdentifier(data_type=type,
                                     virtual_channel_identifier=0)
            packet_prelim = PacketHeader(data_id=data_id,
                                         word_count=payload,
                                         ecc=0)
            packet = PacketHeader(data_id=data_id,
                                  word_count=payload,
                                  ecc=packet_prelim.calculate_ecc())
            return repack_to_lanes(packet.as_value())

        def send_short_packet(p, type, payload=Const(0, 16), lp_after=False):
            for value, last in short_packet_words(type, payload):
                p += process_write_to_stream(m,
                                             self.output,
                                             payload=value,
                                             last=last & lp_after)

        def end_of_transmission(p):
            send_short_packet(
                p,
                DsiShortPacketDataType.END_OF_TRANSMISSION_PACKET,
                lp_after=True)

        blanking_counter = Signal(16)
        is_ready = Signal()

        def blanking(p,
                     length,
                     omit_footer=False,
                     type=DsiLongPacketDataType.BLANKING_PACKET_NO_DATA):
            length_without_overhead = length - 6
            m.d.sync += blanking_counter.eq(0)
            if not isinstance(length_without_overhead, Value):
                length_without_overhead = Const(length_without_overhead, 16)
            send_short_packet(p, type, length_without_overhead[0:16])
            with process_write_to_stream(m, self.output, payload=0x0):
                m.d.sync += blanking_counter.eq(blanking_counter + 1)
                m.d.comb += is_ready.eq(1)
            p += m.If(
                blanking_counter + is_ready >= length_without_overhead //
                2)  # the packet overhead is 6 bytes (4 header and 2 footer)
            if not omit_footer:
                p += process_write_to_stream(m, self.output,
                                             payload=0x0)  # checksum

        frame_last = Signal()
        v_porch_counter = Signal(16)

        def v_porch(name, to, length, skip_first_hsync=False):
            if not skip_first_hsync:
                first_name = name
                second_process_name = f"{name}_OVERHEAD"
            else:
                first_name = f"{name}_HSYNC"
                second_process_name = name

            with Process(m, first_name, to=second_process_name) as p:
                send_short_packet(p, DsiShortPacketDataType.H_SYNC_START)

            with Process(m, second_process_name, to=None) as p:
                blanking(p,
                         self.hfp + self.image_width + self.hbp,
                         type=DsiLongPacketDataType.NULL_PACKET_NO_DATA,
                         omit_footer=True)
                with process_write_to_stream(m, self.output, payload=0x0):
                    with m.If(v_porch_counter < length):
                        m.d.sync += v_porch_counter.eq(v_porch_counter + 1)
                        m.next = first_name
                    with m.Else():
                        m.d.sync += v_porch_counter.eq(0)
                        m.next = to

        trig = Signal()
        if self.debug and False:
            probe(m, self.output.valid)
            probe(m, self.output.ready)
            probe(m, self.output.last)
            probe(m, self.output.payload)
            probe(m, gearbox.output.ready)
            probe(m, gearbox.output.valid)
            probe(m, gearbox.output.frame_last)
            probe(m, gearbox.output.line_last)
            probe(m, gearbox.output.payload)

            # trigger(m, trig)

        with m.FSM() as fsm:
            fsm_status_reg(platform, m, fsm)
            if self.debug:
                ...
                #fsm_probe(m, fsm)

            with Process(m, "VSYNC_START", to="VBP") as p:
                send_short_packet(p, DsiShortPacketDataType.V_SYNC_START)

            v_porch("VBP", "LINE_START", self.vbp, skip_first_hsync=True)

            with Process(m, "LINE_START", to="LINE_DATA") as p:
                end_of_transmission(p)
                p += m.If(gearbox.output.valid)
                m.d.comb += trig.eq(1)
                send_short_packet(p, DsiShortPacketDataType.H_SYNC_START)
                blanking(p, self.hbp)
                send_short_packet(
                    p,
                    DsiLongPacketDataType.PACKED_PIXEL_STREAM_24_BIT_RGB_8_8_8,
                    self.image_width)
            with m.State("LINE_DATA"):
                with m.If(gearbox.output.line_last & gearbox.output.valid
                          & gearbox.output.ready):
                    m.next = "LINE_END"
                    m.d.sync += frame_last.eq(gearbox.output.frame_last)
                with m.If(~gearbox.output.valid):
                    m.d.sync += self.gearbox_not_ready.eq(
                        self.gearbox_not_ready + 1)
                m.d.comb += self.output.connect_upstream(gearbox.output,
                                                         allow_partial=True)
            with Process(m, "LINE_END", to=None) as p:
                p += process_write_to_stream(
                    m, self.output,
                    payload=0x0)  # TODO: handle the non 2 lane case
                blanking(
                    p, self.hfp, omit_footer=True
                )  # we omit the footer to be able to do dispatch the next state with zero cycle delay
                with process_write_to_stream(m, self.output, payload=0x0):
                    with m.If(frame_last):
                        m.next = "VFP"
                    with m.Else():
                        m.next = "LINE_START"

            v_porch("VFP", "FRAME_END", self.vfp)

            with Process(m, "FRAME_END", to="VSYNC_START") as p:
                end_of_transmission(p)

        return m