예제 #1
0
    def __init__(self,
                 lp_pins: TristateIo,
                 hs_pins: TristateDdrIo,
                 initial_driving=True,
                 can_lp=False,
                 ddr_domain="sync"):
        self.lp_pins = lp_pins
        self.hs_pins = hs_pins
        self.can_lp = can_lp
        self.ddr_domain = ddr_domain

        if self.can_lp:
            # The control rx and control tx signals carry the raw escape mode packets.
            # A packet with length 1 and payload 0x0 indicates that we request a bus turnaround.
            # This in Not a valid MIPI Escape Entry Code so we simply repurpose that here.
            self.control_input = PacketizedStream(8)
            self.control_output = PacketizedStream(8)

        # the hs_input stream carries is polled to
        self.hs_input = PacketizedStream(8)

        self.is_hs = StatusSignal()
        self.is_driving = StatusSignal(
            reset=initial_driving) if can_lp else True
        self.bta_timeout = 1023
        self.bta_timeouts = StatusSignal(16)
예제 #2
0
    def elaborate(self, platform):
        m = Module()

        wavelet = m.submodules.wavelet = MultiStageWavelet2D(self.input,
                                                             self.width,
                                                             self.height,
                                                             stages=3)
        packetizer = m.submodules.packetizer = ImageStream2PacketizedStream(
            wavelet.output)

        bit_stuffing_input = VariableWidthStream(self.input.payload.shape(),
                                                 reset_width=len(
                                                     self.input.payload))
        with m.If(packetizer.output.is_hf):
            rle_input = PacketizedStream()
            m.d.comb += rle_input.connect_upstream(packetizer.output)
            rle = m.submodules.rle = ZeroRleEncoder(rle_input,
                                                    self.possible_run_lengths)
            huffman = m.submodules.huffman = HuffmanEncoder(rle.output)
            m.d.comb += bit_stuffing_input.connect_upstream(huffman.output)
        with m.Else():
            m.d.comb += bit_stuffing_input.connect_upstream(packetizer.output)

        bit_stuffing = m.submodules.bit_stuffing = BitStuffer(
            bit_stuffing_input, len(self.output.payload))
        m.d.comb += self.output.connect_upstream(bit_stuffing.output)

        return m
예제 #3
0
    def __init__(self, resource, num_lanes, ddr_domain, ck_domain):
        self.resource = resource
        self.num_lanes = num_lanes
        self.ddr_domain = ddr_domain
        self.ck_domain = ck_domain

        self.control_input = PacketizedStream(8)
        self.control_output = PacketizedStream(8)
        self.hs_input = PacketizedStream(8 * num_lanes)
        self.request_hs = ControlSignal()
예제 #4
0
    def __init__(self, data_width=8, max_packet_size=1024):
        self.max_packet_size = max_packet_size

        self.reset = ControlSignal()
        self.packet_length = ControlSignal(range(max_packet_size))
        self.read_ptr = StatusSignal(range(max_packet_size))
        self.done = StatusSignal(reset=1)
        self.memory = SocMemory(
            width=data_width, depth=self.max_packet_size,
            soc_read=False,  attrs=dict(syn_ramstyle="block_ram")
        )

        self.output = PacketizedStream(data_width)
