Esempio n. 1
0
class ClockDebug(Elaboratable):
    def __init__(self, domain_name, reset_less=False):
        self.domain_name = domain_name
        self.reset_less = reset_less

        self.counter = StatusSignal(32)
        if not self.reset_less:
            self.is_reset = StatusSignal()

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

        m.d[self.domain_name] += self.counter.eq(self.counter + 1)
        if not self.reset_less:
            m.d.comb += self.is_reset.eq(ResetSignal(self.domain_name))

        return m

    @driver_property
    def mhz(self):
        from time import sleep, time
        initial_counter = self.counter
        start = time()
        sleep(0.1)
        counter_difference = (self.counter - initial_counter)
        return counter_difference * (1 / (time() - start)) / 1e6
Esempio n. 2
0
class StreamFIFO(Elaboratable):
    def __init__(self, input: Stream, fifo_type, output_stream_name="fifo_out", **fifo_args):
        self.input = input
        self.output = input.clone(name=output_stream_name)
        if "r_domain" in fifo_args:
            self.output_domain = fifo_args["r_domain"]
        self.fifo = fifo_type(width=len(Cat(self.input.payload_signals.values())), **fifo_args)
        self.depth = fifo_args['depth']

        self.r_level = StatusSignal(range(self.fifo.depth + 1))
        self.w_level = StatusSignal(range(self.fifo.depth + 1))

    def elaborate(self, platform):
        m = Module()
        fifo = m.submodules.fifo = self.fifo

        if self.depth == 0:
            m.d.comb += self.output.connect_upstream(self.input)
        else:
            m.d.comb += self.r_level.eq(fifo.r_level)
            m.d.comb += self.w_level.eq(fifo.w_level)

            m.d.comb += self.input.ready.eq(fifo.w_rdy)
            m.d.comb += fifo.w_data.eq(Cat(self.input.payload_signals.values()))
            m.d.comb += fifo.w_en.eq(self.input.valid)

            m.d.comb += Cat(self.output.payload_signals.values()).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
Esempio n. 3
0
    def elaborate(self, platform):
        m = Module()

        with m.If(self.stream.valid & ~self.stream.ready):
            m.d.sync += self.valid_not_ready.eq(self.valid_not_ready + 1)
        with m.If(self.stream.ready & ~self.stream.valid):
            m.d.sync += self.ready_not_valid.eq(self.ready_not_valid + 1)

        m.d.sync += self.reference_counter.eq(self.reference_counter + 1)

        transaction = Signal()
        m.d.comb += transaction.eq(self.stream.valid & self.stream.ready)
        with m.If(transaction):
            m.d.sync += self.successful_transactions_counter.eq(
                self.successful_transactions_counter + 1)

        m.d.comb += self.current_ready.eq(self.stream.ready)
        m.d.comb += self.current_valid.eq(self.stream.valid)

        for name, signal in self.stream.payload_signals.items():
            if len(signal) == 1:
                m.submodules[name] = MetadataSignalDebug(signal, transaction)
            else:
                current_state = StatusSignal(signal.shape())
                m.d.comb += current_state.eq(signal)
                setattr(self, "current_{}".format(name), current_state)
                last_transaction_state = StatusSignal(signal.shape())
                with m.If(transaction):
                    m.d.sync += last_transaction_state.eq(signal)
                setattr(self, "last_transaction_{}".format(name),
                        last_transaction_state)

        return m
Esempio n. 4
0
class Tracer(Elaboratable):
    def __init__(self, fsm: FSM, trace_length=128):
        self.fsm = fsm
        self.trace_length = trace_length
        self.write_ptr = StatusSignal(range(trace_length))
        self.trace_decoder = {}

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

        mem = m.submodules.mem = SocMemory(width=len(self.fsm.state), depth=self.trace_length, soc_write=False)
        write_port = m.submodules.write_port = mem.write_port(domain="sync")
        with m.If(Changed(m, self.fsm.state)):
            m.d.comb += write_port.en.eq(1)
            m.d.comb += write_port.data.eq(self.fsm.state)
            m.d.comb += write_port.addr.eq(self.write_ptr)
            with m.If(self.write_ptr < self.trace_length):
                m.d.sync += self.write_ptr.eq(self.write_ptr + 1)
            with m.Else():
                m.d.sync += self.write_ptr.eq(0)

        self.trace_decoder.update(self.fsm.decoding)

        return m

    @driver_method
    def print_trace(self):
        r = list(range(self.trace_length))
        for i in r[self.write_ptr:] + r[:self.write_ptr]:
            print(self.trace_decoder[self.mem[i]])
Esempio n. 5
0
    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
Esempio n. 6
0
class Ft60xLegalizer(Elaboratable):
    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 elaborate(self, platform):
        m = Module()

        padding_ctr = Signal.like(self.padding)
        frame_len_ctr = Signal.like(self.frame_len)

        input_transaction = self.input.ready & self.input.valid
        with m.FSM():
            with m.State("ACTIVE"):
                m.d.comb += self.input.ready.eq(self.output.ready)
                m.d.comb += self.output.valid.eq(self.input.valid)
                with m.If(
                        self.input.payload == 0
                ):  # we disallow the transfer of 0 to ease the alignment detection TODO: this only really works for 8 bit this way
                    m.d.comb += self.output.payload.eq(1)
                with m.Else():
                    m.d.comb += self.output.payload.eq(self.input.payload)
                with m.If(input_transaction):
                    m.d.sync += frame_len_ctr.eq(frame_len_ctr + 1)
                with m.If(self.input.last & input_transaction):
                    m.next = "PADDING"
                    m.d.sync += padding_ctr.eq(0)
            with m.State("PADDING"):
                m.d.comb += self.output.valid.eq(1)
                m.d.comb += self.input.ready.eq(0)
                m.d.comb += self.output.payload.eq(0)
                with m.If(self.output.ready):
                    with m.If(padding_ctr < self.padding - 1):
                        m.d.sync += padding_ctr.eq(padding_ctr + 1)
                        m.d.sync += frame_len_ctr.eq(frame_len_ctr + 1)
                    with m.Else():
                        m.next = "ACTIVE"
                        m.d.sync += self.frame_len.eq(frame_len_ctr + 1)
                        with m.If(self.frame_len != frame_len_ctr + 1):
                            m.d.sync += self.frame_len_changed.eq(
                                self.frame_len_changed + 1)
                        m.d.sync += frame_len_ctr.eq(0)
        return m
