Exemple #1
0
    def __init__(self, *, rx_depth=16, tx_depth=16, **kwargs):
        super().__init__()

        self._phy = AsyncSerial(**kwargs)
        self._rx_fifo = SyncFIFO(width=self._phy.rx.data.width, depth=rx_depth)
        self._tx_fifo = SyncFIFO(width=self._phy.tx.data.width, depth=tx_depth)

        bank = self.csr_bank()
        self._enabled = bank.csr(1, "w")
        self._divisor = bank.csr(self._phy.divisor.width, "rw")
        self._rx_data = bank.csr(self._phy.rx.data.width, "r")
        self._rx_rdy = bank.csr(1, "r")
        self._rx_err = bank.csr(len(self._phy.rx.err), "r")
        self._tx_data = bank.csr(self._phy.tx.data.width, "w")
        self._tx_rdy = bank.csr(1, "r")

        self._rx_rdy_ev = self.event(mode="level")
        self._rx_err_ev = self.event(mode="rise")
        self._tx_mty_ev = self.event(mode="rise")

        self._bridge = self.bridge(data_width=32, granularity=8, alignment=2)
        self.bus = self._bridge.bus
        self.irq = self._bridge.irq

        self.tx = Signal()
        self.rx = Signal()
        self.enabled = Signal()
        self.driving = Signal()
    def elaborate(self, platform):
        m = Module()

        # Received symbols are aligned and processed by the PCIePhyRX
        # The PCIePhyTX sends symbols to the SERDES
        #m.submodules.serdes = serdes = LatticeECP5PCIeSERDESx2() # Declare SERDES module with 1:2 gearing
        m.submodules.serdes = serdes = LatticeECP5PCIeSERDES(
            2)  # Declare SERDES module with 1:2 gearing

        m.domains.rx = ClockDomain()
        m.domains.tx = ClockDomain()
        m.d.comb += [
            ClockSignal("rx").eq(serdes.rx_clk),
            ClockSignal("tx").eq(serdes.tx_clk),
            serdes.lane.rx_align.eq(1),
        ]

        uart_pins = platform.request("uart", 0)
        uart = AsyncSerial(divisor=int(100), pins=uart_pins)
        m.submodules += uart

        m.submodules.debug = UARTDebugger(uart,
                                          9,
                                          CAPTURE_DEPTH,
                                          Cat(serdes.lane.rx_symbol,
                                              serdes.lane.tx_symbol,
                                              Signal(9 * 8 - 18 * 2)),
                                          "rx",
                                          timeout=100 * 1000 * 1000)

        return m
    def elaborate(self, platform):
        stereo = platform.request("stereo")
        uart = platform.request("uart")
        divisor = int(platform.default_clk_frequency // 115200)

        m = Module()

        # Create the uart
        m.submodules.serial = serial = AsyncSerial(divisor=divisor, pins=uart)

        pwm_acc = Signal(9)
        dat_r = Signal(8)

        m.d.comb += [
            serial.rx.ack.eq(1),
            stereo.l.o.eq(Mux(pwm_acc[-1], 0x7, 0x0)),  # Not too loud
            stereo.r.o.eq(stereo.l.o)
        ]

        with m.If(serial.rx.rdy):
            m.d.sync += dat_r.eq(serial.rx.data)

        m.d.sync += pwm_acc.eq(pwm_acc[:8] + dat_r)

        return m
Exemple #4
0
    def elaborate(self, platform):
        m = Module()

        m.submodules.phy = ecp5_phy = LatticeECP5PCIePhy()
        phy = ecp5_phy.phy

        ltssm = phy.ltssm
        lane = phy.descrambled_lane

        # Temperature sensor, the chip gets kinda hot
        refclkcounter = Signal(32)
        m.d.sync += refclkcounter.eq(refclkcounter + 1)

        sample = Signal()
        m.d.sync += sample.eq(refclkcounter[25])
        m.submodules.dtr = dtr = DTR(start=refclkcounter[25] & ~sample)

        leds_alnum = Cat(platform.request("alnum_led", 0))

        m.d.comb += leds_alnum.eq(ltssm.debug_state)

        uart_pins = platform.request("uart", 0)
        uart = AsyncSerial(divisor = int(100), pins = uart_pins)
        m.submodules += uart

        if NO_DEBUG:
            pass
        else:
            # 64t 9R 9R 9T 9T 2v 4- 6D
            # t = Ticks since state was entered
            # R = RX symbol
            # T = TX symbol
            # v = RX valid
            # D = DTR Temperature, does not correspond to real temperature besides the range of 21-29 °C. After that in 10 °C steps (30 = 40 °C, 31 = 50 °C etc...), see TN1266

            time_since_state = Signal(64)
            
            with m.If(ltssm.debug_state != State.L0):
                m.d.rx += time_since_state.eq(0)
            with m.Else():
                m.d.rx += time_since_state.eq(time_since_state + 1)

            m.submodules += UARTDebugger(uart, 14, CAPTURE_DEPTH, Cat(
                time_since_state,
                lane.rx_symbol, lane.tx_symbol,
                lane.rx_locked & lane.rx_present & lane.rx_aligned, lane.rx_locked & lane.rx_present & lane.rx_aligned, Signal(4), Signal(4), phy.dll.tx.started_sending, phy.dll.tx.started_sending#dtr.temperature
                ), "rx")

        return m
Exemple #5
0
    def __init__(self, *, rx_depth=16, tx_depth=16, **kwargs):
        super().__init__()

        self._phy       = AsyncSerial(**kwargs)
        self._rx_fifo   = SyncFIFO(width=self._phy.rx.data.width, depth=rx_depth)
        self._tx_fifo   = SyncFIFO(width=self._phy.tx.data.width, depth=tx_depth)

        bank            = self.csr_bank()
        self._divisor   = bank.csr(self._phy.divisor.width, "rw")
        self._rx_data   = bank.csr(self._phy.rx.data.width, "r")
        self._rx_rdy    = bank.csr(1, "r")
        self._rx_err    = bank.csr(len(self._phy.rx.err),   "r")
        self._tx_data   = bank.csr(self._phy.tx.data.width, "w")
        self._tx_rdy    = bank.csr(1, "r")

        self._rx_rdy_ev = self.event(mode="level")
        self._rx_err_ev = self.event(mode="rise")
        self._tx_mty_ev = self.event(mode="rise")
Exemple #6
0
    def elaborate(self, platform):
        m = Module()

        m.submodules.serdes = serdes = LatticeECP5PCIeSERDES(1)
        m.submodules.lane = lane = serdes.lane
        #lane = serdes.lane

        m.d.comb += [
            #    serdes.txd.eq(K(28,5)),
            #lane.rx.eq(1), Crucial?
            lane.rx_invert.eq(0),
            lane.rx_align.eq(1),
        ]

        #m.domains.sync = ClockDomain()
        m.domains.rx = ClockDomain()
        m.domains.tx = ClockDomain()
        m.d.comb += [
            #ClockSignal("sync").eq(serdes.refclk),
            ClockSignal("rx").eq(serdes.rx_clk),
            ClockSignal("tx").eq(serdes.tx_clk),
        ]

        cntr = Signal(5)
        with m.If(cntr == 0):
            m.d.tx += lane.tx_symbol.eq(Ctrl.COM)
        with m.Elif(cntr == 1):
            m.d.tx += lane.tx_symbol.eq(Ctrl.SKP)
        with m.Elif(cntr == 2):
            m.d.tx += lane.tx_symbol.eq(Ctrl.SKP)
        with m.Elif(cntr == 3):
            m.d.tx += lane.tx_symbol.eq(Ctrl.SKP)
        with m.Elif(cntr == 4):
            m.d.tx += lane.tx_symbol.eq(Ctrl.STP)
        with m.Elif(cntr[2:] == 2):
            m.d.tx += lane.tx_symbol.eq(Ctrl.EDB)
        with m.Elif(cntr[2:] == 3):
            m.d.tx += lane.tx_symbol.eq(Ctrl.EIE)
        with m.Elif(cntr[2:] == 4):
            m.d.tx += lane.tx_symbol.eq(Ctrl.END)
        with m.Elif(cntr[2:] == 5):
            m.d.tx += lane.tx_symbol.eq(Ctrl.IDL)
        with m.Else():
            m.d.tx += lane.tx_symbol.eq(cntr)

        m.d.tx += cntr.eq(cntr + 1)
        #with m.FSM(domain="tx"):
        #    with m.State("1"):
        #        m.d.tx += lane.tx_symbol.eq(Ctrl.COM)
        #        m.next = "2"
        #    with m.State("2"):
        #        m.d.tx += lane.tx_symbol.eq(Ctrl.SKP)
        #        m.d.tx += cntr.eq(cntr + 1)
        #        with m.If(cntr == 3):
        #            m.d.tx += cntr.eq(0)
        #            m.next = "1"

        platform.add_resources([Resource("test", 0, Pins("B19", dir="o"))])
        m.d.comb += platform.request("test", 0).o.eq(ClockSignal("rx"))
        platform.add_resources([Resource("test", 1, Pins("A18", dir="o"))])
        m.d.comb += platform.request("test", 1).o.eq(ClockSignal("tx"))

        #refclkcounter = Signal(32)
        #m.d.sync += refclkcounter.eq(refclkcounter + 1)
        #rxclkcounter = Signal(32)
        #m.d.rx += rxclkcounter.eq(rxclkcounter + 1)
        #txclkcounter = Signal(32)
        #m.d.tx += txclkcounter.eq(txclkcounter + 1)

        led_att1 = platform.request("led", 0)
        led_att2 = platform.request("led", 1)
        led_sta1 = platform.request("led", 2)
        led_sta2 = platform.request("led", 3)
        led_err1 = platform.request("led", 4)
        led_err2 = platform.request("led", 5)
        led_err3 = platform.request("led", 6)
        led_err4 = platform.request("led", 7)
        m.d.rx += lane.det_enable.eq(1)
        m.d.comb += [
            led_att2.eq(~(serdes.lane.rx_aligned)),
            led_err1.eq(~(serdes.lane.rx_present)),
            led_err2.eq(~(serdes.lane.rx_locked | serdes.lane.tx_locked)),
            led_err3.eq(~(lane.det_valid)),  #serdes.rxde0)),
            led_err4.eq(~(lane.det_status)),  #serdes.rxce0)),
        ]
        triggered = Signal(reset=1)
        #m.d.tx += triggered.eq((triggered ^ ((lane.rx_symbol[0:9] == Ctrl.EIE) | (lane.rx_symbol[9:18] == Ctrl.EIE))))

        uart_pins = platform.request("uart", 0)
        uart = AsyncSerial(divisor=int(100), pins=uart_pins)
        m.submodules += uart

        #m.d.rx += lane.tx_e_idle.eq(1)
        debug = UARTDebugger(uart, 2, CAPTURE_DEPTH,
                             Cat(lane.rx_symbol[0:9], lane.rx_aligned,
                                 Signal(6)), "rx",
                             triggered)  # lane.rx_present & lane.rx_locked)
        m.submodules += debug

        return m
Exemple #7
0
    def elaborate(self, platform):
        m = Module()

        m.submodules.serdes = serdes = LatticeECP5PCIeSERDESx4(
            speed_5GTps=False, CH=0)
        m.submodules.aligner = lane = DomainRenamer("rx")(PCIeSERDESAligner(
            serdes.lane))

        m.d.comb += [
            lane.rx_invert.eq(0),
            lane.rx_align.eq(1),
        ]

        #m.domains.sync = ClockDomain()
        m.domains.rx = ClockDomain()
        m.domains.tx = ClockDomain()
        m.d.comb += [
            #ClockSignal("sync").eq(serdes.refclk),
            ClockSignal("rx").eq(serdes.rx_clk),
            ClockSignal("tx").eq(serdes.tx_clk),
        ]

        cntr = Signal(1)

        with m.If(cntr[0]):
            m.d.tx += lane.tx_symbol[0:9].eq(Ctrl.COM)
            m.d.tx += lane.tx_symbol[9:18].eq(Ctrl.SKP)
            m.d.tx += lane.tx_symbol[18:27].eq(Ctrl.SKP)
            m.d.tx += lane.tx_symbol[27:36].eq(Ctrl.SKP)
        with m.Else():
            m.d.tx += lane.tx_symbol[0:9].eq(Ctrl.IDL)
            m.d.tx += lane.tx_symbol[9:18].eq(Ctrl.IDL)
            m.d.tx += lane.tx_symbol[18:27].eq(Ctrl.IDL)
            m.d.tx += lane.tx_symbol[27:36].eq(Ctrl.IDL)

        m.d.tx += cntr.eq(cntr + 1)

        platform.add_resources([Resource("test", 0, Pins("B19", dir="o"))])
        m.d.comb += platform.request("test", 0).o.eq(ClockSignal("rx"))
        platform.add_resources([Resource("test", 1, Pins("A18", dir="o"))])
        m.d.comb += platform.request("test", 1).o.eq(ClockSignal("tx"))

        leds = []
        for i in range(8):
            leds.append(platform.request("led", i))

        m.d.rx += Cat(leds).eq(lane.rx_symbol[0:8] ^ lane.rx_symbol[8:16]
                               ^ lane.rx_symbol[16:24] ^ lane.rx_symbol[24:32]
                               ^ Cat(lane.rx_symbol[32:36], Signal(4)))

        uart_pins = platform.request("uart", 0)
        uart = AsyncSerial(divisor=int(100), pins=uart_pins)
        m.submodules += uart

        #m.d.rx += lane.tx_e_idle.eq(1)
        debug = UARTDebugger(
            uart, 8, CAPTURE_DEPTH,
            Cat(lane.rx_symbol[0:9], lane.rx_valid[0], Signal(6),
                lane.rx_symbol[9:18], lane.rx_valid[1], Signal(6),
                lane.rx_symbol[18:27], lane.rx_valid[2], Signal(6),
                lane.rx_symbol[27:36], lane.rx_valid[3], Signal(6)), "rx")

        m.submodules += debug

        return m
    def elaborate(self, platform):
        platform.add_resources([
            Resource(
                "pcie_x1",
                0,
                Subsignal("perst", Pins("A6"), Attrs(IO_TYPE="LVCMOS33")),
            )
        ])

        m = Module()

        uart_pins = platform.request("uart", 0)
        uart = AsyncSerial(divisor=int(100), pins=uart_pins)

        cd_serdes = ClockDomain()
        m.domains += cd_serdes
        m.domains.gearout = ClockDomain()
        serdes = LatticeECP5PCIeSERDES()
        #aligner         = DomainRenamer("rx")(PCIeSERDESAligner(serdes.lane)) # The lane
        dout = Signal(4 * 4 * 12)

        m.submodules += DomainRenamer("rx")(
            Resizer(
                Cat(
                    #Signal(9, reset=0xFE), Signal(6, reset=0), Signal(1, reset=1), Signal(8,reset=0),
                    #Signal(9, reset=0xDC), Signal(6, reset=0), Signal(1, reset=1), Signal(8,reset=2),
                    serdes.lane.rx_symbol.word_select(0, 9),
                    Signal(6, reset=0),
                    serdes.lane.rx_valid[0],
                    serdes.lane.det_valid,
                    serdes.lane.det_status,
                    serdes.lane.rx_present,
                    serdes.lane.rx_locked,
                    serdes.lane.rx_aligned,
                    Signal(3),
                    serdes.lane.rx_symbol.word_select(1, 9),
                    Signal(6, reset=0),
                    serdes.lane.rx_valid[1],
                    Signal(8, reset=0x11),
                ),
                dout,
                ClockSignal("gearout")))

        platform.add_resources([Resource("test", 0,
                                         Pins("B19", dir="o"))])  # Arduino tx
        m.d.comb += platform.request("test").o.eq(ClockSignal("gearout"))
        debug = UARTDebugger(
            uart, 24, 1000, dout,
            "gearout")  # serdes.lane.rx_present & serdes.lane.rx_locked)
        m.submodules += [
            uart,
            serdes,
            #    aligner,
            debug,
        ]

        m.d.comb += [
            cd_serdes.clk.eq(serdes.rx_clk_o),
            serdes.rx_clk_i.eq(cd_serdes.clk),
            serdes.tx_clk_i.eq(cd_serdes.clk),
            serdes.lane.rx_align.eq(1),
            serdes.lane.tx_symbol.eq(K(28, 3)),
            serdes.lane.rx_invert.eq(0),

            #aligner.rx_align.eq(1),
            serdes.lane.det_enable.eq(0),
        ]

        m.d.sync += platform.request("led", 0).o.eq(~serdes.lane.det_valid)
        m.d.sync += platform.request("led", 1).o.eq(~serdes.lane.det_status)
        m.d.sync += platform.request("led", 2).o.eq(~serdes.lane.rx_present)
        m.d.sync += platform.request("led", 3).o.eq(~serdes.lane.rx_locked)
        m.d.sync += platform.request("led", 4).o.eq(~serdes.lane.rx_aligned)
        m.d.sync += platform.request("led", 5).o.eq(~(serdes.lane.rx_locked))
        m.d.sync += platform.request("led", 6).o.eq(~(serdes.lane.tx_locked))
        m.d.sync += platform.request("led", 7).o.eq(~1)

        #with m.FSM():
        #    with m.State("start"):
        #        m.next = "a"
        #    with m.State("a"):
        #        m.d.sync += serdes.lane.det_enable.eq(0)
        return m
Exemple #9
0
    def elaborate(self, platform):
        m = Module()

        m.submodules.serdes = serdes = LatticeECP5PCIeSERDES(2)
        m.submodules.aligner = lane = DomainRenamer("rx")(PCIeSERDESAligner(
            serdes.lane))
        m.d.comb += [
            lane.rx_invert.eq(0),
            lane.rx_align.eq(1),
        ]

        m.domains.rx = ClockDomain()
        m.domains.tx = ClockDomain()
        m.d.comb += [
            ClockSignal("rx").eq(serdes.rx_clk),
            ClockSignal("tx").eq(serdes.tx_clk),
        ]

        platform.add_resources([Resource("test", 0, Pins("B19", dir="o"))])
        m.d.comb += platform.request("test", 0).o.eq(ClockSignal("rx"))
        platform.add_resources([Resource("test", 1, Pins("A18", dir="o"))])
        m.d.comb += platform.request("test", 1).o.eq(ClockSignal("tx"))

        led_att1 = platform.request("led", 0)
        led_att2 = platform.request("led", 1)
        led_sta1 = platform.request("led", 2)
        led_sta2 = platform.request("led", 3)
        led_err1 = platform.request("led", 4)
        led_err2 = platform.request("led", 5)
        led_err3 = platform.request("led", 6)
        led_err4 = platform.request("led", 7)
        #m.d.comb += [
        #    led_att1.eq(~(ClockSignal("rx") ^ ClockSignal("tx"))),
        #]

        count = Signal()
        refclkcounter = Signal(64)
        txclkcounter = Signal(64)
        rxclkcounter = Signal(64)
        with m.If(count):
            m.d.sync += refclkcounter.eq(refclkcounter + 1)
            m.d.tx += txclkcounter.eq(txclkcounter + 1)
            m.d.rx += rxclkcounter.eq(rxclkcounter + 1)

        counter = Signal(16)
        sample = Signal()
        with m.FSM():
            with m.State("Wait"):
                m.d.sync += count.eq(1)
                m.d.sync += counter.eq(counter + 1)
                with m.If(counter == 0xFFFF):
                    m.d.sync += count.eq(0)
                    m.d.sync += counter.eq(0)
                    m.next = "Sample Delay"
            with m.State("Sample Delay"):
                m.d.sync += counter.eq(counter + 1)
                with m.If(counter == 0xF):
                    m.d.sync += counter.eq(0)
                    m.next = "Sample"
            with m.State("Sample"):
                m.d.sync += sample.eq(1)
                m.next = "Sample After Delay"
            with m.State("Sample After Delay"):
                m.d.sync += sample.eq(0)
                m.d.sync += counter.eq(counter + 1)
                with m.If(counter == 0xF):
                    m.d.sync += counter.eq(0)
                    m.next = "Wait"

        uart_pins = platform.request("uart", 0)
        uart = AsyncSerial(divisor=int(100), pins=uart_pins)
        m.submodules += uart
        debug = UARTDebugger(uart, 8 * 3, CAPTURE_DEPTH,
                             Cat(refclkcounter, txclkcounter,
                                 rxclkcounter), "sync",
                             sample)  # lane.rx_present & lane.rx_locked)
        m.submodules += debug

        return m
Exemple #10
0
    def test_write(self):
        pins = Record([("rx", pin_layout(1, dir="i")),
                       ("tx", pin_layout(1, dir="o"))])
        dut = UARTBridge(divisor=self.divisor, pins=pins)
        serial = AsyncSerial(divisor=self.divisor)
        m = Module()
        m.submodules.bridge = dut
        m.submodules.serial = serial
        m.d.comb += [
            pins.rx.i.eq(serial.tx.o),
            serial.rx.i.eq(pins.tx.o),
        ]

        def process():
            # Send write command
            yield from serial_write(serial, 0x01)
            yield

            # Length = 1
            yield from serial_write(serial, 0x01)
            yield

            # Send 0x4000 as address
            yield from serial_write(serial, 0x00)
            yield
            yield from serial_write(serial, 0x00)
            yield
            yield from serial_write(serial, 0x40)
            yield
            yield from serial_write(serial, 0x00)
            yield

            # Send 0xFEEDFACE as value
            yield from serial_write(serial, 0xFE)
            yield
            yield from serial_write(serial, 0xED)
            yield
            yield from serial_write(serial, 0xFA)
            yield
            yield from serial_write(serial, 0xCE)

            # Handle wishbone request
            timeout = 0
            while not (yield dut.bus.cyc):
                yield
                timeout += 1
                if timeout > self.timeout:
                    raise RuntimeError("Simulation timed out")

            # Ensure Wishbone address is the one we asked for
            self.assertEqual((yield dut.bus.adr), 0x00004000)
            self.assertEqual((yield dut.bus.dat_w), 0xFEEDFACE)
            self.assertTrue((yield dut.bus.we))

            # Answer
            yield dut.bus.ack.eq(1)
            yield

        sim = Simulator(m)
        with sim.write_vcd("test_uartbridge.vcd"):
            sim.add_clock(1e-6)
            sim.add_sync_process(process)
            sim.run()
Exemple #11
0
    def elaborate(self, platform):
        m = Module()

        m.submodules.serial = serial = AsyncSerial(divisor=self._divisor,
                                                   pins=self._pins)

        address_width = 32
        data_width = 32

        cmd = Signal(8)
        length = Signal(8)
        address = Signal(address_width)
        data = Signal(data_width)
        bytes_count = Signal(range(data_width // 8))
        words_count = Signal(8)

        m.d.comb += [
            self.bus.dat_w.eq(data),
            self.bus.adr.eq(address),
        ]

        with m.FSM():
            with m.State("Receive-Cmd"):
                m.d.comb += serial.rx.ack.eq(1)

                # Reset registers
                m.d.sync += [
                    bytes_count.eq(data_width // 8 - 1),
                    words_count.eq(0),
                ]

                with m.If(serial.rx.rdy):
                    m.d.sync += cmd.eq(serial.rx.data)
                    m.next = "Receive-Length"

            with m.State("Receive-Length"):
                m.d.comb += serial.rx.ack.eq(1)

                with m.If(serial.rx.rdy):
                    m.d.sync += length.eq(serial.rx.data)
                    m.next = "Receive-Address"

            with m.State("Receive-Address"):
                m.d.comb += serial.rx.ack.eq(1)

                with m.If(serial.rx.rdy):
                    m.d.sync += [
                        address.eq(Cat(serial.rx.data, address)),
                        bytes_count.eq(bytes_count - 1),
                    ]

                    with m.If(bytes_count == 0):
                        with m.Switch(cmd):
                            with m.Case(0x01):
                                m.next = "Handle-Write"
                            with m.Case(0x02):
                                m.next = "Handle-Read"
                            with m.Case():
                                m.next = "Receive-Cmd"

            with m.State("Handle-Write"):
                m.d.comb += serial.rx.ack.eq(1)

                with m.If(serial.rx.rdy):
                    m.d.sync += [
                        data.eq(Cat(serial.rx.data, data)),
                        bytes_count.eq(bytes_count - 1),
                    ]
                    with m.If(bytes_count == 0):
                        m.next = "Write-Data"

            with m.State("Write-Data"):
                m.d.comb += [
                    self.bus.stb.eq(1),
                    self.bus.we.eq(1),
                    self.bus.cyc.eq(1),
                    self.bus.sel.eq(0xF),
                ]

                with m.If(self.bus.ack):
                    m.next = "Receive-Cmd"

            with m.State("Handle-Read"):
                m.d.comb += [
                    self.bus.stb.eq(1),
                    self.bus.we.eq(0),
                    self.bus.cyc.eq(1),
                    self.bus.sel.eq(0xF),
                ]

                with m.If(self.bus.ack):
                    m.d.sync += [
                        bytes_count.eq(data_width // 8 - 1),
                        data.eq(self.bus.dat_r),
                    ]
                    m.next = "Send-Data"

            with m.State("Send-Data"):
                m.d.comb += serial.tx.ack.eq(1)

                with m.Switch(bytes_count):
                    for i in range(data_width // 8):
                        with m.Case(i):
                            m.d.comb += serial.tx.data.eq(data[i * 8:(i + 1) *
                                                               8])

                with m.If(serial.tx.rdy):
                    m.next = "Send-Data-Wait"

            with m.State("Send-Data-Wait"):
                with m.If(serial.tx.rdy):
                    m.d.sync += [
                        bytes_count.eq(bytes_count - 1),
                    ]

                    with m.If(bytes_count == 0):
                        m.next = "Receive-Cmd"
                    with m.Else():
                        m.next = "Send-Data"

        return m
Exemple #12
0
    def elaborate(self, platform):
        m = Module()

        gearing = 1

        m.submodules.serdes = serdes = LatticeECP5PCIeSERDES(
            gearing)  # Declare SERDES module with 1:2 gearing
        lane = serdes.lane
        m.d.comb += lane.tx_e_idle.eq(0)

        m.domains.rx = ClockDomain()
        m.domains.tx = ClockDomain()
        m.d.comb += [
            ClockSignal("rx").eq(serdes.rx_clk),
            ClockSignal("tx").eq(serdes.tx_clk),
        ]

        # Clock outputs for the RX and TX clock domain
        platform.add_resources([Resource("test", 0, Pins("B19", dir="o"))])
        m.d.comb += platform.request("test", 0).o.eq(ClockSignal("rx"))
        platform.add_resources([Resource("test", 1, Pins("A18", dir="o"))])
        m.d.comb += platform.request("test", 1).o.eq(ClockSignal("tx"))

        # Counters for the LEDs
        refclkcounter = Signal(32)
        m.d.sync += refclkcounter.eq(refclkcounter + 1)
        rxclkcounter = Signal(32)
        m.d.rx += rxclkcounter.eq(rxclkcounter + 1)
        txclkcounter = Signal(32)
        m.d.tx += txclkcounter.eq(txclkcounter + 1)

        old_rx = Signal(8)
        m.d.sync += old_rx.eq(Cat(lane.rx_symbol[0:8]))

        tx_symbol = Signal(9, reset=56)

        timer = Signal(32)

        fftest_a = Signal(32)
        fftest_b = Signal(32)
        fftest_a_last = Signal(32)

        slipcnt = Signal(5)
        lastslip = Signal()
        m.d.rx += serdes.slip.eq(rxclkcounter[2])
        m.d.sync += lastslip.eq(serdes.slip)
        with m.If(serdes.slip & ~lastslip):
            with m.If(slipcnt < (10 * gearing - 1)):
                m.d.sync += slipcnt.eq(slipcnt + 1)
            with m.Else():
                m.d.sync += slipcnt.eq(0)

        leds = Cat(platform.request("led", i) for i in range(8))
        m.d.comb += leds[0].eq(~serdes.lane.rx_locked)
        m.d.comb += leds[1].eq(~serdes.lane.rx_present)

        #m.submodules += FFSynchronizer(fftest_a, fftest_b, o_domain="tx")

        with m.FSM():
            #with m.State("Align"):
            #    m.d.rx += fftest_a.eq(~fftest_a)
            #    m.d.rx += timer.eq(timer + 1)
            #    m.d.rx += fftest_a_last.eq(fftest_a)
            #    m.d.tx += fftest_b.eq(fftest_a)
            #
            #    with m.If(fftest_b != fftest_a_last):
            #        m.d.rx += timer.eq(0)
            #
            #    m.d.rx += serdes.slip.eq(rxclkcounter[10])
            #
            #    with m.If(timer == 128):
            #        m.next = "BERTest"
            #
            #
            #    m.next = "BERTest"
            with m.State("Align2"):
                last_rxclkcounter = Signal(32)
                m.d.rx += last_rxclkcounter.eq(rxclkcounter)

                m.d.rx += timer.eq(timer + 1)

                m.d.rx += tx_symbol.eq(Ctrl.STP)

                cond = (Cat(lane.rx_symbol[0:9]) == Ctrl.STP) & (Cat(
                    lane.rx_symbol[9:18]) == Ctrl.COM)

                with m.If(
                        rxclkcounter[8] & ~last_rxclkcounter[8]
                ):  #~((Cat(lane.rx_symbol[0:9]) - old_rx == 0) | (Cat(lane.rx_symbol[0:9]) - old_rx == -2)))
                    with m.If(cond):
                        m.d.rx += timer.eq(0)
                        m.next = "BERTest"
                    with m.Else():
                        pass  #m.d.rx += serdes.slip.eq(~serdes.slip)

                # Invert Lane if too long errored
                m.d.rx += lane.rx_invert.eq(timer[16])
            with m.State("BERTest"):
                m.d.rx += lane.tx_disp.eq(0)
                #m.d.rx += lane.tx_set_disp.eq(1)
                m.d.rx += timer.eq(timer + 1)
                m.d.rx += tx_symbol.eq(Cat(timer[0:8], 0))

        m.d.rx += lane.rx_invert.eq(1)
        #m.d.rx += tx_symbol.eq(tx_symbol + 1)

        commacnt = Signal(3)
        #m.d.sync += commacnt.eq(commacnt + 1)
        with m.If(commacnt == 6):
            m.d.sync += commacnt.eq(0)

        #m.d.comb += Cat(serdes.lane.tx_symbol[0:9]).eq(Mux(commacnt == 2, Ctrl.COM, Ctrl.STP))#(tx_symbol)
        m.d.comb += Cat(serdes.lane.tx_symbol[0:9]).eq(0b101010101)
        m.d.comb += Cat(serdes.lane.tx_symbol[9:18]).eq(Ctrl.COM)
        uart_pins = platform.request("uart", 0)
        uart = AsyncSerial(divisor=int(100), pins=uart_pins)
        m.submodules += uart

        m.d.sync += lane.rx_align.eq(1)

        #debug = UARTDebugger(uart, 8, CAPTURE_DEPTH, Cat(lane.rx_symbol[0:9], lane.rx_aligned, Signal(6), lane.rx_symbol[9:18], lane.rx_valid[0] | lane.rx_valid[1], Signal(6),
        #    lane.tx_symbol[0:9], Signal(7), lane.tx_symbol[9:18], Signal(7)), "rx")
        #debug = UARTDebugger(uart, 8, CAPTURE_DEPTH, Cat(lane.rx_symbol[0:9], lane.rx_aligned, Signal(6), lane.rx_symbol[9:18], lane.rx_valid[0] | lane.rx_valid[1], Signal(6),
        #    serdes.tx_bus_s_2[0:9], Signal(7), serdes.tx_bus_s_2[12:21], Signal(7)), "rx")
        #debug = UARTDebugger(uart, 8, CAPTURE_DEPTH, Cat(lane.rx_symbol[0:9], lane.rx_aligned, Signal(6+9), lane.rx_valid[0], Signal(6),
        #    serdes.tx_bus_s_2[0:9], Signal(7+9), Signal(7)), "rx")
        #debug = UARTDebugger(uart, 9, CAPTURE_DEPTH, Cat(lane.rx_symbol[0:9], lane.rx_aligned, Signal(6+9), lane.rx_valid[0], Signal(6),
        #    serdes.tx_bus[0:9], Signal(7+9), Signal(7), Cat(slipcnt, lane.rx_present, lane.rx_locked, lane.rx_valid)), "rx")
        debug = UARTDebugger(
            uart, 9, CAPTURE_DEPTH,
            Cat(serdes.rx_bus[0:10], lane.rx_aligned, Signal(5 + 9),
                lane.rx_valid[0], Signal(6), serdes.tx_bus[0:10],
                Signal(6 + 9), Signal(7),
                Cat(slipcnt, lane.rx_present, lane.rx_locked, lane.rx_valid)),
            "rx")
        m.submodules += debug

        return m
    def elaborate(self, platform: Platform) -> Module:
        m = Module()

        # UART pins for the AsyncSerial, is needed for doing output enable
        uart_pins = Record([("rx", [("i", 1)]), ("tx", [("o", 1)])])

        # Add the UART resources of the ROCKPro64
        platform.add_resources(
            [Resource("rx_rp64", 0, Pins(self.rx, dir="i"))])
        platform.add_resources(
            [Resource("tx_rp64", 0, Pins(self.tx, dir="oe"))])

        rx_pin = platform.request("rx_rp64", 0)
        tx_pin = platform.request("tx_rp64", 0)

        m.d.comb += uart_pins.rx.i.eq(rx_pin.i)
        m.d.comb += tx_pin.o.eq(uart_pins.tx.o)

        # ROCKPro64 refuses to boot if this is high
        enable_tx = Signal()
        m.d.comb += tx_pin.oe.eq(enable_tx)

        # 1.5 Megabaud UART to the ROCKPro64
        uart = AsyncSerial(divisor=int(self.clk / 1.5E6), pins=uart_pins)
        m.submodules += uart

        # Send 0x03 (Ctrl C) until the u-boot prompt appears (might take quite a while because apparently it seems to try to connect to the network interface for a long time)
        # Send 'pci enum' once '=>' is received and init is asserted
        # Set init_sent to high for 1 cycle after '\n' has been sent

        # Turn a string into a list of bytes
        def generate_memory(data_string):
            result = []
            for char in data_string:
                result.append(ord(char))
            return result

        # Command to send. Don't forget to change depth when changing this command.
        depth = 10
        pci_mem = Memory(width=8,
                         depth=depth,
                         init=generate_memory(' pci enum\n'))
        pci_rport = m.submodules.pci_rport = pci_mem.read_port()

        # Hardwired to 1, since boot is not yet controlled
        m.d.comb += enable_tx.eq(1)

        # We can always accept data
        m.d.comb += uart.rx.ack.eq(1)

        with m.FSM():
            with m.State("Wait"):
                m.d.sync += [
                    uart.tx.data.eq(0x03),  # Spam Ctrl C
                    uart.tx.ack.eq(1),
                ]

                # Wait for '=>'
                with m.If(uart.rx.data == ord('=')):
                    m.next = "uboot-1"

            with m.State("uboot-1"):
                m.d.sync += self.init_sent.eq(0)
                with m.If(uart.rx.data == ord('>')):
                    m.next = "uboot-2"

            # Arrived at u-boot prompt, ready to sent, waiting for init signal
            with m.State("uboot-2"):
                m.d.sync += self.rdy.eq(1)
                with m.If(self.init):
                    m.next = "send-pci-start"

            # Go! Set the UART data to what the memory outputs.
            with m.State("send-pci-start"):
                m.d.sync += [
                    self.rdy.eq(0),
                    uart.tx.data.eq(pci_rport.data),
                    pci_rport.addr.eq(0),
                ]

                # Once the TX is ready, send data
                with m.If(uart.tx.rdy):
                    m.next = "send-pci-data"

            with m.State("send-pci-data"):
                m.d.sync += uart.tx.data.eq(pci_rport.data)
                m.d.sync += uart.tx.ack.eq(uart.tx.rdy)

                # When the TX stops being ready, set the next byte. Doesn't work with 'Rose'.
                with m.If(Fell(uart.tx.rdy)):
                    m.d.sync += pci_rport.addr.eq(pci_rport.addr + 1)

                # Once all data has been sent, go back to waiting for '>' and strobe init_sent.
                with m.If((pci_rport.addr == depth - 1)):
                    m.next = "uboot-1"
                    m.d.sync += self.init_sent.eq(1)

        uart_pins = platform.request("uart", 0)

        #m.d.comb += uart_pins.tx.o.eq(tx_pin.o)
        m.d.comb += uart_pins.tx.o.eq(rx_pin.i)

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

        # Received symbols are aligned and processed by the PCIePhyRX
        # The PCIePhyTX sends symbols to the SERDES
        m.submodules.serdes = serdes = LatticeECP5PCIeSERDESx2(
        )  # Declare SERDES module with 1:2 gearing
        m.submodules.aligner = aligner = DomainRenamer("rx")(PCIeSERDESAligner(
            serdes.lane))  # Aligner for aligning COM symbols
        m.submodules.scrambler = lane = PCIeScrambler(
            aligner)  # Aligner for aligning COM symbols
        #lane = serdes.lane # Aligner for aligning COM symbols
        m.submodules.phy_rx = phy_rx = PCIePhyRX(aligner, lane)
        m.submodules.phy_tx = phy_tx = PCIePhyTX(lane)
        #m.submodules.lfsr = lfsr = PCIeLFSR(0, 1)
        #m.submodules.phy_txfake = phy_txfake = PCIePhyTX(PCIeSERDESInterface(ratio = 2))

        # Link Status Machine to test
        #m.submodules.ltssm = ltssm = PCIeLTSSM(lane, phy_tx, phy_rx)
        m.submodules.ltssm = ltssm = PCIeLTSSM(lane, phy_tx, phy_rx)
        #m.d.comb += [
        #    phy_tx.ts.eq(0),
        #    phy_tx.ts.valid.eq(1),
        #    phy_tx.ts.rate.eq(1),
        #    phy_tx.ts.ctrl.eq(0)
        #]

        m.d.rx += lane.enable.eq(ltssm.status.link.scrambling
                                 & ~phy_tx.sending_ts)

        m.d.comb += [
            #lane.rx_invert.eq(0),
            serdes.lane.rx_align.eq(1),
        ]

        m.d.comb += [
            #lane.rx_invert.eq(0),
            lane.rx_align.eq(1),
        ]

        # Declare the RX and TX clock domain, most of the logic happens in the RX domain
        m.domains.rx = ClockDomain()
        m.domains.tx = ClockDomain()
        m.d.comb += [
            ClockSignal("rx").eq(serdes.rx_clk),
            ClockSignal("tx").eq(serdes.tx_clk),
        ]

        # Clock outputs for the RX and TX clock domain
        #platform.add_resources([Resource("test", 0, Pins("B19", dir="o"))])
        #m.d.comb += platform.request("test", 0).o.eq(ClockSignal("rx"))
        #platform.add_resources([Resource("test", 1, Pins("A18", dir="o"))])
        #m.d.comb += platform.request("test", 1).o.eq(ClockSignal("tx"))

        # Counters for the LEDs
        refclkcounter = Signal(32)
        m.d.sync += refclkcounter.eq(refclkcounter + 1)
        rxclkcounter = Signal(32)
        m.d.rx += rxclkcounter.eq(rxclkcounter + 1)
        txclkcounter = Signal(32)
        m.d.tx += txclkcounter.eq(txclkcounter + 1)

        #m.d.rx += serdes.slip.eq(rxclkcounter[25])

        ## Sample temperature once a second
        #m.d.sync += dtr.start.eq(refclkcounter[25])

        # Temperature sensor, the chip gets kinda hot
        sample = Signal()
        m.d.sync += sample.eq(refclkcounter[25])
        m.submodules.dtr = dtr = DTR(start=refclkcounter[25] & ~sample)

        # Can be used to count how many cycles det_status is on, currently unused
        detstatuscounter = Signal(7)
        with m.If(lane.det_valid & lane.det_status):
            m.d.tx += detstatuscounter.eq(detstatuscounter + 1)

        leds = Cat(platform.request("led", i) for i in range(8))
        leds_alnum = Cat(platform.request("alnum_led", 0))

        # Information LEDs, first three output the clock frequency of the clock domains divided by 2^26
        #m.d.comb += [
        #    leds[0].eq(~(refclkcounter[25])),
        #    leds[2].eq(~(rxclkcounter[25])),
        #    leds[3].eq(~(txclkcounter[25])),
        #    leds[1].eq(~(serdes.lane.rx_aligned)),
        #    leds[4].eq(~(serdes.lane.rx_present)),
        #    leds[5].eq(~(serdes.lane.rx_locked | serdes.lane.tx_locked)),
        #    leds[6].eq(~(0)),#serdes.rxde0)),
        #    leds[7].eq(~(ltssm.status.link.up)),#serdes.rxce0)),
        #]

        m.d.comb += leds_alnum.eq(ltssm.debug_state)
        m.d.comb += leds.eq(~ltssm.debug_state)

        uart_pins = platform.request("uart", 0)
        uart = AsyncSerial(divisor=int(100), pins=uart_pins)
        m.submodules += uart

        # In the default mode, there are some extra words for debugging data
        debug1 = Signal(16)
        debug2 = Signal(16)
        debug3 = Signal(16)
        debug4 = Signal(16)

        # For example data from the LTSSM
        m.d.comb += debug1.eq(ltssm.tx_ts_count)
        m.d.comb += debug2.eq(ltssm.rx_ts_count)
        # Or data about TSs
        m.d.comb += debug3.eq(
            Cat(phy_rx.ts.valid, phy_rx.ts.lane.valid, phy_rx.ts.link.valid,
                phy_rx.ts.ts_id))
        m.d.comb += debug4.eq(1234)

        if NO_DEBUG:
            pass
        if self.tstest:
            # l = Link Number, L = Lane Number, v = Link Valid, V = Lane Valid, t = TS Valid, T = TS ID, n = FTS count, r = TS.rate, c = TS.ctrl, d = lane.det_status, D = lane.det_valid
            # DdTcccccrrrrrrrrnnnnnnnnLLLLLtVvllllllll
            debug = UARTDebugger(
                uart, 5, CAPTURE_DEPTH,
                Cat(phy_rx.ts.link.number, phy_rx.ts.link.valid,
                    phy_rx.ts.lane.valid, phy_rx.ts.valid,
                    phy_rx.ts.lane.number, phy_rx.ts.n_fts, phy_rx.ts.rate,
                    phy_rx.ts.ctrl, phy_rx.ts.ts_id, lane.det_status,
                    lane.det_valid), "rx")  # lane.rx_present & lane.rx_locked)
            #debug = UARTDebugger(uart, 5, CAPTURE_DEPTH, Cat(ts.link.number, ts.link.valid, ts.lane.valid, ts.valid, ts.lane.number, ts.n_fts, ts.rate, ts.ctrl, ts.ts_id, Signal(2)), "rx") # lane.rx_present & lane.rx_locked)
            #debug = UARTDebugger(uart, 5, CAPTURE_DEPTH, Cat(Signal(8, reset=123), Signal(4 * 8)), "rx") # lane.rx_present & lane.rx_locked)

        elif STATE_TEST:
            # 32t 9R 9R 9T 9T 2v 2-
            # t = Ticks since state was entered
            # R = RX symbol
            # T = TX symbol
            # v = RX valid

            time_since_state = Signal(32)

            with m.If(ltssm.debug_state != TESTING_STATE):
                m.d.rx += time_since_state.eq(0)
            with m.Else():
                m.d.rx += time_since_state.eq(time_since_state + 1)
            #m.d.rx += time_since_state.eq(ltssm.status.link.scrambling)
            #m.d.rx += time_since_state.eq(ltssm.rx_idl_count_total)
            #m.d.rx += time_since_state.eq(Cat(phy_rx.inverted, lane.rx_invert))

            debug = UARTDebugger(
                uart, 9, CAPTURE_DEPTH,
                Cat(time_since_state, lane.rx_symbol, lane.tx_symbol,
                    lane.rx_locked & lane.rx_present & lane.rx_aligned,
                    lane.rx_locked & lane.rx_present & lane.rx_aligned,
                    Signal(2)), "rx"
            )  #, (ltssm.debug_state == TESTING_STATE) & (time_since_state < CAPTURE_DEPTH), timeout=100 * 1000 * 1000)

        elif FSM_LOG:
            # Keep track of time in 8 nanosecond increments
            time = Signal(64)
            m.d.rx += time.eq(time + 1)

            # Real time in 10 ns ticks, doesnt drift or change in frequency as compared to the RX clock domain.
            realtime = Signal(64)
            m.d.sync += realtime.eq(realtime + 1)

            # Real time FF sync
            realtime_rx = Signal(64)
            m.submodules += FFSynchronizer(realtime,
                                           realtime_rx,
                                           o_domain="rx")

            last_state = Signal(8)
            m.d.rx += last_state.eq(ltssm.debug_state)
            # 8o 8c 64t 64r 32i 6T 1v 1- 8l 5L o O 1-
            # o = old state, c = current state, t = time, r = realtime, i = idle count, T = temperature, v = temperature valid, - = empty, l = link, L = lane, o = link valid, O = lane valid
            # preceding number is number of bits
            debug = UARTDebugger(uart,
                                 25,
                                 CAPTURE_DEPTH,
                                 Cat(last_state, ltssm.debug_state, time,
                                     realtime_rx, Signal(32), dtr.temperature,
                                     Signal(1), dtr.valid,
                                     phy_rx.ts.link.number,
                                     phy_rx.ts.lane.number,
                                     phy_rx.ts.link.valid,
                                     phy_rx.ts.lane.valid, Signal(1)),
                                 "rx",
                                 ltssm.debug_state != last_state,
                                 timeout=100 * 1000 * 1000)

        else:
            # ssssssss sa000000 ssssssss sb000000 llllllll SSSSSSSS S0000000 SSSSSSSS S0000000 dddddddd dddddddd dddddddd dddddddd dddddddd dddddddd dddddddd dddddddd s = rx_symbol, S = tx_symbol, a = aligned, b = valid, l = ltssm state, d = debug
            debug = UARTDebugger(uart, 17, CAPTURE_DEPTH,
                                 Cat(lane.rx_symbol[0:9], lane.rx_aligned,
                                     Signal(6), lane.rx_symbol[9:18],
                                     lane.rx_valid[0] | lane.rx_valid[1],
                                     Signal(6),
                                     ltssm.debug_state, lane.tx_symbol[0:9],
                                     Signal(7), lane.tx_symbol[9:18],
                                     Signal(7), debug1, debug2, debug3,
                                     debug4),
                                 "rx")  # lane.rx_present & lane.rx_locked)
        m.submodules += debug

        return m
Exemple #15
0
    def elaborate(self, platform):
        m = Module()

        m.submodules.serdes = serdes = LatticeECP5PCIeSERDES(2)
        m.submodules.aligner = lane = DomainRenamer("rx")(PCIeSERDESAligner(
            serdes.lane))
        m.submodules.phy_rx = phy_rx = PCIePhyRX(lane)
        #lane = serdes.lane

        m.d.comb += [
            #    serdes.txd.eq(K(28,5)),
            #lane.rx.eq(1), Crucial?
            lane.rx_invert.eq(0),
            lane.rx_align.eq(1),
        ]

        #m.domains.sync = ClockDomain()
        m.domains.rx = ClockDomain()
        m.domains.tx = ClockDomain()
        m.d.comb += [
            #ClockSignal("sync").eq(serdes.refclk),
            ClockSignal("rx").eq(serdes.rx_clk),
            ClockSignal("tx").eq(serdes.tx_clk),
        ]

        cntr = Signal(8)
        #m.d.tx += lane.tx_symbol.eq(Ctrl.IDL)
        with m.FSM(domain="tx"):
            with m.State("1"):
                m.d.tx += lane.tx_symbol.eq(Ctrl.COM)
                m.next = "2"
            with m.State("2"):
                m.d.tx += lane.tx_symbol.eq(Ctrl.SKP)
                m.d.tx += cntr.eq(cntr + 1)
                with m.If(cntr == 3):
                    m.d.tx += cntr.eq(0)
                    m.next = "1"

        platform.add_resources([Resource("test", 0, Pins("B19", dir="o"))])
        m.d.comb += platform.request("test", 0).o.eq(ClockSignal("rx"))
        platform.add_resources([Resource("test", 1, Pins("A18", dir="o"))])
        m.d.comb += platform.request("test", 1).o.eq(ClockSignal("tx"))

        refclkcounter = Signal(32)
        m.d.sync += refclkcounter.eq(refclkcounter + 1)
        rxclkcounter = Signal(32)
        m.d.rx += rxclkcounter.eq(rxclkcounter + 1)
        txclkcounter = Signal(32)
        m.d.tx += txclkcounter.eq(txclkcounter + 1)

        led_att1 = platform.request("led", 0)
        led_att2 = platform.request("led", 1)
        led_sta1 = platform.request("led", 2)
        led_sta2 = platform.request("led", 3)
        led_err1 = platform.request("led", 4)
        led_err2 = platform.request("led", 5)
        led_err3 = platform.request("led", 6)
        led_err4 = platform.request("led", 7)
        m.d.rx += lane.det_enable.eq(1)
        m.d.comb += [
            led_att1.eq(~(refclkcounter[25])),
            led_att2.eq(~(serdes.lane.rx_aligned)),
            led_sta1.eq(~(rxclkcounter[25])),
            led_sta2.eq(~(txclkcounter[25])),
            led_err1.eq(~(serdes.lane.rx_present)),
            led_err2.eq(~(serdes.lane.rx_locked | serdes.lane.tx_locked)),
            led_err3.eq(~(lane.det_valid)),  #serdes.rxde0)),
            led_err4.eq(~(lane.det_status)),  #serdes.rxce0)),
        ]
        triggered = Signal(reset=1)
        #m.d.tx += triggered.eq((triggered ^ ((lane.rx_symbol[0:9] == Ctrl.EIE) | (lane.rx_symbol[9:18] == Ctrl.EIE))))

        uart_pins = platform.request("uart", 0)
        uart = AsyncSerial(divisor=int(100), pins=uart_pins)
        m.submodules += uart

        m.d.rx += lane.tx_e_idle.eq(1)
        if self.tstest:
            # l = Link Number, L = Lane Number, v = Link Valid, V = Lane Valid, t = TS Valid, T = TS ID, n = FTS count, r = TS.rate, c = TS.ctrl, d = lane.det_status, D = lane.det_valid
            # DdTcccccrrrrrrrrnnnnnnnnLLLLLtVvllllllll
            debug = UARTDebugger(
                uart, 5, CAPTURE_DEPTH,
                Cat(phy_rx.ts.link.number, phy_rx.ts.link.valid,
                    phy_rx.ts.lane.valid, phy_rx.ts.valid,
                    phy_rx.ts.lane.number, phy_rx.ts.n_fts, phy_rx.ts.rate,
                    phy_rx.ts.ctrl, phy_rx.ts.ts_id, lane.det_status,
                    lane.det_valid), "rx")  # lane.rx_present & lane.rx_locked)
            #debug = UARTDebugger(uart, 5, CAPTURE_DEPTH, Cat(ts.link.number, ts.link.valid, ts.lane.valid, ts.valid, ts.lane.number, ts.n_fts, ts.rate, ts.ctrl, ts.ts_id, Signal(2)), "rx") # lane.rx_present & lane.rx_locked)
            #debug = UARTDebugger(uart, 5, CAPTURE_DEPTH, Cat(Signal(8, reset=123), Signal(4 * 8)), "rx") # lane.rx_present & lane.rx_locked)
        else:
            debug = UARTDebugger(
                uart, 4, CAPTURE_DEPTH,
                Cat(lane.rx_symbol[0:9], lane.rx_aligned, Signal(6),
                    lane.rx_symbol[9:18], lane.rx_valid[0] | lane.rx_valid[1],
                    Signal(6)), "rx",
                triggered)  # lane.rx_present & lane.rx_locked)
        m.submodules += debug

        return m
Exemple #16
0
    def elaborate(self, platform):
        # VGA constants
        pixel_f           = self.timing.pixel_freq
        hsync_front_porch = self.timing.h_front_porch
        hsync_pulse_width = self.timing.h_sync_pulse
        hsync_back_porch  = self.timing.h_back_porch
        vsync_front_porch = self.timing.v_front_porch
        vsync_pulse_width = self.timing.v_sync_pulse
        vsync_back_porch  = self.timing.v_back_porch

        # Pins
        clk25   = platform.request("clk25")
        ov7670  = platform.request("ov7670")
        led     = [platform.request("led", i) for i in range(8)]
        leds    = Cat([i.o for i in led])
        led8_2  = platform.request("led8_2")
        leds8_2 = Cat([led8_2.leds[i] for i in range(8)])
        led8_3  = platform.request("led8_3")
        leds8_3 = Cat([led8_3.leds[i] for i in range(8)])
        leds16  = Cat(leds8_3, leds8_2)
        btn1    = platform.request("button_fire", 0)
        btn2    = platform.request("button_fire", 1)
        up      = platform.request("button_up", 0)
        down    = platform.request("button_down", 0)
        pwr     = platform.request("button_pwr", 0)
        left    = platform.request("button_left", 0)
        right   = platform.request("button_right", 0)
        sw      =  Cat([platform.request("switch",i) for i in range(4)])
        uart    = platform.request("uart")
        divisor = int(platform.default_clk_frequency // 460800)
        esp32   = platform.request("esp32_spi")

        csn     = esp32.csn
        sclk    = esp32.sclk
        copi    = esp32.copi
        cipo    = esp32.cipo

        m = Module()
        
        # Clock generator.
        m.domains.sync  = cd_sync  = ClockDomain("sync")
        m.domains.pixel = cd_pixel = ClockDomain("pixel")
        m.domains.shift = cd_shift = ClockDomain("shift")

        m.submodules.ecp5pll = pll = ECP5PLL()
        pll.register_clkin(clk25,  platform.default_clk_frequency)
        pll.create_clkout(cd_sync,  platform.default_clk_frequency)
        pll.create_clkout(cd_pixel, pixel_f)
        pll.create_clkout(cd_shift, pixel_f * 5.0 * (1.0 if self.ddr else 2.0))

        # Add CamRead submodule
        camread = CamRead()
        m.submodules.camread = camread

        # Camera config
        cam_x_res = 640
        cam_y_res = 480

        camconfig = CamConfig()
        m.submodules.camconfig = camconfig

        # OV7670 options: bit 0 = color bar
        ov_opts       = Signal(8, reset=0)
        ov_brightness = Signal(8, reset=0)
        ov_contrast   = Signal(8, reset=0x40)
        
        # Connect the camera pins and config and read modules
        m.d.comb += [
            ov7670.cam_RESET.eq(1),
            ov7670.cam_PWON.eq(0),
            ov7670.cam_XCLK.eq(clk25.i),
            ov7670.cam_SIOC.eq(camconfig.sioc),
            ov7670.cam_SIOD.eq(camconfig.siod),
            camconfig.start.eq(btn1),
            camconfig.options.eq(ov_opts),
            camconfig.brightness.eq(ov_brightness),
            camconfig.contrast.eq(ov_contrast),
            camread.p_data.eq(Cat([ov7670.cam_data[i] for i in range(8)])),
            camread.href.eq(ov7670.cam_HREF),
            camread.vsync.eq(ov7670.cam_VSYNC),
            camread.p_clock.eq(ov7670.cam_PCLK)
        ]

        # Create the uart
        m.submodules.serial = serial = AsyncSerial(divisor=divisor, pins=uart)

        # Frame buffer
        x_res= cam_x_res // 2
        y_res= cam_y_res // 2

        buffer = Memory(width=16, depth=x_res * y_res)
        m.submodules.r = r = buffer.read_port()
        m.submodules.w = w = buffer.write_port()

        # Button debouncers
        m.submodules.debup   = debup = Debouncer()
        m.submodules.debdown = debdown = Debouncer()
        m.submodules.debosd  = debosd = Debouncer()
        m.submodules.debsel  = debsel = Debouncer()
        m.submodules.debsnap = debsnap = Debouncer()
        m.submodules.debhist = debhist = Debouncer()

        # Connect the buttons to debouncers
        m.d.comb += [
            debup.btn.eq(up),
            debdown.btn.eq(down),
            debosd.btn.eq(pwr),
            debsel.btn.eq(right),
            debsnap.btn.eq(left),
            debhist.btn.eq(btn2)
        ]

        # Image processing configuration registers
        flip         = Signal(2, reset=1)           # Flip the image horizontally or vertically
        mono_en      = Signal(reset=0)              # Convert to monochrome
        invert       = Signal(reset=0)              # Invert monochrome image
        thresh_en    = Signal(reset=0)              # Apply threshold to monochrome image  
        threshold    = Signal(8, reset=0)           # Threshold value
        border       = Signal(reset=0)              # Use OSD to show a border
        filt_en      = Signal(reset=0)              # Apply a color filter
        l            = Rgb565(reset=(18,12,6))      # Image filter low values
        h            = Rgb565(reset=(21,22,14))     # Image filter high values
        grid         = Signal(reset=0)              # Use OSD to show a grid
        hist_view    = Signal(reset=1)              # Switch to histogram view
        hist_chan    = Signal(2, reset=0)           # The histogram channel to calculate
        ccr          = CC(reset=(0,0,18,12,16))     # Color control record
        sharpness    = Signal(unsigned(4), reset=0) # Used to select image convolution kernel for blur/sharpness
        roi          = Roi()                        # Region on interest
        frozen       = Signal(reset=1)              # Freeze/unfreeze video display
        sat_en       = Signal()
        saturation   = Signal(5, reset=16)
        border_color = Rgb565(reset=(31,0,0))
        double       = Signal(reset=0)
        square       = Signal(reset=0)

        # Control synchronization of camera with fifo
        sync_fifo = Signal(reset=0)

        # OSD control signals
        osd_val     = Signal(4, reset=0) # Account for spurious start-up button pushes
        osd_on      = Signal(reset=1)
        osd_sel     = Signal(reset=1)

        # Snapshot signals
        snap        = Signal(reset=0)
        writing     = Signal(reset=0)
        written     = Signal(reset=0)
        byte        = Signal(reset=0)
        w_addr      = Signal(18)

        # Signals for calculating histogram
        hist_val    = Signal(6)

        # Signals for displaying histogram
        hist_color  = Signal(8)
        hbin        = Signal(6, reset=0)  
        bin_cnt     = Signal(5, reset=0)
        old_x       = Signal(10)
        
        # Frame buffer coordinates
        frame_x     = Signal(9)
        frame_y     = Signal(9)
        
        # VGA signals
        vga_r       = Signal(8)
        vga_g       = Signal(8)
        vga_b       = Signal(8)
        vga_hsync   = Signal()
        vga_vsync   = Signal()
        vga_blank   = Signal()

        # Fifo stream
        m.submodules.fifo_stream = fs = FifoStream(x_res = x_res, y_res = y_res, fifo_depth=1024)

        # SPI memory for remote configuration
        m.submodules.spimem = spimem = SpiMem(addr_bits=32)

        # Color Control
        m.submodules.cc = cc = ColorControl()

        # Image convolution
        m.submodules.imc = imc = ImageConv(res_x=x_res, res_y=y_res)

        # Statistics
        m.submodules.stats = stats = Stats()

        # Histogram
        m.submodules.hist = hist = Hist()

        # Filter
        m.submodules.fil = fil = Filt()

        # Monochrome
        m.submodules.mon = mon = Mono()

        # Saturation
        m.submodules.sat = sat = Saturation()

        # Buffer
        m.submodules.buf = buf = Buffer()

        # Double
        m.submodules.doub = doub = Double()

        # Square
        m.submodules.sq = sq = Square()

        # Border
        m.submodules.bord = bord = Border()

        # Color correction matrix
        m.submodules.ccm = ccm = Ccm()

        # Half resolution
        m.submodules.half = half = Half()

        # Sync the fifo with the camera
        with m.If(~sync_fifo & (camread.o_x == cam_x_res - 1) & (camread.o_y == cam_y_res -1)):
            m.d.sync += sync_fifo.eq(1)

        with m.If(btn1):
            m.d.sync += sync_fifo.eq(0)

        m.d.comb += leds16.eq(fs.o_level)

        # Histogram channels
        hist_chans = Array([cc.o.r, cc.o.g, cc.o.b, mon.o_m])

        # Input image processing pipeline
        pipeline = [
            [camread, {}, True],                                    # Read from OV7670 Sensor
            [half,  {"i_reset"      : ~sync_fifo}, True],           # Reduce resolution to 320x240
            [fs,    {"i_reset"      : ~sync_fifo}, True],           # Write data to FIFO 
            [sq,    {"i_reset"      : ~sync_fifo,                   # Optional reduce to square
                     "i_en"         : square}, True],     
            [doub,  {"i_reset"      : ~sync_fifo,                   # Optional zoom in horizontally
                     "i_en"         : double}, True],
            [cc,    {"i_cc"         : ccr}, True],                  # Apply color control
            [ccm,   {}, True],                                      # Apply color control matrix
            [sat,   {"i_en"         : sat_en,                       # Adjust color saturation
                     "i_saturation" : saturation}, True],
            [fil,   {"i_en"         : filt_en,                      # Apply optional color filter
                     "i_eof"        : fs.o_eof,
                     "i_l"          : l,                  
                     "i_h"          : h}, True],
            [mon,   {"i_en"         : mono_en | invert | thresh_en, # Optional, monochrome, invert and threshold
                     "i_invert"     : invert,             
                     "i_thresh"     : thresh_en,
                     "i_threshold"  : threshold}, True],
            [bord,   {"i_reset"     : ~sync_fifo,
                      "i_en"        : border,
                      "i_width"     : 5,
                      "i_color"     : border_color}, True],
            [imc,   {"i_ready"      : 1,                            # Image convolution for blur and sharpness
                     "i_reset"      : ~sync_fifo,           
                     "i_sel"        : sharpness}, True],
            [stats, {"i"            : cc.o,                         # Produce statistics               
                     "i_valid"      : cc.o_valid,
                     "i_avg_valid"  : (fs.o_x >= 32) & (fs.o_x < 288) & 
                                      (fs.o_y >= 56) & (fs.o_y < 184),
                     "i_eof"        : fs.o_eof,           
                     "i_x"          : fs.o_x,
                     "i_y"          : fs.o_y,             
                     "i_roi"        : roi}, False],
            [hist,  {"i_p"          : hist_chans[hist_chan],        # Produce histogram         
                     "i_valid"      : mon.o_valid,
                     "i_eof"        : fs.o_eof,           
                     "i_x"          : fs.o_x,
                     "i_y"          : fs.o_y,             
                     "i_roi"        : roi,
                     "i_bin"        : hbin}, False]
        ]

        output = imc

        # Connect pipeline inputs and outputs and ready and valid signals
        def execute(pl):
            us = None # Upstream
            for p in pl:
                mod = p[0]
                d = p[1]
                st = p[2] # Stream or Sink
                if st and us is not None:
                    m.d.comb += mod.i.eq(us.o)
                    m.d.comb += mod.i_valid.eq(us.o_valid)
                    m.d.comb += us.i_ready.eq(mod.o_ready)
                if st:
                    us = mod
                for k in d:
                    m.d.comb += mod.__dict__[k].eq(d[k])

        execute(pipeline)

        # Take a snapshot, freeze the camera, and write the framebuffer to the uart
        # Note that this suspends video output
        with m.If(debsnap.btn_down | (spimem.wr & (spimem.addr == 22))):
            with m.If(frozen):
                m.d.sync += frozen.eq(0)
            with m.Else():
                m.d.sync += [
                    snap.eq(1),
                    frozen.eq(0),
                    w_addr.eq(0),
                    written.eq(0),
                    byte.eq(0)
                ]

        # Wait to end of frame after requesting snapshot, before start of writing to uart
        with m.If(output.o_eof & snap):
            m.d.sync += [
                frozen.eq(1),
                snap.eq(0)
            ]
            with m.If(~written):
                m.d.sync += writing.eq(1)

        # Connect the uart
        m.d.comb += [
            serial.tx.data.eq(Mux(byte, r.data[8:], r.data[:8])),
            serial.tx.ack.eq(writing)
        ]

        # Write to the uart from frame buffer (affects video output)
        with m.If(writing):
            with m.If(w_addr == x_res * y_res):
                m.d.sync += [
                    writing.eq(0),
                    written.eq(1)
                ]
            with m.Elif(serial.tx.ack & serial.tx.rdy):
                m.d.sync += byte.eq(~byte)
                with m.If(byte):
                    m.d.sync += w_addr.eq(w_addr+1)

        # Connect spimem pins
        m.d.comb += [
            spimem.csn.eq(~csn),
            spimem.sclk.eq(sclk),
            spimem.copi.eq(copi),
            cipo.eq(spimem.cipo),
        ]

        # Configuration registers (list implies read-only, i.e a status register)
        # Index in list is the address
        spi_vals = Array([ccr.brightness, ccr.redness, ccr.greenness, ccr.blueness, l.r, h.r, l.g, h.g, l.b, h.b,
                             sharpness, filt_en, border, mono_en, invert, grid, hist_view,
                             roi.x[1:], roi.y[1:], roi.w[1:], roi.h[1:], roi.en, [fil.o_nz[16:]], [fil.o_nz[8:16]], [fil.o_nz[:8]],
                             threshold, thresh_en, hist_chan, flip,
                             [stats.o_min.r], [stats.o_min.g], [stats.o_min.b],
                             [stats.o_max.r], [stats.o_max.g], [stats.o_max.b],
                             [stats.o_avg.r], [stats.o_avg.g], [stats.o_avg.b],
                             frozen, writing, written, sat_en, saturation, ccr.offset,
                             ccm.i_ccm[0], ccm.i_ccm[1], ccm.i_ccm[2], ccm.i_ccm[3], ccm.i_ccm[4],
                             ccm.i_ccm[5], ccm.i_ccm[6], ccm.i_ccm[7], ccm.i_ccm[8],
                             ov_opts, ov_brightness, ov_contrast, double, square])

        with m.If(spimem.wr):
            with m.Switch(spimem.addr):
                for i in range(len(spi_vals)):
                    if not isinstance(spi_vals[i], list):
                        with m.Case(i):
                            m.d.sync += spi_vals[i].eq(spimem.dout)

        with m.If(spimem.rd):
            with m.Switch(spimem.addr):
                for i in range(len(spi_vals)):
                    val = spi_vals[i][0] if isinstance(spi_vals[i], list) else spi_vals[i]
                    with m.Case(i):
                        m.d.sync += spimem.din.eq(val)

        # Add VGA generator
        m.submodules.vga = vga = VGA(
           resolution_x      = self.timing.x,
           hsync_front_porch = hsync_front_porch,
           hsync_pulse       = hsync_pulse_width,
           hsync_back_porch  = hsync_back_porch,
           resolution_y      = self.timing.y,
           vsync_front_porch = vsync_front_porch,
           vsync_pulse       = vsync_pulse_width,
           vsync_back_porch  = vsync_back_porch,
           bits_x            = 16, # Play around with the sizes because sometimes
           bits_y            = 16  # a smaller/larger value will make it pass timing.
        )

        # Fetch histogram for display
        num_bins = cam_x_res // 32

        m.d.sync += old_x.eq(vga.o_beam_x)

        with m.If(vga.o_beam_x == 0):
            m.d.sync += [
                hbin.eq(0),
                bin_cnt.eq(0)
            ]
        with m.Elif(vga.o_beam_x != old_x):
            m.d.sync += bin_cnt.eq(bin_cnt+1)
            with m.If(bin_cnt == num_bins - 1):
                m.d.sync += [
                    bin_cnt.eq(0),
                    hbin.eq(hbin+1)
                ]

        # Switch between camera and histogram view
        with m.If(debhist.btn_down):
            m.d.sync += hist_view.eq(~hist_view)
       
        # Connect frame buffer, with optional x and y flip
        vga_x = vga.o_beam_x[1:]
        vga_y = vga.o_beam_y[1:]
        m.d.comb += [
            frame_x.eq(Mux(flip[0], x_res - 1 - vga_x, vga_x)),
            frame_y.eq(Mux(flip[1], y_res - 1 - vga_y, vga_y)),
            w.en.eq(output.o_valid & ~frozen),
            w.addr.eq(output.o_y * x_res + output.o_x),
            w.data.eq(output.o.as_data()),
            r.addr.eq(Mux(writing, w_addr, frame_y * x_res + frame_x))
        ]

        # Apply the On-Screen Display (OSD)
        m.submodules.osd = osd = OSD()

        m.d.comb += [
            osd.x.eq(vga.o_beam_x),
            osd.y.eq(vga.o_beam_y),
            hist_color.eq(Mux((479 - osd.y) < hist.o_val[8:], 0xff, 0x00)),
            osd.i_r.eq(Mux(hist_view, Mux((hist_chan == 0) | (hist_chan == 3), hist_color, 0), Cat(C(0, 3), r.data[11:16]))),
            osd.i_g.eq(Mux(hist_view, Mux((hist_chan == 1) | (hist_chan == 3), hist_color, 0), Cat(C(0, 2), r.data[5:11]))),
            osd.i_b.eq(Mux(hist_view, Mux((hist_chan == 2) | (hist_chan == 3), hist_color, 0), Cat(C(0, 3), r.data[0:5]))),
            osd.on.eq(osd_on),
            osd.osd_val.eq(osd_val),
            osd.sel.eq(osd_sel),
            osd.grid.eq(grid),
            osd.border.eq(border),
            osd.roi.eq(roi.en & ~hist_view),
            osd.roi_x.eq(roi.x),
            osd.roi_y.eq(roi.y),
            osd.roi_w.eq(roi.w),
            osd.roi_h.eq(roi.h)
        ]

        # OSD control
        dummy = Signal()
        osd_vals = Array([ccr.offset, ccr.brightness, ccr.redness, ccr.greenness, ccr.blueness, sharpness, sat_en, saturation,
                          mono_en, invert, thresh_en, threshold, hist_chan, Cat(border, grid), flip, filt_en])

        def do_btn(m, btn, val, inc):
            with m.If(btn.btn_down):
                with m.If(~osd_sel):
                    m.d.sync += osd_val.eq(osd_val - inc)
                with m.Else():
                    with m.Switch(osd_val):
                        for i in range(len(osd_vals)):
                            with m.Case(i):
                                if (len(osd_vals[i]) == 1):
                                    m.d.sync += osd_vals[i].eq(val)
                                else:
                                    m.d.sync += osd_vals[i].eq(osd_vals[i] + inc)


        with m.If(debosd.btn_down):
            m.d.sync += osd_on.eq(~osd_on)

        with m.If(osd_on):
            with m.If(debsel.btn_down):
                m.d.sync += osd_sel.eq(~osd_sel)

            do_btn(m, debup, 1, 1)
            do_btn(m, debdown, 0, -1)

        # Show configuration values on leds
        with m.Switch(osd_val):
            for i in range(len(osd_vals)):
                with m.Case(i):
                    m.d.comb += leds.eq(osd_vals[i])

        # Generate VGA signals
        m.d.comb += [
            vga.i_clk_en.eq(1),
            vga.i_test_picture.eq(0),
            vga.i_r.eq(osd.o_r), 
            vga.i_g.eq(osd.o_g), 
            vga.i_b.eq(osd.o_b), 
            vga_r.eq(vga.o_vga_r),
            vga_g.eq(vga.o_vga_g),
            vga_b.eq(vga.o_vga_b),
            vga_hsync.eq(vga.o_vga_hsync),
            vga_vsync.eq(vga.o_vga_vsync),
            vga_blank.eq(vga.o_vga_blank),
        ]

        # VGA to digital video converter.
        tmds = [Signal(2) for i in range(4)]
        m.submodules.vga2dvid = vga2dvid = VGA2DVID(ddr=self.ddr, shift_clock_synchronizer=False)
        m.d.comb += [
            vga2dvid.i_red.eq(vga_r),
            vga2dvid.i_green.eq(vga_g),
            vga2dvid.i_blue.eq(vga_b),
            vga2dvid.i_hsync.eq(vga_hsync),
            vga2dvid.i_vsync.eq(vga_vsync),
            vga2dvid.i_blank.eq(vga_blank),
            tmds[3].eq(vga2dvid.o_clk),
            tmds[2].eq(vga2dvid.o_red),
            tmds[1].eq(vga2dvid.o_green),
            tmds[0].eq(vga2dvid.o_blue),
        ]

        # GPDI pins
        if (self.ddr):
            # Vendor specific DDR modules.
            # Convert SDR 2-bit input to DDR clocked 1-bit output (single-ended)
            # onboard GPDI.
            m.submodules.ddr0_clock = Instance("ODDRX1F",
                i_SCLK = ClockSignal("shift"),
                i_RST  = 0b0,
                i_D0   = tmds[3][0],
                i_D1   = tmds[3][1],
                o_Q    = self.o_gpdi_dp[3])
            m.submodules.ddr0_red   = Instance("ODDRX1F",
                i_SCLK = ClockSignal("shift"),
                i_RST  = 0b0,
                i_D0   = tmds[2][0],
                i_D1   = tmds[2][1],
                o_Q    = self.o_gpdi_dp[2])
            m.submodules.ddr0_green = Instance("ODDRX1F",
                i_SCLK = ClockSignal("shift"),
                i_RST  = 0b0,
                i_D0   = tmds[1][0],
                i_D1   = tmds[1][1],
                o_Q    = self.o_gpdi_dp[1])
            m.submodules.ddr0_blue  = Instance("ODDRX1F",
                i_SCLK = ClockSignal("shift"),
                i_RST  = 0b0,
                i_D0   = tmds[0][0],
                i_D1   = tmds[0][1],
                o_Q    = self.o_gpdi_dp[0])
        else:
            m.d.comb += [
                self.o_gpdi_dp[3].eq(tmds[3][0]),
                self.o_gpdi_dp[2].eq(tmds[2][0]),
                self.o_gpdi_dp[1].eq(tmds[1][0]),
                self.o_gpdi_dp[0].eq(tmds[0][0]),
            ]

        return m
Exemple #17
0
    def elaborate(self, platform):
        m = Module()

        m.submodules.serdes = serdes = LatticeECP5PCIeSERDES(2)
        m.submodules.aligner = lane = DomainRenamer("rx")(PCIeSERDESAligner(
            serdes.lane))
        #m.submodules.phy_rx = phy_rx = PCIePhyRX(lane)
        #lane = serdes.lane

        m.d.comb += [
            #    serdes.txd.eq(K(28,5)),
            #lane.rx.eq(1), Crucial?
            lane.rx_invert.eq(0),
            lane.rx_align.eq(1),
        ]

        #m.domains.sync = ClockDomain()
        m.domains.rx = ClockDomain()
        m.domains.tx = ClockDomain()
        m.d.comb += [
            #ClockSignal("sync").eq(serdes.refclk),
            ClockSignal("rx").eq(serdes.rx_clk),
            ClockSignal("tx").eq(serdes.tx_clk),
        ]

        cntr = Signal(5)
        #with m.If(cntr == 0):
        #    m.d.tx += lane.tx_symbol[0:9].eq(Ctrl.COM)
        #    m.d.tx += lane.tx_symbol[9:18].eq(Ctrl.SKP)
        #with m.Elif(cntr == 1):
        #    m.d.tx += lane.tx_symbol[0:9].eq(Ctrl.SKP)
        #    m.d.tx += lane.tx_symbol[9:18].eq(Ctrl.SKP)
        #with m.Elif(cntr == 2):
        #    m.d.tx += lane.tx_symbol[0:9].eq(Ctrl.EIE)
        #    m.d.tx += lane.tx_symbol[9:18].eq(Ctrl.EDB)
        #with m.Elif(cntr == 3):
        #    m.d.tx += lane.tx_symbol[0:9].eq(Ctrl.STP)
        #    m.d.tx += lane.tx_symbol[9:18].eq(Ctrl.SDP)
        #with m.Elif(cntr == 4):
        #    m.d.tx += lane.tx_symbol[0:9].eq(Ctrl.IDL)
        #    m.d.tx += lane.tx_symbol[9:18].eq(Ctrl.EIE)
        #with m.Elif(cntr == 5):
        #    m.d.tx += lane.tx_symbol[0:9].eq(Ctrl.EDB)
        #    m.d.tx += lane.tx_symbol[9:18].eq(Ctrl.EDB)
        #with m.Elif(cntr == 6):
        #    m.d.tx += lane.tx_symbol[0:9].eq(Ctrl.EIE)
        #    m.d.tx += lane.tx_symbol[9:18].eq(Ctrl.EIE)
        #with m.Elif(cntr == 7):
        #    m.d.tx += lane.tx_symbol[0:9].eq(Ctrl.END)
        #    m.d.tx += lane.tx_symbol[9:18].eq(Ctrl.END)
        #with m.Elif(cntr == 8):
        #    m.d.tx += lane.tx_symbol[0:9].eq(Ctrl.IDL)
        #    m.d.tx += lane.tx_symbol[9:18].eq(Ctrl.IDL)
        #with m.Else():
        #    m.d.tx += lane.tx_symbol.eq(cntr)

        with m.If(cntr == 0):
            m.d.tx += lane.tx_symbol[0:9].eq(Ctrl.COM)
            m.d.tx += lane.tx_symbol[9:18].eq(Ctrl.SKP)
        with m.Elif(cntr == 1):
            m.d.tx += lane.tx_symbol[0:9].eq(Ctrl.SKP)
            m.d.tx += lane.tx_symbol[9:18].eq(Ctrl.SKP)

        #with m.Elif(cntr == 6):
        #    m.d.tx += lane.tx_symbol[0:9].eq(Ctrl.COM)
        #    m.d.tx += lane.tx_symbol[9:18].eq(Ctrl.SKP)
        #with m.Elif(cntr == 7):
        #    m.d.tx += lane.tx_symbol[0:9].eq(Ctrl.SKP)
        #    m.d.tx += lane.tx_symbol[9:18].eq(Ctrl.SKP)
#
#with m.Elif(cntr == 12):
#    m.d.tx += lane.tx_symbol[0:9].eq(Ctrl.IDL)
#    m.d.tx += lane.tx_symbol[9:18].eq(Ctrl.COM)
#with m.Elif(cntr == 13):
#    m.d.tx += lane.tx_symbol[0:9].eq(Ctrl.SKP)
#    m.d.tx += lane.tx_symbol[9:18].eq(Ctrl.SKP)
#with m.Elif(cntr == 14):
#    m.d.tx += lane.tx_symbol[0:9].eq(Ctrl.SKP)
#    m.d.tx += lane.tx_symbol[9:18].eq(Ctrl.IDL)
#
#with m.Elif(cntr == 20):
#    m.d.tx += lane.tx_symbol[0:9].eq(Ctrl.IDL)
#    m.d.tx += lane.tx_symbol[9:18].eq(Ctrl.COM)
#with m.Elif(cntr == 21):
#    m.d.tx += lane.tx_symbol[0:9].eq(Ctrl.SKP)
#    m.d.tx += lane.tx_symbol[9:18].eq(Ctrl.SKP)
#with m.Elif(cntr == 22):
#    m.d.tx += lane.tx_symbol[0:9].eq(Ctrl.SKP)
#    m.d.tx += lane.tx_symbol[9:18].eq(Ctrl.IDL)

        with m.Else():
            m.d.tx += lane.tx_symbol[0:9].eq(Ctrl.IDL)
            m.d.tx += lane.tx_symbol[9:18].eq(Ctrl.IDL)
        #m.d.tx += lane.tx_symbol[0:9].eq(Ctrl.COM)
        #m.d.tx += lane.tx_symbol[9:18].eq(cntr)
        m.d.tx += cntr.eq(cntr + 1)
        #with m.FSM(domain="tx"):
        #    with m.State("1"):
        #        m.d.tx += lane.tx_symbol.eq(Ctrl.COM)
        #        m.next = "2"
        #    with m.State("2"):
        #        m.d.tx += lane.tx_symbol.eq(Ctrl.SKP)
        #        m.d.tx += cntr.eq(cntr + 1)
        #        with m.If(cntr == 3):
        #            m.d.tx += cntr.eq(0)
        #            m.next = "1"

        platform.add_resources([Resource("test", 0, Pins("B19", dir="o"))])
        #m.d.comb += platform.request("test", 0).o.eq(ClockSignal("rx"))
        platform.add_resources([Resource("test", 1, Pins("A18", dir="o"))])
        #m.d.comb += platform.request("test", 1).o.eq(ClockSignal("tx"))

        refclkcounter = Signal(32)
        m.d.sync += refclkcounter.eq(refclkcounter + 1)
        rxclkcounter = Signal(32)
        m.d.rx += rxclkcounter.eq(rxclkcounter + 1)
        txclkcounter = Signal(32)
        m.d.tx += txclkcounter.eq(txclkcounter + 1)

        led_att1 = platform.request("led", 0)
        led_att2 = platform.request("led", 1)
        led_sta1 = platform.request("led", 2)
        led_sta2 = platform.request("led", 3)
        led_err1 = platform.request("led", 4)
        led_err2 = platform.request("led", 5)
        led_err3 = platform.request("led", 6)
        led_err4 = platform.request("led", 7)
        m.d.rx += lane.det_enable.eq(1)
        m.d.comb += [
            led_att1.eq(~(refclkcounter[25])),
            led_att2.eq(~(serdes.lane.rx_aligned)),
            led_sta1.eq(~(rxclkcounter[25])),
            led_sta2.eq(~(txclkcounter[25])),
            led_err1.eq(~(serdes.lane.rx_present)),
            led_err2.eq(~(serdes.lane.rx_locked | serdes.lane.tx_locked)),
            led_err3.eq(~(lane.det_valid)),  #serdes.rxde0)),
            led_err4.eq(~(lane.det_status)),  #serdes.rxce0)),
        ]
        triggered = Const(1)
        #m.d.tx += triggered.eq((triggered ^ ((lane.rx_symbol[0:9] == Ctrl.EIE) | (lane.rx_symbol[9:18] == Ctrl.EIE))))

        uart_pins = platform.request("uart", 0)
        uart = AsyncSerial(divisor=int(100), pins=uart_pins)
        m.submodules += uart

        #m.d.rx += lane.tx_e_idle.eq(1)
        debug = UARTDebugger(uart, 4, CAPTURE_DEPTH,
                             Cat(lane.rx_symbol[0:9], lane.rx_valid[0],
                                 Signal(6), lane.rx_symbol[9:18],
                                 lane.rx_valid[1], Signal(6)), "rx",
                             triggered)  # lane.rx_present & lane.rx_locked)
        # You need to add the SERDES within the SERDES as a self. attribute for this to work
        #debug = UARTDebugger(uart, 4, CAPTURE_DEPTH, Cat(serdes.serdes.lane.rx_symbol[0:9], cntr == 0, Signal(6), Signal(9), lane.rx_valid[0] | lane.rx_valid[1], Signal(6)), "rxf", triggered) # lane.rx_present & lane.rx_locked)
        m.submodules += debug

        return m
Exemple #18
0
    def elaborate(self, platform):
        # VGA constants
        pixel_f           = self.timing.pixel_freq
        hsync_front_porch = self.timing.h_front_porch
        hsync_pulse_width = self.timing.h_sync_pulse
        hsync_back_porch  = self.timing.h_back_porch
        vsync_front_porch = self.timing.v_front_porch
        vsync_pulse_width = self.timing.v_sync_pulse
        vsync_back_porch  = self.timing.v_back_porch

        # Pins
        clk25   = platform.request("clk25")
        ov7670  = platform.request("ov7670")
        led     = [platform.request("led", i) for i in range(8)]
        leds    = Cat([i.o for i in led])
        led8_2  = platform.request("led8_2")
        leds8_2 = Cat([led8_2.leds[i] for i in range(8)])
        led8_3  = platform.request("led8_3")
        leds8_3 = Cat([led8_3.leds[i] for i in range(8)])
        leds16  = Cat(leds8_3, leds8_2)
        btn1    = platform.request("button_fire", 0)
        btn2    = platform.request("button_fire", 1)
        up      = platform.request("button_up", 0)
        down    = platform.request("button_down", 0)
        pwr     = platform.request("button_pwr", 0)
        left    = platform.request("button_left", 0)
        right   = platform.request("button_right", 0)
        sw      =  Cat([platform.request("switch",i) for i in range(4)])
        uart    = platform.request("uart")
        divisor = int(platform.default_clk_frequency // 460800)
        esp32   = platform.request("esp32_spi")

        csn     = esp32.csn
        sclk    = esp32.sclk
        copi    = esp32.copi
        cipo    = esp32.cipo

        m = Module()
        
        # Clock generator.
        m.domains.sync  = cd_sync  = ClockDomain("sync")
        m.domains.pixel = cd_pixel = ClockDomain("pixel")
        m.domains.shift = cd_shift = ClockDomain("shift")

        m.submodules.ecp5pll = pll = ECP5PLL()
        pll.register_clkin(clk25,  platform.default_clk_frequency)
        pll.create_clkout(cd_sync,  platform.default_clk_frequency)
        pll.create_clkout(cd_pixel, pixel_f)
        pll.create_clkout(cd_shift, pixel_f * 5.0 * (1.0 if self.ddr else 2.0))

        # Add CamRead submodule
        camread = CamRead()
        m.submodules.camread = camread

        # Camera config
        cam_x_res = 640
        cam_y_res = 480

        camconfig = CamConfig()
        m.submodules.camconfig = camconfig

        # Connect the camera pins and config and read modules
        m.d.comb += [
            ov7670.cam_RESET.eq(1),
            ov7670.cam_PWON.eq(0),
            ov7670.cam_XCLK.eq(clk25.i),
            ov7670.cam_SIOC.eq(camconfig.sioc),
            ov7670.cam_SIOD.eq(camconfig.siod),
            camconfig.start.eq(btn1),
            camread.p_data.eq(Cat([ov7670.cam_data[i] for i in range(8)])),
            camread.href.eq(ov7670.cam_HREF),
            camread.vsync.eq(ov7670.cam_VSYNC),
            camread.p_clock.eq(ov7670.cam_PCLK)
        ]

        # Create the uart
        m.submodules.serial = serial = AsyncSerial(divisor=divisor, pins=uart)

        # Input fifo
        fifo_depth=1024

        m.submodules.fifo = fifo = SyncFIFOBuffered(width=16,depth=fifo_depth)

        # Frame buffer
        x_res= cam_x_res // 2
        y_res= cam_y_res

        buffer = Memory(width=16, depth=x_res * y_res)
        m.submodules.r = r = buffer.read_port()
        m.submodules.w = w = buffer.write_port()

        # Button debouncers
        m.submodules.debup   = debup = Debouncer()
        m.submodules.debdown = debdown = Debouncer()
        m.submodules.debosd  = debosd = Debouncer()
        m.submodules.debsel  = debsel = Debouncer()
        m.submodules.debsnap = debsnap = Debouncer()
        m.submodules.debhist = debhist = Debouncer()

        # Connect the buttons to debouncers
        m.d.comb += [
            debup.btn.eq(up),
            debdown.btn.eq(down),
            debosd.btn.eq(pwr),
            debsel.btn.eq(right),
            debsnap.btn.eq(left),
            debhist.btn.eq(btn2)
        ]

        # Image processing options
        flip        = Signal(2, reset=1)
        mono        = Signal(reset=0)
        invert      = Signal(reset=0)
        gamma       = Signal(reset=0)
        border      = Signal(reset=0)
        filt        = Signal(reset=0)
        grid        = Signal(reset=0)
        histo       = Signal(reset=1)
        hbin        = Signal(6, reset=0)
        bin_cnt     = Signal(5, reset=0)
        thresh      = Signal(reset=0)
        threshold   = Signal(8, reset=0)
        hist_chan   = Signal(2, reset=0)

        ccc         = CC(reset=(0,18,12,16))
        sharpness   = Signal(unsigned(4), reset=0)

        osd_val     = Signal(4, reset=0) # Account for spurious start-up button pushes
        osd_on      = Signal(reset=1)
        osd_sel     = Signal(reset=1)
        snap        = Signal(reset=0)
        frozen      = Signal(reset=1)
        writing     = Signal(reset=0)
        written     = Signal(reset=0)
        byte        = Signal(reset=0)
        w_addr      = Signal(18)

        # Color filter
        l           = Rgb565(reset=(18,12,6)) # Initialised to red LEGO filter
        h           = Rgb565(reset=(21,22,14))

        # Region of interest
        roi         = Roi()

        # VGA signals
        vga_r       = Signal(8)
        vga_g       = Signal(8)
        vga_b       = Signal(8)
        vga_hsync   = Signal()
        vga_vsync   = Signal()
        vga_blank   = Signal()

        # Fifo co-ordinates
        f_x          = Signal(9)
        f_y          = Signal(9)
        f_frame_done = Signal()

        # Pixel from fifo
        pix         = Rgb565()

        # SPI memory for remote configuration
        m.submodules.spimem = spimem = SpiMem(addr_bits=32)

        # Color Control
        m.submodules.cc = cc = ColorControl()

        # Image convolution
        m.submodules.imc = imc = ImageConv()

        # Statistics
        m.submodules.stats = stats = Stats()

        # Histogram
        m.submodules.hist = hist = Hist()

        # Filter
        m.submodules.fil = fil = Filt()

        # Monochrome
        m.submodules.mon = mon = Mono()

        # Sync the fifo with the camera
        sync_fifo = Signal(reset=0)
        with m.If(~sync_fifo & ~fifo.r_rdy & (camread.col == cam_x_res - 1) & (camread.row == cam_y_res -1)):
            m.d.sync += [
                sync_fifo.eq(1),
                f_x.eq(0),
                f_y.eq(0)
            ]

        with m.If(btn1):
            m.d.sync += sync_fifo.eq(0)

        # Connect the fifo
        m.d.comb += [
            fifo.w_en.eq(camread.pixel_valid & camread.col[0] & sync_fifo), # Only write every other pixel
            fifo.w_data.eq(camread.pixel_data), 
            fifo.r_en.eq(fifo.r_rdy & ~imc.o_stall)
        ]

        # Calculate fifo co-ordinates
        m.d.sync += f_frame_done.eq(0)

        with m.If(fifo.r_en & sync_fifo):
            m.d.sync += f_x.eq(f_x + 1)
            with m.If(f_x == x_res - 1):
                m.d.sync += [
                    f_x.eq(0),
                    f_y.eq(f_y + 1)
                ]
                with m.If(f_y == y_res - 1):
                    m.d.sync += [
                        f_y.eq(0),
                        f_frame_done.eq(1)
                    ]
        
        # Extract pixel from fifo data
        m.d.comb += [
            pix.r.eq(fifo.r_data[11:]),
            pix.g.eq(fifo.r_data[5:11]),
            pix.b.eq(fifo.r_data[:5])
        ]

        # Connect color control
        m.d.comb += [
            cc.i.eq(pix),
            cc.i_cc.eq(ccc)
        ]

        # Calculate per-frame statistics, after applying color correction
        m.d.comb += [
            stats.i.eq(cc.o),
            stats.i_valid.eq(fifo.r_rdy),
            # This is not valid when a region of interest is active
            stats.i_avg_valid.eq((f_x >= 32) & (f_x < 288) &
                                 (f_y >= 112) & (f_y < 368)),
            stats.i_frame_done.eq(f_frame_done),
            stats.i_x.eq(f_x),
            stats.i_y.eq(f_y),
            stats.i_roi.eq(roi)
        ]
        
        # Produce histogram, after applying color correction, and after monochrome, for monochrome histogram
        with m.Switch(hist_chan):
            with m.Case(0):
                m.d.comb += hist.i_p.eq(cc.o.r)
            with m.Case(1):
                m.d.comb += hist.i_p.eq(cc.o.g)
            with m.Case(2):
                m.d.comb += hist.i_p.eq(cc.o.b)
            with m.Case(3):
                m.d.comb += hist.i_p.eq(mon.o_m)

        m.d.comb += [
            hist.i_valid.eq(fifo.r_rdy),
            hist.i_clear.eq(f_frame_done),
            hist.i_x.eq(f_x),
            hist.i_y.eq(f_y),
            hist.i_roi.eq(roi),
            hist.i_bin.eq(hbin) # Used when displaying histogram
        ]

        # Apply filter, after color correction
        m.d.comb += [
            fil.i.eq(cc.o),
            fil.i_valid.eq(fifo.r_en),
            fil.i_en.eq(filt),
            fil.i_frame_done.eq(f_frame_done),
            fil.i_l.eq(l),
            fil.i_h.eq(h)
        ]

        # Apply mono, after color correction and filter
        m.d.comb += [
            mon.i.eq(fil.o),
            mon.i_en.eq(mono),
            mon.i_invert.eq(invert),
            mon.i_thresh.eq(thresh),
            mon.i_threshold.eq(threshold)
        ]

        # Apply image convolution, after other transformations
        m.d.comb += [
            imc.i.eq(mon.o),
            imc.i_valid.eq(fifo.r_rdy),
            imc.i_reset.eq(~sync_fifo),
            # Select image convolution
            imc.i_sel.eq(sharpness)
        ]

        # Take a snapshot, freeze the camera, and write the framebuffer to the uart
        # Note that this suspends video output
        with m.If(debsnap.btn_down | (spimem.wr & (spimem.addr == 22))):
            with m.If(frozen):
                m.d.sync += frozen.eq(0)
            with m.Else():
                m.d.sync += [
                    snap.eq(1),
                    frozen.eq(0),
                    w_addr.eq(0),
                    written.eq(0),
                    byte.eq(0)
                ]

        # Wait to end of frame after requesting snapshot, before start of writing to uart
        with m.If(imc.o_frame_done & snap):
            m.d.sync += [
                frozen.eq(1),
                snap.eq(0)
            ]
            with m.If(~written):
                m.d.sync += writing.eq(1)

        # Connect the uart
        m.d.comb += [
            serial.tx.data.eq(Mux(byte, r.data[8:], r.data[:8])),
            serial.tx.ack.eq(writing)
        ]

        # Write to the uart from frame buffer (affects video output)
        with m.If(writing):
            with m.If(w_addr == x_res * y_res):
                m.d.sync += [
                    writing.eq(0),
                    written.eq(1)
                ]
            with m.Elif(serial.tx.ack & serial.tx.rdy):
                m.d.sync += byte.eq(~byte)
                with m.If(byte):
                    m.d.sync += w_addr.eq(w_addr+1)

        # Connect spimem
        m.d.comb += [
            spimem.csn.eq(~csn),
            spimem.sclk.eq(sclk),
            spimem.copi.eq(copi),
            cipo.eq(spimem.cipo),
        ]

        # Writable configuration registers
        spi_wr_vals = Array([ccc.brightness, ccc.redness, ccc.greenness, ccc.blueness, l.r, h.r, l.g, h.g, l.b, h.b,
                             sharpness, filt, border, mono, invert, grid, histo,
                             roi.x[1:], roi.y[1:], roi.w[1:], roi.h[1:], roi.en, None, None, None,
                             threshold, thresh, hist_chan, flip,
                             None, None, None, None, None, None, None, None, None,
                             frozen])

        with m.If(spimem.wr):
            with m.Switch(spimem.addr):
                for i in range(len(spi_wr_vals)):
                    if spi_wr_vals[i] is not None:
                        with m.Case(i):
                            m.d.sync += spi_wr_vals[i].eq(spimem.dout)

        # Readable configuration registers
        spi_rd_vals = Array([ccc.brightness, ccc.redness, ccc.greenness, ccc.blueness, l.r, h.r, l.g, h.g, l.b, h.b,
                             sharpness, filt, border, mono, invert, grid, histo,
                             roi.x[1:], roi.y[1:], roi.w[1:], roi.h[1:], roi.en, fil.o_nz[16:], fil.o_nz[8:16], fil.o_nz[:8],
                             threshold, thresh, hist_chan, flip,
                             stats.o_min.r, stats.o_min.g, stats.o_min.b,
                             stats.o_max.r, stats.o_max.g, stats.o_max.b,
                             stats.o_avg.r, stats.o_avg.g, stats.o_avg.b,
                             frozen, writing, written])

        with m.If(spimem.rd):
            with m.Switch(spimem.addr):
                for i in range(len(spi_rd_vals)):
                    with m.Case(i):
                        m.d.sync += spimem.din.eq(spi_rd_vals[i])

        # Add VGA generator
        m.submodules.vga = vga = VGA(
           resolution_x      = self.timing.x,
           hsync_front_porch = hsync_front_porch,
           hsync_pulse       = hsync_pulse_width,
           hsync_back_porch  = hsync_back_porch,
           resolution_y      = self.timing.y,
           vsync_front_porch = vsync_front_porch,
           vsync_pulse       = vsync_pulse_width,
           vsync_back_porch  = vsync_back_porch,
           bits_x            = 16, # Play around with the sizes because sometimes
           bits_y            = 16  # a smaller/larger value will make it pass timing.
        )

        # Fetch histogram for display
        old_x = Signal(10)
        m.d.sync += old_x.eq(vga.o_beam_x)

        with m.If(vga.o_beam_x == 0):
            m.d.sync += [
                hbin.eq(0),
                bin_cnt.eq(0)
            ]
        with m.Elif(vga.o_beam_x != old_x):
            m.d.sync += bin_cnt.eq(bin_cnt+1)
            with m.If(bin_cnt == 19):
                m.d.sync += [
                    bin_cnt.eq(0),
                    hbin.eq(hbin+1)
                ]

        # Switch between camera and histogram view
        with m.If(debhist.btn_down):
            m.d.sync += histo.eq(~histo)
       
        # Connect frame buffer, with optional x and y flip
        x = Signal(10)
        y = Signal(9)
        
        m.d.comb += [
            w.en.eq(imc.o_valid & ~frozen),
            w.addr.eq(imc.o_y * x_res + imc.o_x),
            w.data.eq(Cat(imc.o.b, imc.o.g, imc.o.r)),
            y.eq(Mux(flip[1], y_res - 1 - vga.o_beam_y, vga.o_beam_y)),
            x.eq(Mux(flip[0], x_res - 1 - vga.o_beam_x[1:], vga.o_beam_x[1:])),
            r.addr.eq(Mux(writing, w_addr, y * x_res + x))
        ]

        # Apply the On-Screen Display (OSD)
        m.submodules.osd = osd = OSD()

        hist_col = Signal(8)

        m.d.comb += [
            osd.x.eq(vga.o_beam_x),
            osd.y.eq(vga.o_beam_y),
            hist_col.eq(Mux((479 - osd.y) < hist.o_val[8:], 0xff, 0x00)),
            osd.i_r.eq(Mux(histo, Mux((hist_chan == 0) | (hist_chan == 3), hist_col, 0), Cat(Const(0, unsigned(3)), r.data[11:16]))),
            osd.i_g.eq(Mux(histo, Mux((hist_chan == 1) | (hist_chan == 3), hist_col, 0), Cat(Const(0, unsigned(2)), r.data[5:11]))),
            osd.i_b.eq(Mux(histo, Mux((hist_chan == 2) | (hist_chan == 3), hist_col, 0), Cat(Const(0, unsigned(3)), r.data[0:5]))),
            osd.on.eq(osd_on),
            osd.osd_val.eq(osd_val),
            osd.sel.eq(osd_sel),
            osd.grid.eq(grid),
            osd.border.eq(border),
            osd.roi.eq(roi.en & ~histo),
            osd.roi_x.eq(roi.x),
            osd.roi_y.eq(roi.y),
            osd.roi_w.eq(roi.w),
            osd.roi_h.eq(roi.h)
        ]

        # OSD control
        osd_vals = Array([ccc.brightness, ccc.redness, ccc.greenness, ccc.blueness, mono, flip[0], flip[1],
                          border, sharpness, invert, grid, filt])

        with m.If(debosd.btn_down):
            m.d.sync += osd_on.eq(~osd_on)

        with m.If(osd_on):
            with m.If(debsel.btn_down):
                m.d.sync += osd_sel.eq(~osd_sel)

            with m.If(debup.btn_down):
                with m.If(~osd_sel):
                    m.d.sync += osd_val.eq(Mux(osd_val == 0, 11, osd_val-1))
                with m.Else():
                    with m.Switch(osd_val):
                        for i in range(len(osd_vals)):
                            with m.Case(i):
                                if (len(osd_vals[i]) == 1):
                                    m.d.sync += osd_vals[i].eq(1)
                                else:
                                    m.d.sync += osd_vals[i].eq(osd_vals[i]+1)

            with m.If(debdown.btn_down):
                with m.If(~osd_sel):
                    m.d.sync += osd_val.eq(Mux(osd_val == 11, 0, osd_val+1))
                with m.Else():
                    with m.Switch(osd_val):
                        for i in range(len(osd_vals)):
                            with m.Case(i):
                                if (len(osd_vals[i]) == 1):
                                    m.d.sync += osd_vals[i].eq(0)
                                else:
                                    m.d.sync += osd_vals[i].eq(osd_vals[i]-1)

        # Show configuration values on leds
        with m.Switch(osd_val):
            for i in range(len(osd_vals)):
                with m.Case(i):
                    m.d.comb += leds.eq(osd_vals[i])

        # Generate VGA signals
        m.d.comb += [
            vga.i_clk_en.eq(1),
            vga.i_test_picture.eq(0),
            vga.i_r.eq(osd.o_r), 
            vga.i_g.eq(osd.o_g), 
            vga.i_b.eq(osd.o_b), 
            vga_r.eq(vga.o_vga_r),
            vga_g.eq(vga.o_vga_g),
            vga_b.eq(vga.o_vga_b),
            vga_hsync.eq(vga.o_vga_hsync),
            vga_vsync.eq(vga.o_vga_vsync),
            vga_blank.eq(vga.o_vga_blank),
        ]

        # VGA to digital video converter.
        tmds = [Signal(2) for i in range(4)]
        m.submodules.vga2dvid = vga2dvid = VGA2DVID(ddr=self.ddr, shift_clock_synchronizer=False)
        m.d.comb += [
            vga2dvid.i_red.eq(vga_r),
            vga2dvid.i_green.eq(vga_g),
            vga2dvid.i_blue.eq(vga_b),
            vga2dvid.i_hsync.eq(vga_hsync),
            vga2dvid.i_vsync.eq(vga_vsync),
            vga2dvid.i_blank.eq(vga_blank),
            tmds[3].eq(vga2dvid.o_clk),
            tmds[2].eq(vga2dvid.o_red),
            tmds[1].eq(vga2dvid.o_green),
            tmds[0].eq(vga2dvid.o_blue),
        ]

        # GPDI pins
        if (self.ddr):
            # Vendor specific DDR modules.
            # Convert SDR 2-bit input to DDR clocked 1-bit output (single-ended)
            # onboard GPDI.
            m.submodules.ddr0_clock = Instance("ODDRX1F",
                i_SCLK = ClockSignal("shift"),
                i_RST  = 0b0,
                i_D0   = tmds[3][0],
                i_D1   = tmds[3][1],
                o_Q    = self.o_gpdi_dp[3])
            m.submodules.ddr0_red   = Instance("ODDRX1F",
                i_SCLK = ClockSignal("shift"),
                i_RST  = 0b0,
                i_D0   = tmds[2][0],
                i_D1   = tmds[2][1],
                o_Q    = self.o_gpdi_dp[2])
            m.submodules.ddr0_green = Instance("ODDRX1F",
                i_SCLK = ClockSignal("shift"),
                i_RST  = 0b0,
                i_D0   = tmds[1][0],
                i_D1   = tmds[1][1],
                o_Q    = self.o_gpdi_dp[1])
            m.submodules.ddr0_blue  = Instance("ODDRX1F",
                i_SCLK = ClockSignal("shift"),
                i_RST  = 0b0,
                i_D0   = tmds[0][0],
                i_D1   = tmds[0][1],
                o_Q    = self.o_gpdi_dp[0])
        else:
            m.d.comb += [
                self.o_gpdi_dp[3].eq(tmds[3][0]),
                self.o_gpdi_dp[2].eq(tmds[2][0]),
                self.o_gpdi_dp[1].eq(tmds[1][0]),
                self.o_gpdi_dp[0].eq(tmds[0][0]),
            ]

        return m