예제 #5
0
    def test_simple_gearbox_384_to_64_last(self):
        input = PacketizedStream(32 * 12)
        dut = SimpleStreamGearbox(input, 64)

        payload_a = int("".join(reversed([f"{i:03x}" for i in range(32)])), 16)
        payload_b = int("".join(reversed([f"{i:03x}" for i in range(57, 57 + 32)])), 16)

        print(hex(payload_a))
        print(hex(payload_b))

        def writer():
            yield from write_to_stream(input, payload=payload_a, last=1)
            yield from write_to_stream(input, payload=payload_b, last=0)

        def reader():
            payload_aa = payload_a
            for i in range(32 * 12 // 64):
                self.assertEqual((yield from read_from_stream(dut.output, extract=("payload", "last"))), (payload_aa & 0xffff_ffff_ffff_ffff, 0 if i < 5 else 1))
                payload_aa = payload_aa >> 64

            payload_bb = payload_b
            for i in range(32 * 12 // 64):
                print(i)
                self.assertEqual((yield from read_from_stream(dut.output, extract=("payload", "last"))), (payload_bb & 0xffff_ffff_ffff_ffff, 0))
                payload_bb = payload_bb >> 64

        platform = SimPlatform()
        platform.add_sim_clock("sync", 100e6)
        platform.add_process(writer, "sync")
        platform.add_process(reader, "sync")
        platform.sim(dut)
예제 #6
0
    def test_simple_gearbox_dont_loose_last_16_to_4(self):
        input = PacketizedStream(16)
        dut = SimpleStreamGearbox(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)
예제 #7
0
    def test_long_fifo(self):
        platform = SimPlatform()

        input_stream = PacketizedStream(32)
        dut = LastWrapper(input_stream, lambda i: BufferedSyncStreamFIFO(i, 200), last_rle_bits=10)

        random.seed(0)
        test_packets = [
            [random.randint(0, 2**32) for _ in range(12)],
            [random.randint(0, 2**32) for _ in range(24)],
            [random.randint(0, 2**32) for _ in range(1)],
            [random.randint(0, 2**32) for _ in range(1000)],
            [random.randint(0, 2**32) for _ in range(1000)],
            [random.randint(0, 2 ** 32) for _ in range(12)],
            [random.randint(0, 2 ** 32) for _ in range(1000)],
        ]

        def writer_process():
            for packet in test_packets:
                yield from write_packet_to_stream(input_stream, packet)
        platform.add_process(writer_process, "sync")

        def reader_process():
            read_packets = []
            while len(read_packets) < len(test_packets):
                read = (yield from read_packet_from_stream(dut.output))
                read_packets.append(read)
                print([len(p) for p in read_packets])

            self.assertEqual(read_packets, test_packets)
        platform.add_process(reader_process, "sync")

        platform.add_sim_clock("sync", 100e6)
        platform.sim(dut)
예제 #8
0
    def test_hello_world(self):
        platform = SimPlatform()
        m = Module()

        address_stream = PacketizedStream(8)
        mem = Memory(width=32, depth=128, init=[i + 2 for i in range(128)])
        reader = m.submodules.reader = StreamMemoryReader(address_stream, mem)

        def write_process():
            for i in range(128):
                yield from write_to_stream(address_stream,
                                           payload=i,
                                           last=(i % 8) == 0)
            yield Passive()

        def read_process():
            for i in range(128):
                data, last = (yield from
                              read_from_stream(reader.output,
                                               extract=("payload", "last")))
                assert data == i + 2
                assert last == ((i % 8) == 0)
            yield Passive()

        platform.add_sim_clock("sync", 100e6)
        platform.add_process(write_process, "sync")
        platform.sim(m, read_process)
예제 #9
0
    def elaborate(self, platform):
        m = Module()

        memory = m.submodules.memory = self.memory

        address_stream = PacketizedStream(bits_for(self.max_packet_size))
        with m.If(~self.done):
            m.d.comb += address_stream.valid.eq(1)
            m.d.comb += address_stream.last.eq(self.read_ptr == self.packet_length)
            m.d.comb += address_stream.payload.eq(self.read_ptr)
            with m.If(address_stream.ready):
                m.d.sync += self.read_ptr.eq(self.read_ptr + 1)
                m.d.sync += self.done.eq(self.read_ptr == self.packet_length)

        reset = Signal()
        m.submodules += FFSynchronizer(self.reset, reset)
        with m.If(Changed(m, reset)):
            m.d.sync += self.read_ptr.eq(0)
            m.d.sync += self.done.eq(0)

        reader = m.submodules.reader = StreamMemoryReader(address_stream, memory)
        buffer = m.submodules.buffer = StreamBuffer(reader.output)
        m.d.comb += self.output.connect_upstream(buffer.output)

        return m
예제 #10
0
    def __init__(self, input: ImageStream, width, height):
        self.input = input
        self.width = width
        self.height = height

        max_input_word = 2**len(self.input.payload)
        self.possible_run_lengths = [2, 4, 8, 16, 32, 64, 128, 256]
        self.huffmann_frequencies = {
            **{k: 1
               for k in range(max_input_word)},
            **{
                k: 10
                for k in range(max_input_word, max_input_word + len(self.possible_run_lengths))
            }
        }

        self.output = PacketizedStream(self.input.payload.shape())
예제 #11
0
 def test_core_output_stream_contract(self):
     input_stream = PacketizedStream(32)
     device_input_stream: BasicStream
     def core_producer(i):
         nonlocal device_input_stream
         device_input_stream = i
         return LegalStreamSource(i.clone())
     dut = GenericMetadataWrapper(input_stream, core_producer)
     verify_stream_output_contract(dut, stream_output=device_input_stream, support_modules=(LegalStreamSource(input_stream),))
예제 #12
0
    def __init__(self,
                 input: ImageStream,
                 num_lanes: int,
                 image_width=480,
                 debug=False):
        assert len(input.payload) == 24
        self.input = input
        self.num_lanes = num_lanes
        self.image_width = ControlSignal(16, reset=image_width * 3)
        self.debug = debug

        self.vbp = ControlSignal(16, reset=18)
        self.vfp = ControlSignal(16, reset=4)
        self.hbp = ControlSignal(16, reset=68 * 3)
        self.hfp = ControlSignal(16, reset=20 * 3)

        self.gearbox_not_ready = StatusSignal(32)

        self.output = PacketizedStream(num_lanes * 8)
예제 #13
0
class ConsolePacketSource(Elaboratable):
    def __init__(self, data_width=8, max_packet_size=1024):
        self.max_packet_size = max_packet_size

        self.reset = ControlSignal()
        self.packet_length = ControlSignal(range(max_packet_size))
        self.read_ptr = StatusSignal(range(max_packet_size))
        self.done = StatusSignal(reset=1)
        self.memory = SocMemory(
            width=data_width, depth=self.max_packet_size,
            soc_read=False,  attrs=dict(syn_ramstyle="block_ram")
        )

        self.output = PacketizedStream(data_width)

    def elaborate(self, platform):
        m = Module()

        memory = m.submodules.memory = self.memory

        address_stream = PacketizedStream(bits_for(self.max_packet_size))
        with m.If(~self.done):
            m.d.comb += address_stream.valid.eq(1)
            m.d.comb += address_stream.last.eq(self.read_ptr == self.packet_length)
            m.d.comb += address_stream.payload.eq(self.read_ptr)
            with m.If(address_stream.ready):
                m.d.sync += self.read_ptr.eq(self.read_ptr + 1)
                m.d.sync += self.done.eq(self.read_ptr == self.packet_length)

        reset = Signal()
        m.submodules += FFSynchronizer(self.reset, reset)
        with m.If(Changed(m, reset)):
            m.d.sync += self.read_ptr.eq(0)
            m.d.sync += self.done.eq(0)

        reader = m.submodules.reader = StreamMemoryReader(address_stream, memory)
        buffer = m.submodules.buffer = StreamBuffer(reader.output)
        m.d.comb += self.output.connect_upstream(buffer.output)

        return m

    @driver_method
    def write_packet(self, packet, timeout=0):
        from time import sleep
        for i in range(int(timeout * 10)):
            if self.done:
                break
            sleep(0.1)
        assert self.done
        for i, word in enumerate(packet):
            self.memory[i] = word
        self.packet_length = len(packet) - 1
        self.reset = not self.reset
예제 #14
0
class ImageStream2PacketizedStream(Elaboratable):
    """Convert an ImageStream to a packetized Stream by producing one packet per frame"""
    def __init__(self, input: ImageStream):
        self.input = input
        self.output = PacketizedStream(self.input.payload.shape(),
                                       name="packetized_image_stream")

    def elaborate(self, platform):
        m = Module()

        m.d.comb += self.output.connect_upstream(
            self.input, exclude=["last", "frame_last", "line_last"])
        m.d.comb += self.output.last.eq(self.input.frame_last)

        return m
예제 #15
0
class WaveletCompressor(Elaboratable):
    """compresses an image stream using a wavelet compression algorithm"""
    def __init__(self, input: ImageStream, width, height):
        self.input = input
        self.width = width
        self.height = height

        max_input_word = 2**len(self.input.payload)
        self.possible_run_lengths = [2, 4, 8, 16, 32, 64, 128, 256]
        self.huffmann_frequencies = {
            **{k: 1
               for k in range(max_input_word)},
            **{
                k: 10
                for k in range(max_input_word, max_input_word + len(self.possible_run_lengths))
            }
        }

        self.output = PacketizedStream(self.input.payload.shape())

    def elaborate(self, platform):
        m = Module()

        wavelet = m.submodules.wavelet = MultiStageWavelet2D(self.input,
                                                             self.width,
                                                             self.height,
                                                             stages=3)
        packetizer = m.submodules.packetizer = ImageStream2PacketizedStream(
            wavelet.output)

        bit_stuffing_input = VariableWidthStream(self.input.payload.shape(),
                                                 reset_width=len(
                                                     self.input.payload))
        with m.If(packetizer.output.is_hf):
            rle_input = PacketizedStream()
            m.d.comb += rle_input.connect_upstream(packetizer.output)
            rle = m.submodules.rle = ZeroRleEncoder(rle_input,
                                                    self.possible_run_lengths)
            huffman = m.submodules.huffman = HuffmanEncoder(rle.output)
            m.d.comb += bit_stuffing_input.connect_upstream(huffman.output)
        with m.Else():
            m.d.comb += bit_stuffing_input.connect_upstream(packetizer.output)

        bit_stuffing = m.submodules.bit_stuffing = BitStuffer(
            bit_stuffing_input, len(self.output.payload))
        m.d.comb += self.output.connect_upstream(bit_stuffing.output)

        return m
예제 #16
0
    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))
