def elaborate(self, platform): m = Module() board_spi = platform.request("debug_spi") # Create a set of registers, and expose them over SPI. spi_registers = SPIRegisterInterface( default_read_value=0x4C554E41) #default read = u'LUNA' m.submodules.spi_registers = spi_registers # Fill in some example registers. # (Register 0 is reserved for size autonegotiation). spi_registers.add_read_only_register(1, read=0xc001cafe) led_reg = spi_registers.add_register(2, size=6, name="leds") spi_registers.add_read_only_register(3, read=0xdeadbeef) # ... and tie our LED register to our LEDs. led_out = Cat( [platform.request("led", i, dir="o") for i in range(0, 6)]) m.d.comb += led_out.eq(led_reg) # Connect up our synchronized copies of the SPI registers. spi = synchronize(m, board_spi) m.d.comb += spi_registers.spi.connect(spi) return m
def elaborate(self, platform): m = Module() m.submodules += self.ila # Grab a reference to our debug-SPI bus. board_spi = synchronize(m, platform.request("debug_spi")) # Clock divider / counter. m.d.sync += self.counter.eq(self.counter + 1) # Another example signal, for variety. m.d.sync += self.toggle.eq(~self.toggle) # Create an SPI bus for our ILA. ila_spi = SPIBus() m.d.comb += [ self.ila.spi .connect(ila_spi), # For sharing, we'll connect the _inverse_ of the primary # chip select to our ILA bus. This will allow us to send # ILA data when CS is un-asserted, and register data when # CS is asserted. ila_spi.cs .eq(~board_spi.cs) ] # Create a set of registers... spi_registers = SPIRegisterInterface() m.submodules.spi_registers = spi_registers # ... and an SPI bus for them. reg_spi = SPIBus() m.d.comb += [ spi_registers.spi .connect(reg_spi), reg_spi.cs .eq(board_spi.cs) ] # Multiplex our ILA and register SPI busses. m.submodules.mux = SPIMultiplexer([ila_spi, reg_spi]) m.d.comb += m.submodules.mux.shared_lines.connect(board_spi) # Add a simple ID register to demonstrate our registers. spi_registers.add_read_only_register(REGISTER_ID, read=0xDEADBEEF) # Create a simple SFR that will trigger an ILA capture when written, # and which will display our sample status read. spi_registers.add_sfr(REGISTER_ILA, read=self.ila.complete, write_strobe=self.ila.trigger ) # Attach the LEDs and User I/O to the MSBs of our counter. leds = [platform.request("led", i, dir="o") for i in range(0, 6)] m.d.comb += Cat(leds).eq(self.counter[-7:-1]) # Return our elaborated module. return m
def elaborate(self, platform): m = Module() # Generate our clock domains. clocking = LunaECP5DomainGenerator() m.submodules.clocking = clocking # Grab a reference to our debug-SPI bus. board_spi = synchronize(m, platform.request("debug_spi")) # Create our SPI-connected registers. m.submodules.spi_registers = spi_registers = SPIRegisterInterface( 7, 32) m.d.comb += spi_registers.spi.connect(board_spi) # Create our UMTI translator. ulpi = platform.request("sideband_phy") m.submodules.umti = umti = UMTITranslator(ulpi=ulpi) # Strap our power controls to be in VBUS passthrough by default, # on the target port. m.d.comb += [ platform.request("power_a_port").eq(0), platform.request("pass_through_vbus").eq(1), ] # Hook up our LEDs to status signals. m.d.comb += [ platform.request("led", 0).eq(umti.vbus_valid), platform.request("led", 1).eq(umti.session_valid), platform.request("led", 2).eq(umti.session_end), platform.request("led", 3).eq(umti.rx_active), platform.request("led", 4).eq(umti.rx_error) ] spi_registers.add_read_only_register(1, read=umti.last_rx_command) # For debugging: mirror some ULPI signals on the UIO. user_io = Cat( platform.request("user_io", i, dir="o") for i in range(0, 4)) m.d.comb += [ user_io[0].eq(ClockSignal("ulpi")), user_io[1].eq(ulpi.dir), user_io[2].eq(ulpi.nxt), user_io[3].eq(ulpi.stp), ] # Return our elaborated module. return m
def elaborate(self, platform): m = Module() # Create a set of registers, and expose them over SPI. board_spi = platform.request("debug_spi") spi_registers = SPIRegisterInterface(default_read_value=-1) m.submodules.spi_registers = spi_registers # Identify ourselves as the SPI flash bridge. spi_registers.add_read_only_register(REGISTER_ID, read=0x53504946) # # SPI flash passthrough connections. # flash_sdo = Signal() spi_flash_bus = platform.request('spi_flash') spi_flash_passthrough = ECP5ConfigurationFlashInterface( bus=spi_flash_bus) m.submodules += spi_flash_passthrough m.d.comb += [ spi_flash_passthrough.sck.eq(board_spi.sck), spi_flash_passthrough.sdi.eq(board_spi.sdi), flash_sdo.eq(spi_flash_passthrough.sdo), ] # # Structural connections. # spi = synchronize(m, board_spi) # Select the passthrough or gateware SPI based on our chip-select values. gateware_sdo = Signal() with m.If(board_spi.cs): m.d.comb += board_spi.sdo.eq(gateware_sdo) with m.Else(): m.d.comb += board_spi.sdo.eq(flash_sdo) # Connect our register interface to our board SPI. m.d.comb += [ spi_registers.spi.sck.eq(spi.sck), spi_registers.spi.sdi.eq(spi.sdi), gateware_sdo.eq(spi_registers.spi.sdo), spi_registers.spi.cs.eq(spi.cs) ] return m
def elaborate(self, platform): m = Module() board_spi = platform.request("debug_spi") # Create a set of registers, and expose them over SPI. spi_registers = SPIRegisterInterface( default_read_value=0x4C554E41) #default read = u'LUNA' m.submodules.spi_registers = spi_registers # Fill in some example registers. # (Register 0 is reserved for size autonegotiation). spi_registers.add_read_only_register(1, read=0xc001cafe) led_reg = spi_registers.add_register(2, size=6, name="leds") spi_registers.add_read_only_register(3, read=0xdeadbeef) # ... and tie our LED register to our LEDs. led_out = Cat( [platform.request("led", i, dir="o") for i in range(0, 6)]) m.d.comb += led_out.eq(led_reg) # # Structural connections. # sck = Signal() sdi = Signal() sdo = Signal() cs = Signal() # # Synchronize each of our I/O SPI signals, where necessary. # m.submodules += FFSynchronizer(board_spi.sck, sck) m.submodules += FFSynchronizer(board_spi.sdi, sdi) m.submodules += FFSynchronizer(board_spi.cs, cs) m.d.comb += board_spi.sdo.eq(sdo) # Connect our register interface to our board SPI. m.d.comb += [ spi_registers.sck.eq(sck), spi_registers.sdi.eq(sdi), sdo.eq(spi_registers.sdo), spi_registers.cs.eq(cs) ] return m
def elaborate(self, platform): m = Module() # Generate our clock domains. clocking = LunaECP5DomainGenerator() m.submodules.clocking = clocking # Grab a reference to our debug-SPI bus. board_spi = synchronize(m, platform.request("debug_spi")) # Create a set of registers... spi_registers = SPIRegisterInterface(7, 32) m.submodules.spi_registers = spi_registers m.d.comb += spi_registers.spi.connect(board_spi) # # HyperRAM test connections. # ram_bus = platform.request('ram') psram = HyperRAMInterface(bus=ram_bus, **platform.ram_timings) m.submodules += psram psram_address_changed = Signal() psram_address = spi_registers.add_register( REGISTER_RAM_REG_ADDR, write_strobe=psram_address_changed) spi_registers.add_sfr(REGISTER_RAM_VALUE, read=psram.read_data) # Hook up our PSRAM. m.d.comb += [ ram_bus.reset.eq(0), psram.single_page.eq(0), psram.perform_write.eq(0), psram.register_space.eq(1), psram.final_word.eq(1), psram.start_transfer.eq(psram_address_changed), psram.address.eq(psram_address), ] # Return our elaborated module. return m
def elaborate(self, platform): m = Module() # Generate our clock domains. clocking = LunaECP5DomainGenerator(clock_frequencies=CLOCK_FREQUENCIES) m.submodules.clocking = clocking # Create a set of registers, and expose them over SPI. board_spi = platform.request("debug_spi") spi_registers = SPIRegisterInterface(default_read_value=-1) m.submodules.spi_registers = spi_registers # Simple applet ID register. spi_registers.add_read_only_register(REGISTER_ID, read=0x54455354) # LED test register. led_reg = spi_registers.add_register(REGISTER_LEDS, size=6, name="leds", reset=0b10) led_out = Cat([platform.request("led", i, dir="o") for i in range(0, 6)]) m.d.comb += led_out.eq(led_reg) # # Target power test register. # Note: these values assume you've populated the correct AP22814 for # your revision (AP22814As for rev0.2+, and AP22814Bs for rev0.1). # bits [1:0]: 0 = power off # 1 = provide A-port VBUS # 2 = pass through target VBUS # power_test_reg = Signal(3) power_test_write_strobe = Signal() power_test_write_value = Signal(2) spi_registers.add_sfr(REGISTER_TARGET_POWER, read=power_test_reg, write_strobe=power_test_write_strobe, write_signal=power_test_write_value ) # Store the values for our enable bits. with m.If(power_test_write_strobe): m.d.sync += power_test_reg[0:2].eq(power_test_write_value) # Decode the enable bits and control the two power supplies. power_a_port = platform.request("power_a_port") power_passthrough = platform.request("pass_through_vbus") with m.If(power_test_reg[0:2] == 1): m.d.comb += [ power_a_port .eq(1), power_passthrough .eq(0) ] with m.Elif(power_test_reg[0:2] == 2): m.d.comb += [ power_a_port .eq(0), power_passthrough .eq(1) ] with m.Else(): m.d.comb += [ power_a_port .eq(0), power_passthrough .eq(0) ] # # User IO GPIO registers. # # Data direction register. user_io_dir = spi_registers.add_register(REGISTER_USER_IO_DIR, size=4) # Pin (input) state register. user_io_in = Signal(4) spi_registers.add_sfr(REGISTER_USER_IO_IN, read=user_io_in) # Output value register. user_io_out = spi_registers.add_register(REGISTER_USER_IO_OUT, size=4) # Grab and connect each of our user-I/O ports our GPIO registers. for i in range(4): pin = platform.request("user_io", i) m.d.comb += [ pin.oe .eq(user_io_dir[i]), user_io_in[i] .eq(pin.i), pin.o .eq(user_io_out[i]) ] # # ULPI PHY windows # self.add_ulpi_registers(m, platform, ulpi_bus="target_phy", register_base=REGISTER_TARGET_ADDR ) self.add_ulpi_registers(m, platform, ulpi_bus="host_phy", register_base=REGISTER_HOST_ADDR ) self.add_ulpi_registers(m, platform, ulpi_bus="sideband_phy", register_base=REGISTER_SIDEBAND_ADDR ) # # HyperRAM test connections. # ram_bus = platform.request('ram') psram = HyperRAMInterface(bus=ram_bus) m.submodules += psram psram_address_changed = Signal() psram_address = spi_registers.add_register(REGISTER_RAM_REG_ADDR, write_strobe=psram_address_changed) spi_registers.add_sfr(REGISTER_RAM_VALUE, read=psram.read_data) # Hook up our PSRAM. m.d.comb += [ ram_bus.reset .eq(0), psram.single_page .eq(0), psram.perform_write .eq(0), psram.register_space .eq(1), psram.final_word .eq(1), psram.start_transfer .eq(psram_address_changed), psram.address .eq(psram_address), ] # # SPI flash passthrough connections. # flash_sdo = Signal() spi_flash_bus = platform.request('spi_flash') spi_flash_passthrough = ECP5ConfigurationFlashInterface(bus=spi_flash_bus) m.submodules += spi_flash_passthrough m.d.comb += [ spi_flash_passthrough.sck .eq(board_spi.sck), spi_flash_passthrough.sdi .eq(board_spi.sdi), flash_sdo .eq(spi_flash_passthrough.sdo), ] # # Synchronize each of our I/O SPI signals, where necessary. # spi = synchronize(m, board_spi) # Select the passthrough or gateware SPI based on our chip-select values. gateware_sdo = Signal() with m.If(spi_registers.spi.cs): m.d.comb += board_spi.sdo.eq(gateware_sdo) with m.Else(): m.d.comb += board_spi.sdo.eq(flash_sdo) # Connect our register interface to our board SPI. m.d.comb += [ spi_registers.spi.sck .eq(spi.sck), spi_registers.spi.sdi .eq(spi.sdi), gateware_sdo .eq(spi_registers.spi.sdo), spi_registers.spi.cs .eq(spi.cs) ] return m
def elaborate(self, platform): m = Module() # Generate our clock domains. clocking = LunaECP5DomainGenerator() m.submodules.clocking = clocking # Grab a reference to our debug-SPI bus. board_spi = synchronize(m, platform.request("debug_spi")) # Create our SPI-connected registers. m.submodules.spi_registers = spi_registers = SPIRegisterInterface(7, 8) m.d.comb += spi_registers.spi.connect(board_spi) # Create our UMTI translator. ulpi = platform.request("target_phy") m.submodules.umti = umti = UMTITranslator(ulpi=ulpi) # Strap our power controls to be in VBUS passthrough by default, # on the target port. m.d.comb += [ platform.request("power_a_port").eq(0), platform.request("pass_through_vbus").eq(1), ] # Set up our parameters. m.d.comb += [ # Set our mode to non-driving and to the desired speed. umti.op_mode.eq(0b01), umti.xcvr_select.eq(self.usb_speed), # Disable all of our terminations, as we want to participate in # passive observation. umti.dm_pulldown.eq(0), umti.dm_pulldown.eq(0), umti.term_select.eq(0) ] read_strobe = Signal() # Create a USB analyzer, and connect a register up to its output. m.submodules.analyzer = analyzer = USBAnalyzer(umti_interface=umti) # Provide registers that indicate when there's data ready, and what the result is. spi_registers.add_read_only_register(DATA_AVAILABLE, read=analyzer.data_available) spi_registers.add_read_only_register(ANALYZER_RESULT, read=analyzer.data_out, read_strobe=read_strobe) m.d.comb += [ # Internal connections. analyzer.next.eq(read_strobe), # LED indicators. platform.request("led", 0).eq(analyzer.capturing), platform.request("led", 1).eq(analyzer.data_available), platform.request("led", 2).eq(analyzer.overrun), platform.request("led", 3).eq(umti.session_valid), platform.request("led", 4).eq(umti.rx_active), platform.request("led", 5).eq(umti.rx_error), ] # Return our elaborated module. return m
def elaborate(self, platform): m = Module() # Generate our clock domains. clocking = LunaECP5DomainGenerator(clock_frequencies=CLOCK_FREQUENCIES) m.submodules.clocking = clocking # Create a set of registers, and expose them over SPI. board_spi = platform.request("debug_spi") spi_registers = SPIRegisterInterface(default_read_value=-1) m.submodules.spi_registers = spi_registers # Simple applet ID register. spi_registers.add_read_only_register(REGISTER_ID, read=0x54455354) # LED test register. led_reg = spi_registers.add_register(REGISTER_LEDS, size=5, name="leds", reset=0b1) led_out = Cat( [platform.request("led", i, dir="o") for i in range(0, 6)]) m.d.comb += led_out[1:].eq(led_reg) # # User IO GPIO registers. # # Data direction register. user_io_dir = spi_registers.add_register(REGISTER_USER_IO_DIR, size=4) # Pin (input) state register. user_io_in = Signal(4) spi_registers.add_sfr(REGISTER_USER_IO_IN, read=user_io_in) # Output value register. user_io_out = spi_registers.add_register(REGISTER_USER_IO_OUT, size=4) # Grab and connect each of our user-I/O ports our GPIO registers. for i in range(4): pin = platform.request("user_io", i) m.d.comb += [ pin.oe.eq(user_io_dir[i]), user_io_in[i].eq(pin.i), pin.o.eq(user_io_out[i]) ] # # ULPI PHY windows # self.add_ulpi_registers(m, platform, ulpi_bus="host_phy", register_base=REGISTER_HOST_ADDR) self.add_ulpi_registers(m, platform, ulpi_bus="sideband_phy", register_base=REGISTER_SIDEBAND_ADDR) # # HyperRAM test connections. # ram_bus = platform.request('ram') psram = HyperRAMInterface(bus=ram_bus) m.submodules += psram psram_address_changed = Signal() psram_address = spi_registers.add_register( REGISTER_RAM_REG_ADDR, write_strobe=psram_address_changed) spi_registers.add_sfr(REGISTER_RAM_VALUE, read=psram.read_data) # Hook up our PSRAM. m.d.comb += [ ram_bus.reset.eq(0), psram.single_page.eq(0), psram.perform_write.eq(0), psram.register_space.eq(1), psram.final_word.eq(1), psram.start_transfer.eq(psram_address_changed), psram.address.eq(psram_address), ] # # SPI flash passthrough connections. # flash_sdo = Signal() spi_flash_bus = platform.request('spi_flash') spi_flash_passthrough = ECP5ConfigurationFlashInterface( bus=spi_flash_bus) m.submodules += spi_flash_passthrough m.d.comb += [ spi_flash_passthrough.sck.eq(board_spi.sck), spi_flash_passthrough.sdi.eq(board_spi.sdi), flash_sdo.eq(spi_flash_passthrough.sdo), ] # # Synchronize each of our I/O SPI signals, where necessary. # spi = synchronize(m, board_spi) # Select the passthrough or gateware SPI based on our chip-select values. gateware_sdo = Signal() with m.If(spi_registers.spi.cs): m.d.comb += board_spi.sdo.eq(gateware_sdo) with m.Else(): m.d.comb += board_spi.sdo.eq(flash_sdo) # Connect our register interface to our board SPI. m.d.comb += [ spi_registers.spi.sck.eq(spi.sck), spi_registers.spi.sdi.eq(spi.sdi), gateware_sdo.eq(spi_registers.spi.sdo), spi_registers.spi.cs.eq(spi.cs) ] # Radio SPI window radio = platform.request("radio") radio_spi = RadioSPI(clk_freq=CLOCK_FREQUENCIES["sync"] * 1e6) m.submodules += radio_spi radio_address_changed = Signal() radio_address = spi_registers.add_register( REGISTER_RADIO_ADDR, write_strobe=radio_address_changed) radio_value_changed = Signal() spi_registers.add_sfr( REGISTER_RADIO_VALUE, read=radio_spi.read_value, write_signal=radio_spi.write_value, write_strobe=radio_value_changed, ) # Hook up our radio. m.d.comb += [ radio.rst.eq(0), # SPI outputs radio.sel.eq(radio_spi.sel), radio.sclk.eq(radio_spi.sclk), radio.mosi.eq(radio_spi.mosi), # SPI inputs radio_spi.miso.eq(radio.miso), radio_spi.write.eq(radio_value_changed), radio_spi.start.eq(radio_address_changed | radio_value_changed), radio_spi.address.eq(radio_address), ] # Radio LVDS loop-back # Set up radio clock domain from rxclk, and pass it through to txclk m.domains.radio = ClockDomain() m.d.comb += [ ClockSignal("radio").eq(radio.rxclk), ResetSignal("radio").eq(ResetSignal()), radio.txclk.eq(ClockSignal("radio")), ] # TX a pattern tx = Signal(8, reset=0x2e) m.d.radio += [ tx.eq(Cat(tx[7], tx[:-1])), radio.txd.eq(tx[7]), ] # ... and receive it back. rx = Signal(8) rx_counter = Signal(range(8)) m.d.radio += rx.eq(Cat(radio.rxd09, rx[:-1])) m.d.radio += rx_counter.eq(rx_counter - 1) # Sync up to the pattern got_sync = Signal() with m.FSM() as fsm: with m.State("start"): with m.If(rx == 0x2e): m.next = "sync" m.d.radio += got_sync.eq(1) m.d.radio += rx_counter.eq(7) with m.State("sync"): with m.If(rx_counter == 0): with m.If(rx != 0x2e): m.next = "start" m.d.radio += got_sync.eq(0) with m.State("error"): pass got_sync_reg = Signal() m.submodules += FFSynchronizer(got_sync, got_sync_reg) spi_registers.add_read_only_register(REGISTER_RADIO_SYNC, read=got_sync_reg) m.d.comb += led_out[0].eq(got_sync) return m
def elaborate(self, platform): m = Module() # Generate our clock domains. clocking = LunaECP5DomainGenerator() m.submodules.clocking = clocking # Grab a reference to our debug-SPI bus. board_spi = synchronize(m, platform.request("debug_spi").i) # Create our SPI-connected registers. m.submodules.spi_registers = spi_registers = SPIRegisterInterface(7, 8) m.d.comb += spi_registers.spi.connect(board_spi) # Create our UTMI translator. ulpi = platform.request(platform.default_usb_connection) m.submodules.utmi = utmi = UTMITranslator(ulpi=ulpi) # Strap our power controls to be in VBUS passthrough by default, # on the target port. m.d.comb += [ platform.request("power_a_port").o.eq(0), platform.request("pass_through_vbus").o.eq(1), ] # Hook up our LEDs to status signals. m.d.comb += [ platform.request("led", 2).o.eq(utmi.session_valid), platform.request("led", 3).o.eq(utmi.rx_active), platform.request("led", 4).o.eq(utmi.rx_error) ] # Set up our parameters. m.d.comb += [ # Set our mode to non-driving and full speed. utmi.op_mode.eq(0b01), utmi.xcvr_select.eq(0b01), # Disable the DP/DM pull resistors. utmi.dm_pulldown.eq(0), utmi.dm_pulldown.eq(0), utmi.term_select.eq(0) ] read_strobe = Signal() # Create a USB analyzer, and connect a register up to its output. m.submodules.analyzer = analyzer = USBAnalyzer(utmi_interface=utmi) # Provide registers that indicate when there's data ready, and what the result is. spi_registers.add_read_only_register(DATA_AVAILABLE, read=analyzer.data_available) spi_registers.add_read_only_register(ANALYZER_RESULT, read=analyzer.data_out, read_strobe=read_strobe) m.d.comb += [ platform.request("led", 0).o.eq(analyzer.capturing), platform.request("led", 1).o.eq(analyzer.data_available), platform.request("led", 5).o.eq(analyzer.overrun), analyzer.next.eq(read_strobe) ] # Debug output. m.d.comb += [ platform.request("user_io", 0, dir="o").eq(ClockSignal("usb")), platform.request("user_io", 1, dir="o").eq(ulpi.dir), platform.request("user_io", 2, dir="o").eq(ulpi.nxt), platform.request("user_io", 3, dir="o").eq(analyzer.sampling), ] # Return our elaborated module. return m
def elaborate(self, platform): m = Module() clk_60MHz = platform.request(platform.default_clk) # Drive the sync clock domain with our main clock. m.domains.sync = ClockDomain() m.d.comb += ClockSignal().eq(clk_60MHz) # Create a set of registers, and expose them over SPI. board_spi = platform.request("debug_spi") spi_registers = SPIRegisterInterface(default_read_value=-1) m.submodules.spi_registers = spi_registers # Simple applet ID register. spi_registers.add_read_only_register(REGISTER_ID, read=0x54455354) # LED test register. led_reg = spi_registers.add_register(REGISTER_LEDS, size=6, name="leds", reset=0b10) led_out = Cat( [platform.request("led", i, dir="o") for i in range(0, 6)]) m.d.comb += led_out.eq(led_reg) # # Target power test register. # Note: these values assume you've populated the correct AP22814 for # your revision (AP22814As for rev0.2+, and AP22814Bs for rev0.1). # bits [1:0]: 0 = power off # 1 = provide A-port VBUS # 2 = pass through target VBUS # power_test_reg = Signal(3) power_test_write_strobe = Signal() power_test_write_value = Signal(2) spi_registers.add_sfr(REGISTER_TARGET_POWER, read=power_test_reg, write_strobe=power_test_write_strobe, write_signal=power_test_write_value) # Store the values for our enable bits. with m.If(power_test_write_strobe): m.d.sync += power_test_reg[0:2].eq(power_test_write_value) # Decode the enable bits and control the two power supplies. power_a_port = platform.request("power_a_port") power_passthrough = platform.request("pass_through_vbus") with m.If(power_test_reg[0:2] == 1): m.d.comb += [power_a_port.eq(1), power_passthrough.eq(0)] with m.Elif(power_test_reg[0:2] == 2): m.d.comb += [power_a_port.eq(0), power_passthrough.eq(1)] with m.Else(): m.d.comb += [power_a_port.eq(0), power_passthrough.eq(0)] # # User IO GPIO registers. # # Data direction register. user_io_ddr = spi_registers.add_register(REGISTER_USER_IO_DIR, size=4) # Pin (input) state register. user_io_in = Signal(4) spi_registers.add_sfr(REGISTER_USER_IO_IN, read=user_io_in) # Output value register. user_io_out = spi_registers.add_register(REGISTER_USER_IO_OUT, size=4) # Grab and connect each of our user-I/O ports our GPIO registers. for i in range(4): pin = platform.request("user_io", i) m.d.comb += [ pin.oe.eq(user_io_ddr[i]), user_io_in[i].eq(pin.i), pin.o.eq(user_io_out[i]) ] # # ULPI PHY windows # self.add_ulpi_registers(m, platform, clock=clk_60MHz, ulpi_bus="target_phy", register_base=REGISTER_TARGET_ADDR) self.add_ulpi_registers(m, platform, clock=clk_60MHz, ulpi_bus="host_phy", register_base=REGISTER_HOST_ADDR) self.add_ulpi_registers(m, platform, clock=clk_60MHz, ulpi_bus="sideband_phy", register_base=REGISTER_SIDEBAND_ADDR) # # SPI flash passthrough connections. # flash_sdo = Signal() spi_flash_bus = platform.request('spi_flash') spi_flash_passthrough = ECP5ConfigurationFlashInterface( bus=spi_flash_bus) m.submodules += spi_flash_passthrough m.d.comb += [ spi_flash_passthrough.sck.eq(board_spi.sck), spi_flash_passthrough.sdi.eq(board_spi.sdi), flash_sdo.eq(spi_flash_passthrough.sdo), ] # # Structural connections. # sck = Signal() sdi = Signal() cs = Signal() gateware_sdo = Signal() # # Synchronize each of our I/O SPI signals, where necessary. # m.submodules += FFSynchronizer(board_spi.sck, sck) m.submodules += FFSynchronizer(board_spi.sdi, sdi) m.submodules += FFSynchronizer(board_spi.cs, cs) # Select the passthrough or gateware SPI based on our chip-select values. with m.If(spi_registers.cs): m.d.comb += board_spi.sdo.eq(gateware_sdo) with m.Else(): m.d.comb += board_spi.sdo.eq(flash_sdo) # Connect our register interface to our board SPI. m.d.comb += [ spi_registers.sck.eq(sck), spi_registers.sdi.eq(sdi), gateware_sdo.eq(spi_registers.sdo), spi_registers.cs.eq(cs) ] return m
def elaborate(self, platform): m = Module() clk_60MHz = platform.request(platform.default_clk) # Drive the sync clock domain with our main clock. m.domains.sync = ClockDomain() m.d.comb += ClockSignal().eq(clk_60MHz) # Create a set of registers, and expose them over SPI. board_spi = platform.request("debug_spi") spi_registers = SPIRegisterInterface(default_read_value=-1) m.submodules.spi_registers = spi_registers # Identify ourselves as the SPI flash bridge. spi_registers.add_read_only_register(REGISTER_ID, read=0x53504946) # # For now, keep resources on our right-side I/O network used. # platform.request("target_phy") # # SPI flash passthrough connections. # flash_sdo = Signal() spi_flash_bus = platform.request('spi_flash') spi_flash_passthrough = ECP5ConfigurationFlashInterface( bus=spi_flash_bus) m.submodules += spi_flash_passthrough m.d.comb += [ spi_flash_passthrough.sck.eq(board_spi.sck), spi_flash_passthrough.sdi.eq(board_spi.sdi), flash_sdo.eq(spi_flash_passthrough.sdo), ] # # Structural connections. # sck = Signal() sdi = Signal() cs = Signal() gateware_sdo = Signal() # # Synchronize each of our I/O SPI signals, where necessary. # m.submodules += FFSynchronizer(board_spi.sck, sck) m.submodules += FFSynchronizer(board_spi.sdi, sdi) m.submodules += FFSynchronizer(board_spi.cs, cs) # Select the passthrough or gateware SPI based on our chip-select values. with m.If(spi_registers.cs): m.d.comb += board_spi.sdo.eq(gateware_sdo) with m.Else(): m.d.comb += board_spi.sdo.eq(flash_sdo) # Connect our register interface to our board SPI. m.d.comb += [ spi_registers.sck.eq(sck), spi_registers.sdi.eq(sdi), gateware_sdo.eq(spi_registers.sdo), spi_registers.cs.eq(cs) ] return m