Esempio n. 7
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
Esempio n. 8
0
class AxiWriter(Elaboratable):
    def __init__(self,
                 address_source: BasicStream,
                 data_source: BasicStream,
                 axi=None):
        self.address_source = address_source
        self.data_source = data_source
        self.axi = axi

        self.axi_address_ready = StatusSignal()
        self.axi_data_ready = StatusSignal()
        self.write_response_ok = StatusSignal(32)
        self.write_response_err = StatusSignal(32)

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

        burster = m.submodules.burster = AxiWriterBurster(
            self.address_source, self.data_source)

        axi = if_none_get_zynq_hp_port(self.axi, m, platform)
        for fifo_signal_name in [
                "write_address_fifo_level", "write_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)

        m.d.comb += axi.write_data.connect_upstream(burster.data_output)
        m.d.comb += axi.write_address.connect_upstream(burster.address_output)

        # we do not currently care about the write responses
        m.d.comb += axi.write_response.ready.eq(1)
        with m.If(axi.write_response.valid):
            with m.If(axi.write_response.resp == AxiResponse.OKAY):
                m.d.sync += self.write_response_ok.eq(self.write_response_ok +
                                                      1)
            with m.Else():
                m.d.sync += self.write_response_err.eq(
                    self.write_response_err + 1)

        m.d.comb += self.axi_data_ready.eq(axi.write_data.ready)
        m.d.comb += self.axi_address_ready.eq(axi.write_address.ready)

        info_axi_address = m.submodules.info_axi_address = StreamInfo(
            axi.write_address)
        info_axi_data = m.submodules.info_axi_data = StreamInfo(axi.write_data)

        return m
Esempio n. 9
0
class ConsolePacketSink(Elaboratable):
    def __init__(self, input: PacketizedStream, max_packet_size=1024):
        self.max_packet_size = max_packet_size

        self.reset = ControlSignal()
        self.write_pointer = StatusSignal(range(self.max_packet_size))
        self.packet_done = StatusSignal()
        self.memory = SocMemory(
            width=len(input.payload), depth=self.max_packet_size,
            soc_write=False, attrs=dict(syn_ramstyle="block_ram")
        )

        self.input = input

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

        memory = m.submodules.memory = self.memory
        write_port = m.submodules.write_port = memory.write_port(domain="sync")
        with m.If(~self.packet_done & (self.write_pointer < self.max_packet_size)):
            m.d.comb += self.input.ready.eq(1)
            with m.If(self.input.valid):
                m.d.comb += write_port.en.eq(1)
                m.d.comb += write_port.addr.eq(self.write_pointer)
                m.d.comb += write_port.data.eq(self.input.payload)
                m.d.sync += self.write_pointer.eq(self.write_pointer + 1)
                with m.If(self.input.last):
                    m.d.sync += self.packet_done.eq(1)

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


        return m

    @driver_method
    def read_packet(self, timeout=0):
        from time import sleep
        for i in range(int(timeout * 10)):
            if self.packet_done:
                break
            sleep(0.1)
        if not self.packet_done:
            return None

        to_return = [self.memory[i] for i in range(self.write_pointer)]
        self.reset = not self.reset
        return to_return
Esempio n. 10
0
        class Top(Elaboratable):
            def __init__(self):
                self.up_counter = StatusSignal(16)
                self.down_counter = StatusSignal(16, reset=1000)

            def elaborate(self, platform):
                m = Module()
                m.d.sync += self.up_counter.eq(self.up_counter + 1)
                m.d.sync += self.down_counter.eq(self.down_counter - 1)

                add_ila(platform, trace_length=100)
                probe(m, self.up_counter)
                probe(m, self.down_counter)
                trigger(m, self.up_counter > 200)
                return m
Esempio n. 11
0
class DPhyClockLane(Elaboratable):
    def __init__(self, lp_pins: TristateIo, hs_pins: TristateDdrIo, ck_domain):
        self.lp_pins = lp_pins
        self.hs_pins = hs_pins
        self.ck_domain = ck_domain

        self.request_hs = Signal()
        self.is_hs = StatusSignal()

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

        m.d.comb += self.lp_pins.oe.eq(1)
        m.d.comb += self.hs_pins.oe.eq(self.is_hs)
        m.d.comb += self.hs_pins.o_clk.eq(ClockSignal(self.ck_domain))
        lp = self.lp_pins.o[::-1]

        with m.FSM():
            with m.State("LP"):
                m.d.comb += lp.eq(STOP)
                with m.If(self.request_hs):
                    m.next = "HS_REQUEST"
            with Process(m, "HS_REQUEST", to="HS") as p:
                m.d.comb += lp.eq(STOP)
                p += process_delay(
                    m, 6)  # we need to stay in lp state for some minimum time
                m.d.comb += lp.eq(HS_REQUEST)
                p += process_delay(m, 6)
                m.d.comb += lp.eq(BRIDGE)
                p += process_delay(m, 5)
            with m.State("HS"):
                m.d.comb += lp.eq(0)
                m.d.comb += self.is_hs.eq(1)
                m.d.comb += self.hs_pins.o0.eq(fake_differential(1))
                m.d.comb += self.hs_pins.o1.eq(fake_differential(0))
                with m.If(~self.request_hs):
                    m.next = "HS_END"
            with Process(m, name="HS_END", to="LP") as p:
                m.d.comb += self.is_hs.eq(1)
                m.d.comb += lp.eq(0)
                m.d.comb += self.hs_pins.o0.eq(fake_differential(0))
                m.d.comb += self.hs_pins.o1.eq(fake_differential(0))
                p += process_delay(m, 2)  # delay minimum 60ns

        return m
Esempio n. 12
0
class InflexibleSinkDebug(Elaboratable):
    def __init__(self, stream):
        self.stream = stream
        self.invalid = StatusSignal(32)

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

        with m.If(self.stream.ready & ~self.stream.valid):
            m.d.sync += self.invalid.eq(self.invalid + 1)

        return m
Esempio n. 13
0
def fsm_status_reg(platform, m, fsm: FSM):
    if isinstance(platform, SocPlatform):
        fsm_state = StatusSignal(
            name=f"{fsm.state.name}_reg"
        )  # TODO: use meaningful shape value here (needs deferring)

        def signal_fixup_hook(platform, top_fragment: Fragment, sames):
            fsm_state.width = fsm.state.width
            fsm_state.decoder = fsm.state.decoder

        platform.prepare_hooks.insert(0, signal_fixup_hook)
        m.d.comb += fsm_state.eq(fsm.state)
Esempio n. 14
0
class ImageSplitter2(Elaboratable):
    """Splits an Image into n chunks horizontally"""
    def __init__(self, input: ImageStream, chunk_width, n_chunks, height):
        self.chunk_width = chunk_width
        self.height = height
        self.n_chunks = n_chunks
        self.input = input

        self.x_ctr = StatusSignal(16)
        self.y_ctr = StatusSignal(16)

        self.outputs = [
            self.input.clone(f'splitter_output_{i}') for i in range(n_chunks)
        ]

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

        with m.If(self.input.ready & self.input.valid):
            m.d.sync += self.x_ctr.eq(self.x_ctr + 1)
            with m.If(self.input.line_last):
                m.d.sync += self.x_ctr.eq(0)
                m.d.sync += self.y_ctr.eq(self.y_ctr + 1)
            with m.If(self.input.frame_last):
                m.d.sync += self.y_ctr.eq(0)

        for i, output in enumerate(self.outputs):
            start, end = i * self.chunk_width, (i + 1) * self.chunk_width
            m.d.comb += self.input.ready.eq(
                1)  # if noone is responsible, we dont hang everything
            with m.If((self.x_ctr >= start) & (self.x_ctr < end)):
                m.d.comb += output.connect_upstream(
                    self.input, exclude=['frame_last', 'line_last'])
                m.d.comb += output.line_last.eq(self.x_ctr == end - 1)
                m.d.comb += output.frame_last.eq((self.x_ctr == end - 1)
                                                 & (self.y_ctr == self.height -
                                                    1))

        return m
Esempio n. 15
0
class IDelayCtrl(Elaboratable):
    def __init__(self, refclk_domain):
        self.refclk_domain = refclk_domain
        self.ready = StatusSignal()

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

        idelay_ctl = m.submodules.idelay_ctl = _IDelayCtrl()
        m.d.comb += self.ready.eq(idelay_ctl.rdy)
        m.d.comb += idelay_ctl.refclk.eq(ClockSignal(self.refclk_domain))
        m.d.comb += idelay_ctl.rst.eq(ResetSignal(self.refclk_domain))

        return m
Esempio n. 16
0
class HdmiTimingGenerator(Elaboratable):
    def __init__(self, video_timing, vertical_signals_shape=range(8000), horizontal_signals_shape=range(4000)):
        self.hscan = ControlSignal(horizontal_signals_shape, reset=video_timing.hscan)
        self.vscan = ControlSignal(vertical_signals_shape, reset=video_timing.vscan)
        self.width = ControlSignal(horizontal_signals_shape, reset=video_timing.hres)
        self.height = ControlSignal(vertical_signals_shape, reset=video_timing.vres)
        self.hsync_start = ControlSignal(horizontal_signals_shape, reset=video_timing.hsync_start)
        self.hsync_end = ControlSignal(horizontal_signals_shape, reset=video_timing.hsync_end)
        self.vsync_start = ControlSignal(vertical_signals_shape, reset=video_timing.vsync_start)
        self.vsync_end = ControlSignal(vertical_signals_shape, reset=video_timing.vsync_end)

        self.x = StatusSignal(horizontal_signals_shape,)
        self.y = StatusSignal(vertical_signals_shape)
        self.active = StatusSignal()
        self.is_blanking_x = StatusSignal()
        self.is_blanking_y = StatusSignal()
        self.hsync = StatusSignal()
        self.vsync = StatusSignal()

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

        # set the xy coordinates
        with m.If(self.x < self.hscan - 1):
            m.d.sync += self.x.eq(self.x + 1)
        with m.Else():
            m.d.sync += self.x.eq(0)
            with m.If(self.y < self.vscan - 1):
                m.d.sync += self.y.eq(self.y + 1)
            with m.Else():
                m.d.sync += self.y.eq(0)

        m.d.comb += [
            self.is_blanking_x.eq(self.x >= self.width),
            self.is_blanking_y.eq(self.y >= self.height),
            self.active.eq((self.x < self.width) & (self.y < self.height)),
            self.hsync.eq((self.x >= self.hsync_start) & (self.x < self.hsync_end)),
            self.vsync.eq((self.y >= self.vsync_start) & (self.y < self.vsync_end))
        ]

        return m
Esempio n. 17
0
class MetadataSignalDebug(Elaboratable):
    def __init__(self, signal, transaction):
        assert len(signal) == 1
        self.signal = signal
        self.transaction = transaction

        self.cycle_1_length = StatusSignal(32)
        self.cycle_1_length_changed = StatusSignal(32)
        self.cycle_0_length = StatusSignal(32)
        self.cycle_0_length_changed = StatusSignal(32)
        self.cycles = StatusSignal(32)
        self.current = StatusSignal()

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

        m.d.comb += self.current.eq(self.signal)

        cycle_0_counter = Signal(32)
        cycle_1_counter = Signal(32)

        with m.If(self.transaction):
            with m.If(self.signal):
                m.d.sync += cycle_0_counter.eq(0)
                with m.If(cycle_0_counter != 0):
                    m.d.sync += self.cycle_0_length.eq(cycle_0_counter)
                    with m.If(self.cycle_0_length != cycle_0_counter):
                        m.d.sync += self.cycle_0_length_changed.eq(
                            self.cycle_0_length_changed + 1)
                m.d.sync += cycle_1_counter.eq(cycle_1_counter + 1)
            with m.Else():
                m.d.sync += cycle_1_counter.eq(0)
                with m.If(cycle_1_counter != 0):
                    m.d.sync += self.cycle_1_length.eq(cycle_1_counter)
                    with m.If(self.cycle_1_length != cycle_1_counter):
                        m.d.sync += self.cycle_1_length_changed.eq(
                            self.cycle_1_length_changed + 1)
                m.d.sync += cycle_0_counter.eq(cycle_0_counter + 1)

            signal_last = Signal()
            m.d.sync += signal_last.eq(self.signal)
            with m.If(self.signal & ~signal_last):
                m.d.sync += self.cycles.eq(self.cycles + 1)

        return m

    @driver_property
    def cycle_length(self):
        return self.cycle_0_length + self.cycle_1_length
Esempio n. 18
0
    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
Esempio n. 19
0
class PacketizedStream2ImageStream(Elaboratable):
    """Convert a Packetized stream to an Image stream by creating lines with `width`"""
    def __init__(self, input: PacketizedStream, width):
        self.input = input
        self.width = width
        self.not_exact_number_of_lines_error = StatusSignal(32)
        self.output = ImageStream(input.payload.shape(),
                                  name="adapted_image_stream")

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

        line_ctr = Signal(16)

        m.d.comb += self.output.connect_upstream(
            self.input, only=["ready", "valid", "payload"])
        with m.If(self.input.ready & self.input.valid):
            with m.If(self.input.last):
                m.d.sync += line_ctr.eq(0)
                with m.If(line_ctr != self.width - 1):
                    m.d.sync += self.not_exact_number_of_lines_error.eq(
                        self.not_exact_number_of_lines_error + 1)
            with m.Else():
                with m.If(line_ctr >= (self.width - 1)):
                    m.d.sync += line_ctr.eq(0)
                with m.Else():
                    m.d.sync += line_ctr.eq(line_ctr + 1)

        m.d.comb += self.output.payload.eq(self.input.payload)
        with m.If(self.input.last):
            m.d.comb += self.output.frame_last.eq(1)
            m.d.comb += self.output.line_last.eq(1)
        with m.Else():
            with m.If(line_ctr >= (self.width - 1)):
                m.d.comb += self.output.line_last.eq(1)

        return m
Esempio n. 20
0
class HdmiStreamSource(Elaboratable):
    def __init__(self, resource):
        self.resource = resource

        self.blanking_threshold = ControlSignal(16, reset=(480 * 16))

        self.measured_width = StatusSignal(16)
        self.measured_height = StatusSignal(16)

        self.width = ControlSignal(16, reset=1440)
        self.height = ControlSignal(16, reset=480)

        self.blank_r = ControlSignal()
        self.blank_g = ControlSignal()
        self.blank_b = ControlSignal()

        self.stable_lines_needed = 2000
        self.lines_stable = StatusSignal(range(self.stable_lines_needed + 1))
        self.frames_stable = StatusSignal(32)
        self.stable = StatusSignal()
        self.always_valid = ControlSignal()

        self.output_not_ready = StatusSignal(32)

        self.output = ImageStream(24)

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

        resource = self.resource

        self.lane_b = m.submodules.lane_b = HdmiRxLane(resource.b, "hdmi_eclk",
                                                       "hdmi_qdr")
        self.lane_g = m.submodules.lane_g = HdmiRxLane(resource.g, "hdmi_eclk",
                                                       "hdmi_qdr")
        self.lane_r = m.submodules.lane_r = HdmiRxLane(resource.r, "hdmi_eclk",
                                                       "hdmi_qdr")

        m.d.comb += self.stable.eq(
            self.lines_stable > self.stable_lines_needed - 1)

        de = Signal()
        m.d.comb += de.eq((self.lane_b.data_enable + self.lane_r.data_enable +
                           self.lane_g.data_enable) > 1)

        ce = Signal()
        m.d.comb += ce.eq(
            (~self.lane_b.data_enable + ~self.lane_r.data_enable +
             ~self.lane_g.data_enable) > 1)

        x_ctr = Signal(16)
        y_ctr = Signal(16)

        long_blanking = Signal()
        blanking_ctr = Signal.like(self.blanking_threshold)
        with m.If(ce):
            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.comb += long_blanking.eq(1)
        with m.Else():
            m.d.sync += blanking_ctr.eq(0)

        probe(m, self.lane_b.data_enable, "de_b")
        probe(m, self.lane_g.data_enable, "de_g")
        probe(m, self.lane_r.data_enable, "de_r")
        probe(m, long_blanking)
        trigger(m, long_blanking)

        output = self.output.clone()
        line_started = Signal()

        with m.If(de | (x_ctr > 0)):
            m.d.sync += x_ctr.eq(x_ctr + 1)

            with m.If(x_ctr < self.width):

                with m.If(~output.ready):
                    self.output_not_ready.eq(self.output_not_ready + 1)

                m.d.comb += output.valid.eq(self.stable | self.always_valid)
                m.d.comb += output.payload.eq(
                    Cat(
                        self.lane_r.data & Repl(~self.blank_r, 8),
                        self.lane_g.data & Repl(~self.blank_g, 8),
                        self.lane_b.data & Repl(~self.blank_b, 8),
                    ))

                m.d.comb += output.line_last.eq(x_ctr == self.width - 1)
                m.d.comb += output.frame_last.eq((x_ctr == self.width - 1)
                                                 & (y_ctr == self.height - 1))

        with m.If(ce & ((x_ctr >= self.width) | (x_ctr == 0))):
            m.d.sync += x_ctr.eq(0)
            with m.If(x_ctr > 128):
                m.d.sync += y_ctr.eq(y_ctr + 1)
                m.d.sync += self.measured_width.eq(x_ctr)
                with m.If(x_ctr == self.measured_width):
                    with m.If(self.lines_stable < self.stable_lines_needed):
                        m.d.sync += self.lines_stable.eq(self.lines_stable + 1)
                with m.Else():
                    m.d.sync += self.frames_stable.eq(0)
                    m.d.sync += self.lines_stable.eq(0)

            with m.If(long_blanking):
                m.d.sync += y_ctr.eq(0)
                with m.If(y_ctr > 128):
                    m.d.sync += self.measured_height.eq(y_ctr)
                    with m.If(y_ctr == self.height):
                        m.d.sync += self.frames_stable.eq(self.frames_stable +
                                                          1)
                    with m.Else():
                        m.d.sync += self.frames_stable.eq(0)

        buffer = m.submodules.buffer = StreamBuffer(output)
        m.d.comb += self.output.connect_upstream(buffer.output)

        return m

    @driver_method
    def train(self):
        print("training hdmi")
        print("tranining lane b...")
        _, delay, alignment = self.lane_b.train()
        self.set_delay(delay)
        self.lane_g.select.offset = alignment
        self.lane_r.select.offset = alignment

    @driver_method
    def set_delay(self, delay):
        self.lane_b.delayf.set_delay(delay)
        self.lane_g.delayf.set_delay(delay)
        self.lane_r.delayf.set_delay(delay)
Esempio n. 21
0
class StreamInfo(Elaboratable):
    def __init__(self, stream: Stream):
        self.stream = stream

        self.reference_counter = StatusSignal(32)
        self.successful_transactions_counter = StatusSignal(32)
        self.ready_not_valid = StatusSignal(32)
        self.valid_not_ready = StatusSignal(32)
        self.current_ready = StatusSignal()
        self.current_valid = StatusSignal()

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

        with m.If(self.stream.valid & ~self.stream.ready):
            m.d.sync += self.valid_not_ready.eq(self.valid_not_ready + 1)
        with m.If(self.stream.ready & ~self.stream.valid):
            m.d.sync += self.ready_not_valid.eq(self.ready_not_valid + 1)

        m.d.sync += self.reference_counter.eq(self.reference_counter + 1)

        transaction = Signal()
        m.d.comb += transaction.eq(self.stream.valid & self.stream.ready)
        with m.If(transaction):
            m.d.sync += self.successful_transactions_counter.eq(
                self.successful_transactions_counter + 1)

        m.d.comb += self.current_ready.eq(self.stream.ready)
        m.d.comb += self.current_valid.eq(self.stream.valid)

        for name, signal in self.stream.payload_signals.items():
            if len(signal) == 1:
                m.submodules[name] = MetadataSignalDebug(signal, transaction)
            else:
                current_state = StatusSignal(signal.shape())
                m.d.comb += current_state.eq(signal)
                setattr(self, "current_{}".format(name), current_state)
                last_transaction_state = StatusSignal(signal.shape())
                with m.If(transaction):
                    m.d.sync += last_transaction_state.eq(signal)
                setattr(self, "last_transaction_{}".format(name),
                        last_transaction_state)

        return m

    @driver_property
    def efficiency_percent(self):
        return self.successful_transactions_counter / self.reference_counter * 100

    @driver_property
    def stall_source_percent(self):
        return self.ready_not_valid / self.reference_counter * 100

    @driver_property
    def stall_sink_percent(self):
        return self.valid_not_ready / self.reference_counter * 100

    @driver_property
    def stall_both_percent(self):
        return (100 - self.efficiency_percent
                ) - self.stall_source_percent - self.stall_sink_percent
Esempio n. 22
0
class Pll(Elaboratable):
    vco_multipliers = list(range(2, 64))
    vco_dividers = list(range(1, 56))
    output_dividers = list(range(1, 128))

    @staticmethod
    def is_valid_vco_conf(input_freq, mul, div, exception=False):
        if not mul in Pll.vco_multipliers:
            if exception:
                raise ValueError(f'mul {mul} is not an allowed multiplier')
            return False
        if not div in Pll.vco_dividers:
            if exception:
                raise ValueError(f'div {div} is not an allowed divider')
            return False
        vco_freq = input_freq * mul / div
        if 800e6 > vco_freq:
            if exception:
                raise ValueError(
                    f'{vco_freq} is a to low vco freq. minimum is 800Mhz')
            return False
        if 1600e6 < vco_freq:
            if exception:
                raise ValueError(
                    f'{vco_freq} is a to high vco freq. maximum is 1600Mhz')
            return False
        return True

    def __init__(self, input_freq, vco_mul, vco_div, input_domain="sync"):
        Pll.is_valid_vco_conf(input_freq, vco_mul, vco_div, exception=True)
        self._pll = _Pll(
            clkin1_period=1 / input_freq * 1e9,
            clkfbout_mult=vco_mul,
            divclk_divide=vco_div,
        )
        m = self.m = Module()
        m.d.comb += self._pll.clk.fbin.eq(self._pll.clk.fbout)
        m.d.comb += self._pll.clk.in_[1].eq(ClockSignal(input_domain))
        m.d.comb += self._pll.clk.insel.eq(1)  # HIGH for clkin1

        self.locked = StatusSignal()

        self._input_domain = input_domain
        self._input_freq = input_freq
        self._vco = Clock(input_freq * vco_mul / vco_div)
        self._clock_constraints = {}

    def output_domain(self, domain_name, divisor, number=None, bufg=True):
        if number is None:
            number = next(x for x in range(6)
                          if x not in self._clock_constraints.keys())
        assert number not in self._clock_constraints.keys(
        ), "port {} is already taken".format(number)

        assert divisor in Mmcm.output_dividers

        self._pll.parameters["CLKOUT{}_DIVIDE".format(number)] = divisor
        self._pll.parameters["CLKOUT{}_PHASE".format(number)] = 0.0

        m = self.m

        clock_signal = Signal(name="pll_out_{}".format(number),
                              attrs={"KEEP": "TRUE"})
        m.d.comb += clock_signal.eq(self._pll.clk.out[number])

        if bufg:
            # TODO: seems to not change anything
            bufg = m.submodules["bufg_{}".format(number)] = BufG(clock_signal)
            output = bufg.o
        else:
            output = clock_signal

        m.domains += ClockDomain(domain_name)
        m.d.comb += ClockSignal(domain_name).eq(output)
        m.d.comb += ResetSignal(domain_name).eq(~self.locked)

        frequency = self._vco.frequency / divisor
        self._clock_constraints[number] = (clock_signal, frequency)
        print("PLL: creating domain '{}' with frequency {}Mhz".format(
            domain_name, frequency / 1e6))
        return Clock(frequency)

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

        m.submodules.pll_block = self._pll
        m.submodules.connections = self.m

        for i, (clock_signal, frequency) in self._clock_constraints.items():
            platform.add_clock_constraint(clock_signal, frequency)

        m.d.comb += self.locked.eq(self._pll.locked)
        m.d.comb += self._pll.rst.eq(ResetSignal(self._input_domain))

        if isinstance(platform, SocPlatform):
            m.submodules.drp_bridge = DrpBridge(
                DrpInterface(self._pll.dwe, self._pll.den, self._pll.daddr,
                             self._pll.di, self._pll.do, self._pll.drdy,
                             self._pll.dclk))

        return m
Esempio n. 23
0
class VideoResizer(Elaboratable):
    """Resize an ImageStream by cropping it / extending it with blackness to the desired resolution"""
    def __init__(self, input: ImageStream, desired_width, desired_height):
        self.input = input
        self.output = input.clone(name="resized")

        self.output_width = ControlSignal(16, reset=desired_width)
        self.output_height = ControlSignal(16, reset=desired_height)
        self.shift_x = ControlSignal(signed(16))
        self.shift_y = ControlSignal(signed(16))

        self.input_width = StatusSignal(16)
        self.input_height = StatusSignal(16)

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

        input_x = Signal(16)
        input_y = Signal(16)

        input_read = (self.input.ready & self.input.valid)
        with m.If(input_read):
            with m.If(~self.input.line_last):
                m.d.sync += input_x.eq(input_x + 1)
            with m.Else():
                m.d.sync += input_x.eq(0)
                m.d.sync += self.input_width.eq(input_x + 1)
                m.d.sync += input_y.eq(input_y + 1)
            with m.If(self.input.frame_last):
                m.d.sync += input_y.eq(0)
                m.d.sync += self.input_height.eq(input_y + 1)

        output_x = Signal(16)
        output_y = Signal(16)
        output_write = (self.output.ready & self.output.valid)
        with m.If(output_write):
            with m.If(output_x < self.output_width - 1):
                m.d.sync += output_x.eq(output_x + 1)
            with m.Else():
                m.d.sync += output_x.eq(0)
                m.d.comb += self.output.line_last.eq(1)
                with m.If(output_y < self.output_height - 1):
                    m.d.sync += output_y.eq(output_y + 1)
                with m.Else():
                    m.d.sync += output_y.eq(0)
                    m.d.comb += self.output.frame_last.eq(1)

        eff_x = output_x - self.shift_x
        eff_y = output_y - self.shift_y
        with m.If((eff_x == input_x) & (eff_y == input_y)):
            m.d.comb += self.output.valid.eq(self.input.valid)
            m.d.comb += self.input.ready.eq(self.output.ready)
            m.d.comb += self.output.payload.eq(self.input.payload)
        with m.Elif(((eff_x < input_x) | (eff_y < input_x)) & (eff_x >= 0)
                    & (eff_y >= 0)):
            m.d.comb += self.output.valid.eq(0)
            m.d.comb += self.input.ready.eq(1)
        with m.Else():
            m.d.comb += self.output.valid.eq(1)
            m.d.comb += self.input.ready.eq(0)
            m.d.comb += self.output.payload.eq(0)

        m.submodules.input_stream_info = StreamInfo(self.input)
        m.submodules.output_stream_info = StreamInfo(self.output)

        return m
Esempio n. 24
0
class HispiPhy(Elaboratable):
    def __init__(self, num_lanes=4, bits=12, hispi_domain="hispi"):
        assert bits == 12
        self.hispi_domain = hispi_domain

        self.hispi_clk = Signal()
        self.hispi_lanes = Signal(num_lanes)

        self.bitslip = [Signal() for _ in range(num_lanes)]
        self.out = [Signal(12) for _ in range(num_lanes)]

        self.hispi_x6_in_domain_counter = StatusSignal(32)
        self.enable_bitslip = ControlSignal(reset=1)
        self.word_reverse = ControlSignal()

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

        hispi_6_in = "{}_x6_in".format(self.hispi_domain)
        m.domains += ClockDomain(hispi_6_in)
        m.d.comb += ClockSignal(hispi_6_in).eq(self.hispi_clk)
        m.d[hispi_6_in] += self.hispi_x6_in_domain_counter.eq(
            self.hispi_x6_in_domain_counter + 1)

        mul = 3
        pll = m.submodules.pll = Mmcm(300e6,
                                      mul,
                                      1,
                                      input_domain=hispi_6_in.format(
                                          self.hispi_domain))
        pll.output_domain("{}_x6".format(self.hispi_domain), mul * 1)
        pll.output_domain("{}_x3".format(self.hispi_domain), mul * 2)
        pll.output_domain("{}_x2".format(self.hispi_domain), mul * 3)
        pll.output_domain("{}".format(self.hispi_domain), mul * 6)

        for lane in range(0, len(self.hispi_lanes)):
            iserdes = m.submodules["hispi_iserdes_" + str(lane)] = _ISerdes(
                data_width=6,
                data_rate="DDR",
                serdes_mode="master",
                interface_type="networking",
                num_ce=1,
                iobDelay="none",
            )

            m.d.comb += iserdes.d.eq(self.hispi_lanes[lane])
            m.d.comb += iserdes.ce[1].eq(1)
            m.d.comb += iserdes.clk.eq(
                ClockSignal("{}_x6".format(self.hispi_domain)))
            m.d.comb += iserdes.clkb.eq(
                ~ClockSignal("{}_x6".format(self.hispi_domain)))
            m.d.comb += iserdes.rst.eq(
                ResetSignal("{}_x6".format(self.hispi_domain)))
            m.d.comb += iserdes.clkdiv.eq(
                ClockSignal("{}_x2".format(self.hispi_domain)))

            data = Signal(12)
            iserdes_output = Signal(6)
            m.d.comb += iserdes_output.eq(
                Cat(iserdes.q[j] for j in range(1, 7)))

            hispi_x2 = "{}_x2".format(self.hispi_domain)
            lower_upper_half = Signal()
            m.d[hispi_x2] += lower_upper_half.eq(~lower_upper_half)
            with m.If(lower_upper_half):
                m.d[hispi_x2] += data[6:12].eq(iserdes_output)
            with m.Else():
                m.d[hispi_x2] += data[0:6].eq(iserdes_output)

            data_in_hispi_domain = Signal(12)
            m.submodules["data_cdc_{}".format(lane)] = FFSynchronizer(
                data, data_in_hispi_domain, o_domain=self.hispi_domain)

            hispi_domain = m.d[self.hispi_domain]
            bitslip = Signal()
            was_bitslip = Signal()
            hispi_domain += was_bitslip.eq(bitslip)
            with m.If(self.bitslip[lane] & ~was_bitslip & self.enable_bitslip):
                hispi_domain += bitslip.eq(1)
            with m.Else():
                hispi_domain += bitslip.eq(0)

            serdes_or_emulated_bitslip = Signal()
            with m.If(bitslip):
                hispi_domain += serdes_or_emulated_bitslip.eq(
                    ~serdes_or_emulated_bitslip)

            m.d.comb += iserdes.bitslip.eq(bitslip
                                           & serdes_or_emulated_bitslip)

            data_order_index = Signal(range(4))
            with m.If(bitslip & ~serdes_or_emulated_bitslip):
                hispi_domain += data_order_index.eq(data_order_index + 1)

            data_order = StatusSignal(range(16))
            setattr(self, "data_order_{}".format(lane), data_order)
            m.d.comb += data_order.eq(Array((1, 4, 9, 12))[data_order_index])

            current = Signal(12)
            last = Signal(12)
            m.d.comb += current.eq(data_in_hispi_domain)
            hispi_domain += last.eq(data_in_hispi_domain)
            reordered = Signal(12)
            parts = [current[0:6], current[6:12], last[0:6], last[6:12]]
            for cond, i in iterator_with_if_elif(range(16), m):
                with cond(data_order == i):
                    first = parts[i % 4]
                    second = parts[i // 4]
                    m.d.comb += reordered.eq(Cat(first, second))

            with m.If(self.word_reverse):
                m.d.comb += self.out[lane].eq(
                    Cat(reordered[i] for i in range(12)))
            with m.Else():
                m.d.comb += self.out[lane].eq(
                    Cat(reordered[i] for i in reversed(range(12))))

            out_status_signal = StatusSignal(12, name="out_{}".format(lane))
            setattr(self, "out_{}".format(lane), out_status_signal)
            m.d.comb += out_status_signal.eq(data_in_hispi_domain)

        return m
Esempio n. 25
0
class LaneManager(Elaboratable):
    def __init__(self, input_data: Signal, sync_pattern=(-1, 0, 0)):
        """
        Aligns the word boundries of one Hispi lane and detects control codes.
        Compatible only with Packetized-SP mode because it needs end markers.

        :param sync_pattern: the preamble of a control word (default is correct for most cases)
        :param timeout: Issue a bit slip after a control word wasnt found for n cycles
        """
        self.sync_pattern = sync_pattern
        self.input_data = input_data

        self.is_aligned = StatusSignal()

        self.timeout = ControlSignal(32, reset=10000)
        self.timeouts_to_resync = ControlSignal(32, reset=10000)

        self.since_last_sync_pattern_or_bitslip = StatusSignal(32)
        self.performed_bitslips = StatusSignal(32)
        self.timeouts_since_alignment = StatusSignal(32)
        self.last_word = StatusSignal(input_data.shape())
        self.last_control_word = StatusSignal(
            input_data.shape(),
            decoder=lambda x: next(
                ("{}/{:012b}".format(control_word, x)
                 for control_word, ending in control_words.items() if "{:012b}"
                 .format(x).endswith(ending)), "UNKNOWN/{:012b}".format(x)))

        self.do_bitslip = Signal()
        self.output = ImageStream(self.input_data.shape())

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

        m.d.sync += self.last_word.eq(self.input_data)
        m.d.comb += self.output.payload.eq(self.input_data)

        with m.If(self.since_last_sync_pattern_or_bitslip < self.timeout):
            m.d.sync += self.since_last_sync_pattern_or_bitslip.eq(
                self.since_last_sync_pattern_or_bitslip + 1)
        with m.Else():
            with m.If(self.is_aligned):
                with m.If(
                        self.timeouts_since_alignment > self.timeouts_to_resync
                ):
                    m.d.sync += self.is_aligned.eq(0)
                    m.d.sync += self.timeouts_since_alignment.eq(0)
                with m.Else():
                    m.d.sync += self.timeouts_since_alignment.eq(
                        self.timeouts_since_alignment + 1)
            with m.Else():
                m.d.sync += self.since_last_sync_pattern_or_bitslip.eq(0)
                m.d.sync += self.performed_bitslips.eq(
                    self.performed_bitslips + 1)
                m.d.comb += self.do_bitslip.eq(1)

        with m.FSM():
            for i, pattern_word in enumerate(self.sync_pattern):
                with m.State("sync{}".format(i)):
                    with m.If(self.input_data == Const(
                            pattern_word, self.input_data.shape())):
                        if i < len(self.sync_pattern) - 1:
                            m.next = "sync{}".format(i + 1)
                        else:
                            m.next = "control_word"
                    with m.Else():
                        with m.If(self.input_data == Const(
                                self.sync_pattern[0],
                                self.input_data.shape())):
                            m.next = "sync1"
                        with m.Else():
                            m.next = "sync0"
            with m.State("control_word"):
                with m.If(ends_with(self.input_data, *control_words.values())):
                    m.d.sync += self.last_control_word.eq(self.input_data)
                    m.d.sync += self.since_last_sync_pattern_or_bitslip.eq(0)
                    m.d.sync += self.is_aligned.eq(1)
                m.next = "sync0"

        # assemble the output stream
        valid = Signal()
        m.d.comb += valid.eq(
            ends_with(
                self.last_control_word,
                # control_words["START_OF_ACTIVE_FRAME_EMBEDDED_DATA"],
                control_words["START_OF_ACTIVE_FRAME_IMAGE_DATA"],
                # control_words["START_OF_ACTIVE_LINE_EMBEDDED_DATA"],
                control_words["START_OF_ACTIVE_LINE_IMAGE_DATA"]))

        # delay is needed because we only know that the line finished when the control code is done
        # this is len(sync_pattern) + 1 + 1 cycles after the line really ended
        delayed_valid = delay_by(valid, len(self.sync_pattern) + 2, m)
        delayed_data = delay_by(self.input_data, len(self.sync_pattern) + 2, m)

        with m.If(
                ends_with(self.last_control_word,
                          control_words["END_OF_ACTIVE_FRAME"],
                          control_words["END_OF_ACTIVE_LINE"])):
            m.d.sync += delayed_valid.eq(0)

        m.d.comb += self.output.payload.eq(delayed_data)
        m.d.comb += self.output.valid.eq(delayed_valid)
        m.d.comb += self.output.frame_last.eq(
            ends_with(self.last_control_word,
                      control_words["END_OF_ACTIVE_FRAME"]))
        m.d.comb += self.output.line_last.eq(
            ends_with(self.last_control_word,
                      control_words["END_OF_ACTIVE_LINE"],
                      control_words["END_OF_ACTIVE_FRAME"]))

        m.submodules.debug = InflexibleSourceDebug(self.output)

        return m
Esempio n. 26
0
class Ila(Elaboratable):
    def __init__(self, trace_length=2048, after_trigger=None):
        self.trace_length = trace_length

        self.after_trigger = ControlSignal(
            range(trace_length),
            reset=(trace_length //
                   2 if after_trigger is None else after_trigger))
        self.reset = ControlSignal()

        # Yosys cannot handle a signal named `initial` (bug #2914)
        self.initial_ = StatusSignal(reset=1)
        self.running = StatusSignal()
        self.write_ptr = StatusSignal(range(trace_length))
        self.trigger_since = StatusSignal(range(trace_length + 1))
        self.probes = []
        self.decoders = []

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

        if hasattr(platform, "ila_error"):
            raise platform.ila_error

        after_trigger = Signal.like(self.after_trigger)
        m.submodules += FFSynchronizer(self.after_trigger, after_trigger)

        assert hasattr(platform, "trigger"), "No trigger in Design"
        trigger = Signal()
        m.submodules += FFSynchronizer(platform.trigger, trigger)
        assert hasattr(platform, "probes"), "No probes in Design"
        platform_probes = list(platform.probes.items())
        probes = [(k, Signal.like(signal))
                  for k, (signal, decoder) in platform_probes]
        for (_, (i, _)), (_, o) in zip(platform_probes, probes):
            m.submodules += FFSynchronizer(i, o)
        self.probes = [(k, (len(signal), decoder))
                       for k, (signal, decoder) in platform_probes]

        probe_bits = sum(length for name, (length, decoder) in self.probes)
        print(f"ila: using {probe_bits} probe bits")
        self.mem = m.submodules.mem = SocMemory(
            width=ceil(probe_bits / 32) * 32,
            depth=self.trace_length,
            soc_write=False,
            attrs=dict(syn_ramstyle="block_ram"))
        write_port = m.submodules.write_port = self.mem.write_port(
            domain="sync")

        since_reset = Signal(range(self.trace_length + 1))
        with m.If(self.running):
            with m.If(self.write_ptr < (self.trace_length - 1)):
                m.d.sync += self.write_ptr.eq(self.write_ptr + 1)
            with m.Else():
                m.d.sync += self.write_ptr.eq(0)
            m.d.comb += write_port.addr.eq(self.write_ptr)
            m.d.comb += write_port.en.eq(1)
            m.d.comb += write_port.data.eq(Cat([s for _, s in probes]))

            # we wait trace_length cycles to be sure to overwrite the whole buffer at least once
            # and avoid confusing results
            with m.If(since_reset < self.trace_length):
                m.d.sync += since_reset.eq(since_reset + 1)

            with m.If(self.trigger_since == 0):
                with m.If(trigger & (since_reset > self.trace_length - 1)):
                    m.d.sync += self.trigger_since.eq(1)
            with m.Else():
                with m.If(self.trigger_since < (after_trigger - 1)):
                    m.d.sync += self.trigger_since.eq(self.trigger_since + 1)
                with m.Else():
                    m.d.sync += self.running.eq(0)
                    m.d.sync += self.initial_.eq(0)
        with m.Else():
            reset = Signal()
            m.submodules += FFSynchronizer(self.reset, reset)
            with m.If(Changed(m, reset)):
                m.d.sync += self.running.eq(1)
                m.d.sync += self.trigger_since.eq(0)
                m.d.sync += self.write_ptr.eq(0)
                m.d.sync += since_reset.eq(0)

        return m

    @driver_method
    def arm(self):
        self.reset = not self.reset

    @driver_method
    def get_values(self):
        assert (not self.running) and (
            not self.initial_), "ila didnt trigger yet"
        r = list(range(self.trace_length))
        addresses = r[self.write_ptr:] + r[:self.write_ptr]
        for address in addresses:
            value = self.mem[address]
            current_offset = 0
            current_row = []
            for name, (size, _) in self.probes:
                current_row.append((value >> current_offset) & (2**size - 1))
                current_offset += size
            yield current_row

    @driver_method
    def write_vcd(self, path="/tmp/ila.vcd"):
        from pathlib import Path
        path = Path(path)
        print(f"writing vcd to {path.absolute()}")
        from vcd import VCDWriter
        with open(path, "w") as f:
            with VCDWriter(f) as writer:
                vcd_vars = [(writer.register_var(
                    'ila_signals',
                    name,
                    'reg' if decoder is None else 'string',
                    size=size), decoder)
                            for name, (size, decoder) in self.probes]
                clk = writer.register_var('ila_signals', 'clk', 'reg', size=1)
                for timestamp, values in enumerate(self.get_values()):
                    writer.change(clk, timestamp * 2, 1)
                    for (var, decoder), value in zip(vcd_vars, values):
                        writer.change(
                            var, timestamp * 2,
                            value if decoder is None else decoder.get(
                                value, str(value)))
                    writer.change(clk, timestamp * 2 + 1, 0)
Esempio n. 27
0
class PluginModuleStreamerRx(Elaboratable):
    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()

        domain = self.domain_name
        domain_in = domain + "_in"
        domain_ddr = domain + "_ddr"
        domain_ddr_eclk = domain + "_ddr_eclk"

        m.domains += ClockDomain(domain_in)
        m.d.comb += ClockSignal(domain_in).eq(self.plugin.clk_word)

        pll = m.submodules.pll = Pll(input_freq=50e6, vco_mul=4, vco_div=1, input_domain=domain_in)
        pll.output_domain(domain_ddr, 1)

        m.submodules.eclk_ddr = EClkSync(domain_ddr, domain_ddr_eclk, input_frequency=400e6)

        lanes = []
        bitslip_signal = Signal()
        for i in range(4):
            lane = m.submodules["lane{}".format(i)] = LaneBitAligner(
                input=self.plugin["lvds{}".format(i)],
                in_testpattern_mode=~self.valid,
                bitslip_signal=bitslip_signal,
                ddr_domain=domain_ddr_eclk,
            )
            lanes.append(lane)
        word_aligner = m.submodules.word_aligner = WordAligner(domain_ddr_eclk, lanes[0].output)
        m.d.comb += bitslip_signal.eq(word_aligner.bitslip)

        valid_iserdes = m.submodules.valid_iserdes = ISerdes8(self.plugin.valid, domain_ddr_eclk, word_domain="sync", invert=True)
        m.d.comb += valid_iserdes.bitslip.eq(bitslip_signal)
        m.d.comb += self.valid.eq(valid_iserdes.output[4])

        m.d.sync += self.output.payload.eq(Cat(*[lane.output for lane in lanes]))
        m.d.comb += self.output.valid.eq(
            self.valid & self.trained
        )

        m.submodules.inflexible_output = InflexibleSourceDebug(self.output)

        return DomainRenamer(domain)(m)

    @driver_method
    def train(self, timeout=32):
        self.lane0.delay = 15
        print("doing word alignment...")
        for i in range(timeout):
            if self.lane0.output == 0b00010110:
                print("-> {} slips".format(i))
                print("training lane 0...")
                self.lane0.train()
                print("training lane 1...")
                self.lane1.train()
                print("training lane 2...")
                self.lane2.train()
                print("training lane 3...")
                self.lane3.train()
                self.trained = True
                return
            else:
                self.word_aligner.slip()
        raise TimeoutError()
Esempio n. 28
0
class LaneBitAligner(Elaboratable):
    def __init__(self, input, in_testpattern_mode, ddr_domain, bitslip_signal, testpattern=0b00010110):
        """
        Does bit alignment of one lane usig a given testpattern if in_testpattern_mode is high
        """
        self.input = input
        self.bitslip_signal = bitslip_signal
        self.in_testpattern_mode = in_testpattern_mode

        self.ddr_domain = ddr_domain
        self.testpattern = testpattern

        self.delay = ControlSignal(5, reset=15)
        self.error = StatusSignal(32)

        self.output = StatusSignal(8)

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

        delayed = Signal()
        m.submodules.delayd = Instance(
            "DELAYD",

            i_A=self.input,
            i_DEL0=self.delay[0],
            i_DEL1=self.delay[1],
            i_DEL2=self.delay[2],
            i_DEL3=self.delay[3],
            i_DEL4=self.delay[4],

            o_Z=delayed,
        )
        iserdes = m.submodules.iserdes = ISerdes8(delayed, self.ddr_domain, word_domain="sync", invert=True)
        m.d.comb += self.output.eq(iserdes.output)
        m.d.comb += iserdes.bitslip.eq(self.bitslip_signal)

        with m.If(self.in_testpattern_mode & (self.output != self.testpattern)):
            m.d.sync += self.error.eq(self.error + 1)

        return m

    @driver_method
    def train(self):
        from time import sleep
        start_current = 0
        start_longest = 0
        len_longest = 0
        was_good = True
        for i in range(32):
            self.delay = i
            e_start = self.error
            sleep(0.01)
            difference = self.error - e_start
            if difference == 0 and not was_good:
                start_current = i
            elif ((difference != 0) or (i == 31)) and was_good:
                len = i - start_current
                if len > len_longest:
                    len_longest = len
                    start_longest = start_current
            print(i, difference)
            was_good = difference == 0
        self.delay = int(start_longest + (len_longest / 2))
        print("-> delay tap", self.delay)
Esempio n. 29
0
class HdmiStreamAligner(Elaboratable):
    """
    Aligns the HDMI output to the Image stream by 'slipping' data during the blanking periods until the frame is
    aligned.
    """
    def __init__(self, input: ImageStream, hdmi):
        self.hdmi = hdmi
        self.input = input

        self.allow_slip_h = ControlSignal(reset=1)
        self.allow_slip_v = ControlSignal(reset=1)
        self.slipped_v = StatusSignal(32)
        self.slipped_h = StatusSignal(32)

        self.line_cycles = StatusSignal(32)
        self.frame_cycles = StatusSignal(32)

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

        m.submodules.debug = InflexibleSinkDebug(self.input)
        input_stream_info = m.submodules.input_stream_info = StreamInfo(
            stream=self.input)

        line_length_counter = Signal(32)
        was_blanking_x = Signal()
        m.d.sync += was_blanking_x.eq(self.hdmi.timing_generator.is_blanking_x)
        with m.If(~self.hdmi.timing_generator.is_blanking_x):
            m.d.sync += line_length_counter.eq(line_length_counter + 1)
        with m.If(self.hdmi.timing_generator.is_blanking_x & ~was_blanking_x):
            m.d.sync += self.line_cycles.eq(line_length_counter)
            m.d.sync += line_length_counter.eq(0)

        frame_length_counter = Signal(32)
        was_blanking_y = Signal()
        m.d.sync += was_blanking_y.eq(self.hdmi.timing_generator.is_blanking_y)
        with m.If(self.hdmi.timing_generator.active):
            m.d.sync += frame_length_counter.eq(frame_length_counter + 1)
        with m.If(self.hdmi.timing_generator.is_blanking_y & ~was_blanking_y):
            m.d.sync += self.frame_cycles.eq(frame_length_counter)
            m.d.sync += frame_length_counter.eq(0)

        with m.If(self.hdmi.timing_generator.active):
            m.d.comb += self.input.ready.eq(1)

        was_line_last = Signal()
        was_frame_last = Signal()
        with m.If(self.input.ready):
            m.d.sync += was_line_last.eq(self.input.line_last)
            m.d.sync += was_frame_last.eq(self.input.frame_last)

        with m.If(self.hdmi.timing_generator.is_blanking_x & ~was_line_last
                  & self.allow_slip_h):
            m.d.sync += self.slipped_h.eq(self.slipped_h + 1)
            m.d.comb += self.input.ready.eq(1)

        with m.If(self.hdmi.timing_generator.is_blanking_y & ~was_frame_last
                  & self.allow_slip_v):
            m.d.sync += self.slipped_v.eq(self.slipped_v + 1)
            m.d.comb += self.input.ready.eq(1)

        return m
Esempio n. 30
0
class HdmiRxLane(Elaboratable):
    def __init__(self, pin, ddr_domain, qdr_domain):
        self.pin = pin
        self.ddr_domain = ddr_domain
        self.qdr_domain = qdr_domain

        self.not_valid_cnt = StatusSignal(16)

        self.blanking_threshold = ControlSignal(
            16, reset=(480 * 16))  # 128 is dvi spec, for hdmi this should be 8
        self.blankings_hit = StatusSignal(32)

        self.raw_word = StatusSignal(10)
        self.invert = StatusSignal(reset=1)

        self.data = StatusSignal(8)
        self.data_enable = StatusSignal()
        self.control = StatusSignal(2)

    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

    @driver_method
    def train(self, start=0, step=10, n=13, fine_training=False):
        self.delayf.set_delay(start)
        from time import sleep
        best = (0.0, 0, 0)
        for i in range(n):
            delay = i * step + start
            print(f"delay {delay}")

            for alignment in range(9):
                self.select.offset = alignment
                hit_before = self.blankings_hit
                sleep(0.1)
                hit = self.blankings_hit - hit_before
                if hit > best[0]:
                    best = (hit, delay, alignment)
                print(f"alignment {alignment} hit {hit}")

            self.delayf.forward(step)

        hits, delay, alignment = best
        print(f"elected hits={hits} delay={delay} alignment={alignment}")
        self.delayf.set_delay(delay)
        self.select.offset = alignment
        if fine_training:
            if hits != 0:
                return self.train(start=delay - 10,
                                  step=1,
                                  n=20,
                                  fine_training=False)
            else:
                print("failed training")
        else:
            return best