예제 #17
0
class DsiPhy(Elaboratable):
    def __init__(self, resource, num_lanes, ddr_domain, ck_domain):
        self.resource = resource
        self.num_lanes = num_lanes
        self.ddr_domain = ddr_domain
        self.ck_domain = ck_domain

        self.control_input = PacketizedStream(8)
        self.control_output = PacketizedStream(8)
        self.hs_input = PacketizedStream(8 * num_lanes)
        self.request_hs = ControlSignal()


    def elaborate(self, platform: Platform):
        resource = platform.request(*self.resource, xdr={"hs_ck": 2, **{f"hs_d{i}": 2 for i in range(self.num_lanes)}})

        m = Module()

        lanes = []
        for i in range(2):
            lane = DPhyDataLane(
                lp_pins=getattr(resource, f"lp_d{i}"),
                hs_pins=getattr(resource, f"hs_d{i}"),
                can_lp=(i == 0),
                ddr_domain=self.ddr_domain
            )
            m.submodules[f"lane_d{i}"] = lane
            lanes.append(lane)

        lane0 = lanes[0]
        m.d.comb += lane0.control_input.connect_upstream(self.control_input)
        m.d.comb += self.control_output.connect_upstream(lane0.control_output)

        m.d.comb += self.hs_input.ready.eq(lane0.hs_input.ready)
        for i, lane in enumerate(lanes):
            m.d.comb += lane.hs_input.payload.eq(self.hs_input.payload[i * 8: (i+1) * 8])
            m.d.comb += lane.hs_input.valid.eq(self.hs_input.valid)
            m.d.comb += lane.hs_input.last.eq(self.hs_input.last)

        lane_ck = m.submodules.lane_ck = DPhyClockLane(resource.lp_ck, resource.hs_ck, ck_domain=self.ck_domain)
        m.d.comb += lane_ck.request_hs.eq(self.request_hs)

        return m
