greatscottgadgets / apollo

microcontroller-based FPGA / JTAG programmer
BSD 3-Clause "New" or "Revised" License
54 stars 28 forks source link

firmware: Disallow FPGA takeover of USB port #54

Closed mossmann closed 2 months ago

mossmann commented 2 months ago

Whenever the FPGA is taken offline, stop allowing it to take over the shared USB port. This prevents a later FPGA configuration from taking over the port before it is explicitly allowed to do so.

This fixes a bug introduced in #50 in which a port handoff could be inappropriately deferred from one FPGA configuration (which does not request the port) to a later configuration (which does request the port):

$ blinky.py
$ bulk_speed_test.py (modified to use CONTROL)
INFO    | __init__    | Building and uploading gateware to attached Cynthion r1.3...
Traceback (most recent call last):
  File "/home/mossmann/src/apollo/apollo_fpga/ecp5.py", line 467, in configure
    status = self._read_status()
             ^^^^^^^^^^^^^^^^^^^
  File "/home/mossmann/src/apollo/apollo_fpga/ecp5.py", line 515, in _read_status
    status_bytes = self._execute_command(self.Opcode.LSC_READ_STATUS, self.STATUS_REGISTER_LENGTH,
                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/mossmann/src/apollo/apollo_fpga/ecp5.py", line 988, in _execute_command
    response = self.chain.shift_data(tdi=data, length=length, state_after='DRPAUSE')
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/mossmann/src/apollo/apollo_fpga/jtag.py", line 479, in shift_data
    response = self._shift_while_in_state('DRSHIFT', tdi=tdi, length=length, ignore_response=ignore_response,
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/mossmann/src/apollo/apollo_fpga/jtag.py", line 422, in _shift_while_in_state
    self._ensure_in_state(state)
  File "/home/mossmann/src/apollo/apollo_fpga/jtag.py", line 386, in _ensure_in_state
    self.debugger.out_request(REQUEST_JTAG_GO_TO_STATE, value=state_number)
  File "/home/mossmann/src/apollo/apollo_fpga/__init__.py", line 272, in out_request
    return self.device.ctrl_transfer(request_type, number, value, index, data, timeout=timeout)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/mossmann/src/cynthion/cynthion/python/venv/lib/python3.11/site-packages/usb/core.py", line 1082, in ctrl_transfer
    ret = self._ctx.backend.ctrl_transfer(
          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/mossmann/src/cynthion/cynthion/python/venv/lib/python3.11/site-packages/usb/backend/libusb1.py", line 893, in ctrl_transfer
    ret = _check(self.lib.libusb_control_transfer(
          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/mossmann/src/cynthion/cynthion/python/venv/lib/python3.11/site-packages/usb/backend/libusb1.py", line 604, in _check
    raise USBError(_strerror(ret), ret, _libusb_errno[ret])
usb.core.USBError: [Errno 32] Pipe error

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/home/mossmann/src/cynthion/cynthion/python/venv/lib/python3.11/site-packages/cynthion/gateware/platform/core.py", line 79, in toolchain_program
    programmer.configure(bitstream)
  File "/home/mossmann/src/apollo/apollo_fpga/ecp5.py", line 472, in configure
    self.chain.debugger.set_led_pattern(self.chain.debugger.LED_PATTERN_IDLE)
  File "/home/mossmann/src/apollo/apollo_fpga/__init__.py", line 285, in set_led_pattern
    self.out_request(self.REQUEST_SET_LED_PATTERN, number)
  File "/home/mossmann/src/apollo/apollo_fpga/__init__.py", line 272, in out_request
    return self.device.ctrl_transfer(request_type, number, value, index, data, timeout=timeout)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/mossmann/src/cynthion/cynthion/python/venv/lib/python3.11/site-packages/usb/core.py", line 1082, in ctrl_transfer
    ret = self._ctx.backend.ctrl_transfer(
          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/mossmann/src/cynthion/cynthion/python/venv/lib/python3.11/site-packages/usb/backend/libusb1.py", line 893, in ctrl_transfer
    ret = _check(self.lib.libusb_control_transfer(
          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/mossmann/src/cynthion/cynthion/python/venv/lib/python3.11/site-packages/usb/backend/libusb1.py", line 604, in _check
    raise USBError(_strerror(ret), ret, _libusb_errno[ret])
usb.core.USBError: [Errno 32] Pipe error      

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/home/mossmann/src/luna/bulk_speed_test.py", line 166, in <module>
    device = top_level_cli(SpeedTestDevice,
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/mossmann/src/luna/luna/__init__.py", line 113, in top_level_cli
    products = platform.build(fragment,
               ^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/mossmann/src/cynthion/cynthion/python/venv/lib/python3.11/site-packages/amaranth/build/plat.py", line 113, in build
    self.toolchain_program(products, name, **(program_opts or {}))
  File "/home/mossmann/src/cynthion/cynthion/python/venv/lib/python3.11/site-packages/cynthion/gateware/platform/core.py", line 77, in toolchain_program
    with debugger.jtag as jtag:
  File "/home/mossmann/src/apollo/apollo_fpga/jtag.py", line 216, in __exit__
    self.debugger.out_request(REQUEST_JTAG_STOP)
  File "/home/mossmann/src/apollo/apollo_fpga/__init__.py", line 272, in out_request
    return self.device.ctrl_transfer(request_type, number, value, index, data, timeout=timeout)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/mossmann/src/cynthion/cynthion/python/venv/lib/python3.11/site-packages/usb/core.py", line 1082, in ctrl_transfer
    ret = self._ctx.backend.ctrl_transfer(
          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/mossmann/src/cynthion/cynthion/python/venv/lib/python3.11/site-packages/usb/backend/libusb1.py", line 893, in ctrl_transfer
    ret = _check(self.lib.libusb_control_transfer(
          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/mossmann/src/cynthion/cynthion/python/venv/lib/python3.11/site-packages/usb/backend/libusb1.py", line 604, in _check
    raise USBError(_strerror(ret), ret, _libusb_errno[ret])
usb.core.USBError: [Errno 32] Pipe error