From 7cb0abb275869641e7c8045d2599d50ead78bb25 Mon Sep 17 00:00:00 2001 From: Antoine van Gelder Date: Tue, 9 Jul 2024 15:39:17 +0200 Subject: [PATCH 1/2] On Windows, create the libusb1 backend explicitly by specifying the installed location of libusb-1.0.dll --- apollo_fpga/__init__.py | 27 +++++++++++++++++++++++---- apollo_fpga/gateware/flash_bridge.py | 19 +++++++++++-------- 2 files changed, 34 insertions(+), 12 deletions(-) diff --git a/apollo_fpga/__init__.py b/apollo_fpga/__init__.py index b397c71..bfe2061 100644 --- a/apollo_fpga/__init__.py +++ b/apollo_fpga/__init__.py @@ -92,7 +92,7 @@ def __init__(self, force_offline=False): device = self._find_device(self.APOLLO_USB_IDS, custom_match=self._device_has_apollo_id) # If Apollo VID/PID is not found, try to find a gateware VID/PID with a valid Apollo stub - # interface. If found, request the gateware to liberate the USB port. In devices with a + # interface. If found, request the gateware to liberate the USB port. In devices with a # shared port, this effectively hands off the USB port to Apollo. if device is None: @@ -111,7 +111,7 @@ def __init__(self, force_offline=False): raise DebuggerNotFound(f"Handoff request failed: {e.strerror}") # Wait for Apollo to enumerate and try again - time.sleep(2) + time.sleep(2) device = self._find_device(self.APOLLO_USB_IDS, custom_match=self._device_has_apollo_id) if device is None: raise DebuggerNotFound("Handoff was requested, but Apollo is not available") @@ -150,10 +150,29 @@ def _request_handoff(cls, device): @staticmethod def _find_device(ids, custom_match=None): + import usb.backend.libusb1 + + # In Windows, we need to specify the libusb library location to create a backend. + if platform.system() == "Windows": + # Determine the path to libusb-1.0.dll. + try: + from importlib_resources import files # <= 3.8 + except: + from importlib.resources import files # >= 3.9 + libusb_dll = os.path.join(files("usb1"), "libusb-1.0.dll") + + # Create a backend by explicitly passing the path to libusb_dll. + backend = usb.backend.libusb1.get_backend(find_library=lambda x: libusb_dll) + else: + # On other systems we can just use the default backend. + backend = usb.backend.libusb1.get_backend() + + # Find the device. for vid, pid in ids: - device = usb.core.find(idVendor=vid, idProduct=pid, custom_match=custom_match) + device = usb.core.find(backend=backend, idVendor=vid, idProduct=pid, custom_match=custom_match) if device is not None: return device + return None @staticmethod @@ -282,7 +301,7 @@ def create_jtag_programmer(self, jtag_chain): def create_jtag_spi(self, jtag_chain): """ Returns a JTAG-over-SPI connection for the given device. """ - # If this is an external programmer, we don't yet know how to create a JTAG-SPI + # If this is an external programmer, we don't yet know how to create a JTAG-SPI # interface for it. For now, assume we can't. if self.major == self.EXTERNAL_BOARD_MAJOR: return None, None diff --git a/apollo_fpga/gateware/flash_bridge.py b/apollo_fpga/gateware/flash_bridge.py index a29926c..b7f2723 100644 --- a/apollo_fpga/gateware/flash_bridge.py +++ b/apollo_fpga/gateware/flash_bridge.py @@ -34,7 +34,7 @@ class SPIStreamController(Elaboratable): """ Class that drives a SPI bus with data from input stream packets. Data received from the device is returned as another packet.""" - + def __init__(self): self.period = 4 # powers of two only self.bus = SPIBus() @@ -56,7 +56,7 @@ def elaborate(self, platform): sck_fall.eq( sck_d & ~self.bus.sck), # falling edge sck_rise.eq(~sck_d & self.bus.sck), # rising edge ] - + # I/O shift registers, bit counter and last flag shreg_o = Signal(8) shreg_i = Signal(8) @@ -114,7 +114,7 @@ def elaborate(self, platform): m.next = 'END' with m.Elif(~self.input.valid): m.next = 'WAIT' - + with m.State("END"): m.d.comb += [ self.input.ready .eq(0), @@ -134,7 +134,7 @@ def elaborate(self, platform): ] return m - + class FlashBridgeRequestHandler(USBRequestHandler): """ Request handler that can trigger a FPGA reconfiguration. """ @@ -168,7 +168,7 @@ def elaborate(self, platform): # Once the receive is complete, respond with an ACK. with m.If(interface.rx_ready_for_response): - m.d.comb += interface.handshakes_out.ack.eq(1) + m.d.comb += interface.handshakes_out.ack.eq(1) # If we reach the status stage, send a ZLP. with m.If(interface.status_requested): @@ -181,7 +181,7 @@ def elaborate(self, platform): class FlashBridgeSubmodule(Elaboratable): """ Implements gateware for the USB<->SPI bridge. Intended to use as a submodule See example in FlashBridge """ - + def __init__(self, endpoint): # Endpoint number for the in/out stream endpoints self.endpoint = endpoint @@ -354,12 +354,15 @@ class FlashBridgeNotFound(IOError): class FlashBridgeConnection: def __init__(self): # Try to create a connection to our configuration flash bridge. - device = usb.core.find(idVendor=VENDOR_ID, idProduct=PRODUCT_ID, custom_match=self._find_cfg_flash_bridge) + device = ApolloDebugger._find_device( + ids=[(VENDOR_ID, PRODUCT_ID)], + custom_match=self._find_cfg_flash_bridge + ) # If we couldn't find the bridge, bail out. if device is None: raise FlashBridgeNotFound("Unable to find device") - + self.device = device self.interface, self.endpoint = self._find_cfg_flash_bridge(device, get_ep=True) From f1fb923f02db2562bbab5aa097053d932dfe64b6 Mon Sep 17 00:00:00 2001 From: Antoine van Gelder Date: Tue, 9 Jul 2024 16:01:27 +0200 Subject: [PATCH 2/2] Add 'importlib_resources' to dependencies for Python versions <= 3.8 --- pyproject.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/pyproject.toml b/pyproject.toml index 0b9ab5a..1bdc1d3 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -24,6 +24,7 @@ classifiers = [ 'Topic :: Scientific/Engineering', ] dependencies = [ + "importlib_resources; python_version<'3.9'", "pyusb>1.1.1", "pyvcd>=0.2.4", "prompt-toolkit>3.0.16",