예제 #18
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)
예제 #19
0
    def test_hello_world(self):
        platform = SimPlatform()
        m = Module()

        input = PacketizedStream(8)
        input_data = "hello, world :)"
        distribution = defaultdict(lambda: 0)
        for c in input_data:
            distribution[ord(c)] += 1
        huffman = m.submodules.huffman = HuffmanEncoder(input, distribution)

        def write_process():
            for i, c in enumerate(input_data):
                yield from write_to_stream(input,
                                           payload=ord(c),
                                           last=(i == len(input_data) - 1))

        def read_process():
            read = ""
            while True:
                data, length, last = (yield from read_from_stream(
                    huffman.output,
                    extract=("payload", "current_width", "last")))
                bitstring = "{:0255b}".format(data)[::-1][:length]
                read += bitstring
                if last:
                    break
            print(read)
            decode_iter = bitarray(read).iterdecode(
                {k: bitarray(v[::-1])
                 for k, v in huffman.table.items()})
            decoded = ""
            try:
                for c in decode_iter:
                    decoded += chr(c)
            except ValueError:  # Decoding may not finish with the byte boundary
                pass
            self.assertEqual(input_data, decoded)

        platform.add_sim_clock("sync", 100e6)
        platform.add_process(write_process, "sync")
        platform.sim(m, read_process)
예제 #20
0
    def test_hello_world_bit_stuffing(self):
        platform = SimPlatform()
        m = Module()

        input = PacketizedStream(8)
        input_data = "hello, world :)"
        distribution = defaultdict(lambda: 0)
        for c in input_data:
            distribution[ord(c)] += 1
        huffman = m.submodules.huffman = HuffmanEncoder(input, distribution)
        bit_stuffing = m.submodules.bit_stuffing = BitStuffer(
            huffman.output, 8)

        def write_process():
            for i, c in enumerate(input_data):
                yield from write_to_stream(input,
                                           payload=ord(c),
                                           last=(i == len(input_data) - 1))

        def read_process():
            read = []
            while True:
                payload, last = (yield from
                                 read_from_stream(bit_stuffing.output,
                                                  extract=("payload", "last")))
                read.append("{:08b}".format(payload))
                if last:
                    break
            read_bitarray = "".join(x[::-1] for x in read)
            print(read_bitarray)
            decode_iter = bitarray(read_bitarray).iterdecode(
                {k: bitarray(v[::-1])
                 for k, v in huffman.table.items()})
            for c, expected in zip(decode_iter, input_data):
                self.assertEqual(chr(c), expected)

        platform.add_sim_clock("sync", 100e6)
        platform.add_process(write_process, "sync")
        platform.sim(m, read_process)
예제 #21
0
    def test_PacketizedStream2ImageStream(self):
        platform = SimPlatform()
        input_stream = PacketizedStream(32)
        dut = PacketizedStream2ImageStream(input_stream, width=10)

        def write_process():
            for frame in range(10):
                yield from write_packet_to_stream(input_stream,
                                                  [0 for _ in range(100)])

        platform.add_process(write_process, "sync")

        def read_process():
            for frame in range(10):
                frame = yield from read_frame_from_stream(dut.output)
                self.assertEqual(len(frame), 10)
                self.assertTrue(all(len(l) == 10 for l in frame))

        platform.add_process(read_process, "sync")

        platform.add_sim_clock("sync", 100e6)
        platform.sim(dut)
예제 #22
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)
예제 #23
0
 def test_output_stream_contract(self):
     input_stream = PacketizedStream(8)
     mem = Memory(width=32, depth=128, init=[i + 2 for i in range(128)])
     dut = StreamMemoryReader(input_stream, mem)
     verify_stream_output_contract(
         dut, support_modules=(LegalStreamSource(input_stream), ))
예제 #24
0
 def __init__(self, input: ImageStream):
     self.input = input
     self.output = PacketizedStream(self.input.payload.shape(),
                                    name="packetized_image_stream")
예제 #25
0
    def __init__(self, packet_length_stream: BasicStream,
                 data_stream: BasicStream):
        self.packet_length_stream = packet_length_stream
        self.data_stream = data_stream

        self.output = PacketizedStream(self.data_stream.payload.shape())
예제 #26
0
class DPhyDataLane(Elaboratable):
    """ A mipi D-Phy Data lane that can handle bidirectional lp data transfer and unidirectional hs transfer.

    The `sync` domain of this module should run at 2x the LP Hold period. Eg if the hold period is 66ns, the sync domain should run at 30 Mhz
    (these are reasonable values btw). This is needed to be able to sample the incoming data during bus turnaround since there is no fixed phase relation (nyquist).
    """
    def __init__(self,
                 lp_pins: TristateIo,
                 hs_pins: TristateDdrIo,
                 initial_driving=True,
                 can_lp=False,
                 ddr_domain="sync"):
        self.lp_pins = lp_pins
        self.hs_pins = hs_pins
        self.can_lp = can_lp
        self.ddr_domain = ddr_domain

        if self.can_lp:
            # The control rx and control tx signals carry the raw escape mode packets.
            # A packet with length 1 and payload 0x0 indicates that we request a bus turnaround.
            # This in Not a valid MIPI Escape Entry Code so we simply repurpose that here.
            self.control_input = PacketizedStream(8)
            self.control_output = PacketizedStream(8)

        # the hs_input stream carries is polled to
        self.hs_input = PacketizedStream(8)

        self.is_hs = StatusSignal()
        self.is_driving = StatusSignal(
            reset=initial_driving) if can_lp else True
        self.bta_timeout = 1023
        self.bta_timeouts = StatusSignal(16)

    def elaborate(self, platform):
        m = Module()

        m.d.comb += self.lp_pins.oe.eq(self.is_driving)

        def delay_lp(cycles):
            return process_delay(m, cycles * 4)

        serializer_reset = Signal()
        m.d.comb += serializer_reset.eq(~(self.is_hs & self.is_driving))
        serializer = m.submodules.serializer = Serializer(
            self.hs_pins,
            width=8,
            ddr_domain=self.ddr_domain,
            reset=serializer_reset)

        @process_block
        def send_hs(data):
            return process_write_to_stream(m, serializer.input, payload=data)

        bta_timeout_counter = Signal(range(self.bta_timeout))
        bta_timeout_possible = Signal()

        with m.If(self.is_driving):
            lp = self.lp_pins.o[::-1]
            with m.FSM(name="tx_fsm") as fsm:
                fsm_status_reg(platform, m, fsm)
                with m.State("IDLE"):
                    m.d.comb += lp.eq(STOP)
                    if self.can_lp:
                        with m.If(self.control_input.valid
                                  & (self.control_input.payload == 0x00)
                                  & self.control_input.last):
                            m.d.comb += self.control_input.ready.eq(1)
                            m.next = "TURNAROUND_LP_REQUEST"
                        with m.Elif(self.control_input.valid):
                            m.next = "LP_REQUEST"
                        with m.Elif(self.hs_input.valid):
                            m.next = "HS_REQUEST"
                    else:
                        with m.If(self.hs_input.valid):
                            m.next = "HS_REQUEST"

                with Process(m, name="HS_REQUEST", to="HS_SEND") as p:
                    m.d.comb += lp.eq(HS_REQUEST)
                    p += delay_lp(1)
                    m.d.comb += lp.eq(BRIDGE)
                    p += delay_lp(3)
                    m.d.sync += self.is_hs.eq(1)
                    p += delay_lp(
                        4
                    )  # we are in HS-ZERO now and wait the constant part (150ns)
                    p += send_hs(Repl(0, 8))
                    p += send_hs(Repl(0, 8))
                    p += send_hs(Const(0b10111000, 8))

                with m.State("HS_SEND"):
                    with send_hs(self.hs_input.payload):
                        with m.If(self.hs_input.last):
                            m.next = "HS_END"
                        with m.Else():
                            m.next = "HS_SEND"
                            m.d.comb += self.hs_input.ready.eq(1)

                with Process(m, name="HS_END", to="IDLE") as p:
                    p += send_hs(Repl(~self.hs_input.payload[7], 8))
                    p += send_hs(Repl(~self.hs_input.payload[7], 8))
                    with m.If(NewHere(m)):
                        m.d.comb += self.hs_input.ready.eq(1)
                    p += m.If(serializer.is_idle)
                    m.d.sync += self.is_hs.eq(0)
                    p += process_delay(
                        m, 1
                    )  # TODO: this is currently tied to the way we do ddr (beaks when we change clock frequencies)
                    m.d.comb += lp.eq(STOP)
                    p += delay_lp(2)

                if self.can_lp:
                    with Process(m, name="LP_REQUEST", to="ESCAPE_0") as p:
                        m.d.comb += lp.eq(LP_REQUEST)
                        p += delay_lp(1)
                        m.d.comb += lp.eq(BRIDGE)
                        p += delay_lp(1)
                        m.d.comb += lp.eq(ESCAPE_REQUEST)
                        p += delay_lp(1)
                        m.d.comb += lp.eq(BRIDGE)
                        p += delay_lp(1)

                    for bit in range(8):
                        with m.State(f"ESCAPE_{bit}"):
                            with m.If(
                                    self.control_input.valid
                            ):  # after transmitting the first byte, this can be false. the mipi spec allows us to wait here (in space state)
                                with m.If(self.control_input.payload[bit]):
                                    m.d.comb += lp.eq(MARK_1)
                                with m.Else():
                                    m.d.comb += lp.eq(MARK_0)
                                with delay_lp(1):
                                    m.next = f"ESCAPE_{bit}_SPACE"
                        with m.State(f"ESCAPE_{bit}_SPACE"):
                            m.d.comb += lp.eq(SPACE)
                            if bit < 7:
                                with delay_lp(1):
                                    m.next = f"ESCAPE_{bit + 1}"
                            else:
                                with m.If(
                                        self.control_input.last
                                ):  # according to the stream contract, this may not change, until we assert ready :)
                                    with delay_lp(1):
                                        m.next = "ESCAPE_FINISH"
                                        m.d.comb += self.control_input.ready.eq(
                                            1)
                                with m.Else():
                                    with delay_lp(1):
                                        m.next = "ESCAPE_0"
                                        m.d.comb += self.control_input.ready.eq(
                                            1)

                    with Process(m, "ESCAPE_FINISH", to="IDLE") as p:
                        m.d.comb += lp.eq(MARK_1)
                        p += delay_lp(1)
                        m.d.comb += lp.eq(STOP)
                        p += delay_lp(
                            10
                        )  # TODO: reduce the delay; it is here to ease debugging :)

                    with Process(m,
                                 name="TURNAROUND_LP_REQUEST",
                                 to="TURNAROUND_RETURN") as p:
                        m.d.comb += lp.eq(LP_REQUEST)
                        p += delay_lp(1)
                        m.d.comb += lp.eq(BRIDGE)
                        p += delay_lp(1)
                        m.d.comb += lp.eq(TURNAROUND_REQUEST)
                        p += delay_lp(1)
                        m.d.comb += lp.eq(BRIDGE)
                        p += delay_lp(4)
                        m.d.sync += self.is_driving.eq(
                            0
                        )  # this makes us leave this FSM and enter the one below
                        m.d.sync += bta_timeout_counter.eq(0)
                        m.d.sync += bta_timeout_possible.eq(1)
                        p += process_delay(m, 1)

                    with Process(m, name="TURNAROUND_RETURN", to="IDLE") as p:
                        m.d.comb += lp.eq(STOP)
                        p += delay_lp(10)

        if self.can_lp:

            # we buffer the control output to be able to meet the stream contract
            control_output_unbuffered = PacketizedStream(8)
            control_output_buffer = m.submodules.control_output_buffer = StreamBuffer(
                control_output_unbuffered)
            m.d.comb += self.control_output.connect_upstream(
                control_output_buffer.output)

            with m.If(~self.is_driving):
                lp = Signal(2)
                m.submodules += FFSynchronizer(self.lp_pins.i[::-1], lp)

                with m.FSM(name="rx_fsm") as fsm:

                    def maybe_next(condition, next_state):
                        with m.If(condition):
                            m.next = next_state

                    def maybe_stop():
                        maybe_next(lp == STOP, "STOP")

                    with m.State("STOP"):
                        with m.If(bta_timeout_possible):
                            with m.If(bta_timeout_counter < self.bta_timeout):
                                m.d.sync += bta_timeout_counter.eq(
                                    bta_timeout_counter + 1)
                            with m.Else():
                                m.d.sync += self.bta_timeouts.eq(
                                    self.bta_timeouts + 1)
                                m.d.sync += self.is_driving.eq(1)
                                m.d.sync += bta_timeout_counter.eq(0)
                                m.d.sync += bta_timeout_possible.eq(0)
                        maybe_next(lp == LP_REQUEST, "AFTER-LP-REQUEST")
                        maybe_stop()

                    with m.State("AFTER-LP-REQUEST"):
                        m.d.sync += bta_timeout_possible.eq(0)
                        with m.If(lp == BRIDGE):
                            m.next = "AFTER-LP-REQUEST-BRIDGE"
                        maybe_stop()
                    with m.State("AFTER-LP-REQUEST-BRIDGE"):
                        with m.If(lp == ESCAPE_REQUEST):
                            m.next = "AFTER-ESCAPE-REQUEST"
                        with m.Elif(lp == TURNAROUND_REQUEST):
                            m.next = "AFTER-TURNAROUND-REQUEST"
                        maybe_stop()

                    with m.State("AFTER-TURNAROUND-REQUEST"):
                        with m.If(lp == BRIDGE):
                            with delay_lp(4):
                                m.next = "STOP"
                                m.d.sync += self.is_driving.eq(1)
                        maybe_stop()

                    with m.State("AFTER-ESCAPE-REQUEST"):
                        with m.If(lp == BRIDGE):
                            m.next = "ESCAPE_0"

                    # we keep track if we have already sent the currently or last received bit over our output stream.
                    # we send it either on the first bit of the next word or during the stop condition
                    outboxed = Signal(reset=1)

                    def maybe_finish_escape():
                        with m.If(lp == STOP):
                            m.next = "STOP"
                            m.d.sync += outboxed.eq(1)
                            with m.If(~outboxed):
                                m.d.comb += control_output_unbuffered.last.eq(
                                    1)
                                m.d.comb += control_output_unbuffered.valid.eq(
                                    1)

                    bit_value = Signal()
                    for bit in range(8):
                        with m.State(f"ESCAPE_{bit}"):
                            with m.If(lp == MARK_0):
                                m.d.sync += bit_value.eq(0)
                                m.next = f"ESCAPE_{bit}_SPACE"
                            with m.If(lp == MARK_1):
                                m.d.sync += bit_value.eq(1)
                                m.next = f"ESCAPE_{bit}_SPACE"
                            maybe_finish_escape()
                        with m.State(f"ESCAPE_{bit}_SPACE"):
                            with m.If(lp == SPACE):
                                if bit == 0:
                                    with m.If(~outboxed):
                                        m.d.comb += control_output_unbuffered.valid.eq(
                                            1)
                                        m.d.sync += outboxed.eq(1)

                                m.d.sync += control_output_unbuffered.payload[
                                    bit].eq(bit_value)
                                m.d.sync += outboxed.eq(0)
                                m.next = f"ESCAPE_{(bit + 1) % 8}"
                            maybe_finish_escape()

        return m
예제 #27
0
    def elaborate(self, platform):
        m = Module()

        m.d.comb += self.lp_pins.oe.eq(self.is_driving)

        def delay_lp(cycles):
            return process_delay(m, cycles * 4)

        serializer_reset = Signal()
        m.d.comb += serializer_reset.eq(~(self.is_hs & self.is_driving))
        serializer = m.submodules.serializer = Serializer(
            self.hs_pins,
            width=8,
            ddr_domain=self.ddr_domain,
            reset=serializer_reset)

        @process_block
        def send_hs(data):
            return process_write_to_stream(m, serializer.input, payload=data)

        bta_timeout_counter = Signal(range(self.bta_timeout))
        bta_timeout_possible = Signal()

        with m.If(self.is_driving):
            lp = self.lp_pins.o[::-1]
            with m.FSM(name="tx_fsm") as fsm:
                fsm_status_reg(platform, m, fsm)
                with m.State("IDLE"):
                    m.d.comb += lp.eq(STOP)
                    if self.can_lp:
                        with m.If(self.control_input.valid
                                  & (self.control_input.payload == 0x00)
                                  & self.control_input.last):
                            m.d.comb += self.control_input.ready.eq(1)
                            m.next = "TURNAROUND_LP_REQUEST"
                        with m.Elif(self.control_input.valid):
                            m.next = "LP_REQUEST"
                        with m.Elif(self.hs_input.valid):
                            m.next = "HS_REQUEST"
                    else:
                        with m.If(self.hs_input.valid):
                            m.next = "HS_REQUEST"

                with Process(m, name="HS_REQUEST", to="HS_SEND") as p:
                    m.d.comb += lp.eq(HS_REQUEST)
                    p += delay_lp(1)
                    m.d.comb += lp.eq(BRIDGE)
                    p += delay_lp(3)
                    m.d.sync += self.is_hs.eq(1)
                    p += delay_lp(
                        4
                    )  # we are in HS-ZERO now and wait the constant part (150ns)
                    p += send_hs(Repl(0, 8))
                    p += send_hs(Repl(0, 8))
                    p += send_hs(Const(0b10111000, 8))

                with m.State("HS_SEND"):
                    with send_hs(self.hs_input.payload):
                        with m.If(self.hs_input.last):
                            m.next = "HS_END"
                        with m.Else():
                            m.next = "HS_SEND"
                            m.d.comb += self.hs_input.ready.eq(1)

                with Process(m, name="HS_END", to="IDLE") as p:
                    p += send_hs(Repl(~self.hs_input.payload[7], 8))
                    p += send_hs(Repl(~self.hs_input.payload[7], 8))
                    with m.If(NewHere(m)):
                        m.d.comb += self.hs_input.ready.eq(1)
                    p += m.If(serializer.is_idle)
                    m.d.sync += self.is_hs.eq(0)
                    p += process_delay(
                        m, 1
                    )  # TODO: this is currently tied to the way we do ddr (beaks when we change clock frequencies)
                    m.d.comb += lp.eq(STOP)
                    p += delay_lp(2)

                if self.can_lp:
                    with Process(m, name="LP_REQUEST", to="ESCAPE_0") as p:
                        m.d.comb += lp.eq(LP_REQUEST)
                        p += delay_lp(1)
                        m.d.comb += lp.eq(BRIDGE)
                        p += delay_lp(1)
                        m.d.comb += lp.eq(ESCAPE_REQUEST)
                        p += delay_lp(1)
                        m.d.comb += lp.eq(BRIDGE)
                        p += delay_lp(1)

                    for bit in range(8):
                        with m.State(f"ESCAPE_{bit}"):
                            with m.If(
                                    self.control_input.valid
                            ):  # after transmitting the first byte, this can be false. the mipi spec allows us to wait here (in space state)
                                with m.If(self.control_input.payload[bit]):
                                    m.d.comb += lp.eq(MARK_1)
                                with m.Else():
                                    m.d.comb += lp.eq(MARK_0)
                                with delay_lp(1):
                                    m.next = f"ESCAPE_{bit}_SPACE"
                        with m.State(f"ESCAPE_{bit}_SPACE"):
                            m.d.comb += lp.eq(SPACE)
                            if bit < 7:
                                with delay_lp(1):
                                    m.next = f"ESCAPE_{bit + 1}"
                            else:
                                with m.If(
                                        self.control_input.last
                                ):  # according to the stream contract, this may not change, until we assert ready :)
                                    with delay_lp(1):
                                        m.next = "ESCAPE_FINISH"
                                        m.d.comb += self.control_input.ready.eq(
                                            1)
                                with m.Else():
                                    with delay_lp(1):
                                        m.next = "ESCAPE_0"
                                        m.d.comb += self.control_input.ready.eq(
                                            1)

                    with Process(m, "ESCAPE_FINISH", to="IDLE") as p:
                        m.d.comb += lp.eq(MARK_1)
                        p += delay_lp(1)
                        m.d.comb += lp.eq(STOP)
                        p += delay_lp(
                            10
                        )  # TODO: reduce the delay; it is here to ease debugging :)

                    with Process(m,
                                 name="TURNAROUND_LP_REQUEST",
                                 to="TURNAROUND_RETURN") as p:
                        m.d.comb += lp.eq(LP_REQUEST)
                        p += delay_lp(1)
                        m.d.comb += lp.eq(BRIDGE)
                        p += delay_lp(1)
                        m.d.comb += lp.eq(TURNAROUND_REQUEST)
                        p += delay_lp(1)
                        m.d.comb += lp.eq(BRIDGE)
                        p += delay_lp(4)
                        m.d.sync += self.is_driving.eq(
                            0
                        )  # this makes us leave this FSM and enter the one below
                        m.d.sync += bta_timeout_counter.eq(0)
                        m.d.sync += bta_timeout_possible.eq(1)
                        p += process_delay(m, 1)

                    with Process(m, name="TURNAROUND_RETURN", to="IDLE") as p:
                        m.d.comb += lp.eq(STOP)
                        p += delay_lp(10)

        if self.can_lp:

            # we buffer the control output to be able to meet the stream contract
            control_output_unbuffered = PacketizedStream(8)
            control_output_buffer = m.submodules.control_output_buffer = StreamBuffer(
                control_output_unbuffered)
            m.d.comb += self.control_output.connect_upstream(
                control_output_buffer.output)

            with m.If(~self.is_driving):
                lp = Signal(2)
                m.submodules += FFSynchronizer(self.lp_pins.i[::-1], lp)

                with m.FSM(name="rx_fsm") as fsm:

                    def maybe_next(condition, next_state):
                        with m.If(condition):
                            m.next = next_state

                    def maybe_stop():
                        maybe_next(lp == STOP, "STOP")

                    with m.State("STOP"):
                        with m.If(bta_timeout_possible):
                            with m.If(bta_timeout_counter < self.bta_timeout):
                                m.d.sync += bta_timeout_counter.eq(
                                    bta_timeout_counter + 1)
                            with m.Else():
                                m.d.sync += self.bta_timeouts.eq(
                                    self.bta_timeouts + 1)
                                m.d.sync += self.is_driving.eq(1)
                                m.d.sync += bta_timeout_counter.eq(0)
                                m.d.sync += bta_timeout_possible.eq(0)
                        maybe_next(lp == LP_REQUEST, "AFTER-LP-REQUEST")
                        maybe_stop()

                    with m.State("AFTER-LP-REQUEST"):
                        m.d.sync += bta_timeout_possible.eq(0)
                        with m.If(lp == BRIDGE):
                            m.next = "AFTER-LP-REQUEST-BRIDGE"
                        maybe_stop()
                    with m.State("AFTER-LP-REQUEST-BRIDGE"):
                        with m.If(lp == ESCAPE_REQUEST):
                            m.next = "AFTER-ESCAPE-REQUEST"
                        with m.Elif(lp == TURNAROUND_REQUEST):
                            m.next = "AFTER-TURNAROUND-REQUEST"
                        maybe_stop()

                    with m.State("AFTER-TURNAROUND-REQUEST"):
                        with m.If(lp == BRIDGE):
                            with delay_lp(4):
                                m.next = "STOP"
                                m.d.sync += self.is_driving.eq(1)
                        maybe_stop()

                    with m.State("AFTER-ESCAPE-REQUEST"):
                        with m.If(lp == BRIDGE):
                            m.next = "ESCAPE_0"

                    # we keep track if we have already sent the currently or last received bit over our output stream.
                    # we send it either on the first bit of the next word or during the stop condition
                    outboxed = Signal(reset=1)

                    def maybe_finish_escape():
                        with m.If(lp == STOP):
                            m.next = "STOP"
                            m.d.sync += outboxed.eq(1)
                            with m.If(~outboxed):
                                m.d.comb += control_output_unbuffered.last.eq(
                                    1)
                                m.d.comb += control_output_unbuffered.valid.eq(
                                    1)

                    bit_value = Signal()
                    for bit in range(8):
                        with m.State(f"ESCAPE_{bit}"):
                            with m.If(lp == MARK_0):
                                m.d.sync += bit_value.eq(0)
                                m.next = f"ESCAPE_{bit}_SPACE"
                            with m.If(lp == MARK_1):
                                m.d.sync += bit_value.eq(1)
                                m.next = f"ESCAPE_{bit}_SPACE"
                            maybe_finish_escape()
                        with m.State(f"ESCAPE_{bit}_SPACE"):
                            with m.If(lp == SPACE):
                                if bit == 0:
                                    with m.If(~outboxed):
                                        m.d.comb += control_output_unbuffered.valid.eq(
                                            1)
                                        m.d.sync += outboxed.eq(1)

                                m.d.sync += control_output_unbuffered.payload[
                                    bit].eq(bit_value)
                                m.d.sync += outboxed.eq(0)
                                m.next = f"ESCAPE_{(bit + 1) % 8}"
                            maybe_finish_escape()

        return m
예제 #28
0
 def test_output_stream_contract(self):
     input_stream = PacketizedStream(32)
     dut = GenericMetadataWrapper(input_stream, lambda i: BufferedSyncStreamFIFO(i, 10))
     verify_stream_output_contract(dut, support_modules=(LegalStreamSource(input_stream),))
예제 #29
0
 def test_output_stream_contract(self):
     input_stream = PacketizedStream(32)
     dut = LastWrapper(input_stream, lambda i: BufferedSyncStreamFIFO(i, 10), last_rle_bits=3)
     verify_stream_output_contract(dut, support_modules=(LegalStreamSource(input_stream),))
예제 #30
0
 def test_last_wrapper_contract(self):
     dut = LastWrapperContract(LastWrapper(PacketizedStream(32), lambda i: BufferedSyncStreamFIFO(i, 10)))
     assert_formal(dut, mode="hybrid", depth=10)