I wanted to use OpenOCD with my Nexys 3 FPGA devboard. The Reference Manual1 states that it has an on-board USB controller that is connected to the JTAG lines. In this post, we will (hopefully) make it work under Linux with OpenOCD, so that I can debug softcores in the future.
Getting familiar with the on-board USB-JTAG infrastructure
Checking the schematic2 reveals that it uses a CY7C68013A
IC, also known as a Cypress EZ-USB FX2LP USB microcontroller.
Its datasheet3 states that it contains a 8051 CPU core with a max clock of 48 MHz, there is no internal flash memory and all data and code is loaded from external storage.
On the board I can see an 8-legged chip that looks very suspicous, after tracing it out we can see it is IC4, a 24AA128
128K I2C EEPROM.
Sadly the WP pin is connected to GND and the EEPROM's datasheet5 says, the write-protection is NOT enabled, therefore it would be the safest to create a dump of it for backup reasons. However, as we will se later I decided against it.
Already existing tools and projects
The firmware on the FX2LP reports itself as a 1443:0007
USB device (that can be checked using the lsusb
command)
After looking around in the OpenOCD files, we can find a very useful note in the file /usr/share/openocd/scripts/board/digilent_atlys.cfg
:
The Digilent Atlys normally requires proprietary tools to program and will enumerate as: ID 1443:0007 Digilent Development board JTAG
However, the ixo-usb-jtag project provides an alternative open firmware for the on board programmer. When using this firmware the board will then enumerate as: ID 16c0:06ad Van Ooijen Technische Informatica (With SerialNumber == hw_nexys)
This points us to the repo of ixo-usb-jtag
4 which already seems to have a support for Nexys and Nexys 2 boards. But how can we run our own code on the FX2LP?
By using the cycfx2prog
utility with can read and write the memories of the chip:
For fun, I also checked out the RAM dump in Ghidra and it decompiled very nicely:
Running code on the onboard controller
After that we can focus on getting this board supported for ixo-usb-jtag
. Compilation is done using the SDCC (Small Device C Compiler). The code on the GitHub repo will not work with the modern version of the SDCC, and the latest GCC would not build an older SDCC on modern systems. Therefore, I just used the prebuilt SDCC 3.3.0 installer6 for Windows. I installed Cygwin with make
and it built flawlessly. As you can see it resulted in IntelHex files that can be flashed to the RAM of the device.
By checking out the usbjtag-nexys.hex
file, we can see the follwing memory regions being used:
This corresponds to the following memory regions, which are all RAM:
I checked the code for any i2c_write()
functions, but did not find any, so I was confident to try it out without dumping the EEPROM first. I don't think I even have the proper clip for dumping the ROM in-circuit without desoldering.
After executing the cycfx2prog -id=1443.0007 prg:/tmp/shared/usbjtag-nexys.hex run
command
and listing the USB devices, I was greeted precisely what the note said in the OpenOCD config:
And after a power cycle, the old Digilent USB ID returned as expected :^)
(No) firmware modifications
Anyways, after checking the code, we can see that the Nexys boards use almost the same pinouts:
This makes perfect sense, as reusing the same pinout allows for the potential reuse of the older board's firmware. Therefore, I just programmed the untouched custom firmware and It worked fine, after overcoming one last obstacle:
in procedure 'script'
at file "embedded:startup.tcl", line 28
at file "/usr/share/openocd/scripts/board/digilent_atlys.cfg", line 17
at file "/usr/bin/../share/openocd/scripts/interface/usb-jtag.cfg", line 36
OpenOCD would not start with the default config. After a painstaking debug session, the fix was very easy: I just needed to comment out the line starting with usb_blaster device_desc
. My guess is that this command simply does not exist anymore (or never did).
And after all of that, I was finally ready to use the JTAG:
-
Nexys 3 FPGA Board Reference Manual: https://digilent.com/reference/_media/nexys:nexys3:nexys3_rm.pdf ↩
-
Nexys 3 Schematic: https://digilent.com/reference/_media/reference/programmable-logic/nexys-3/nexys3_sch.pdf ↩
-
CY7C68013A datasheet: https://www.infineon.com/dgdl/Infineon-CY7C68013A_CY7C68014A_CY7C68015A_CY7C68016A_EZ-USB_FX2LP_USB_Microcontroller_High-Speed_USB_Peripheral_Controller-DataSheet-v31_00-EN.pdf?fileId=8ac78c8c7d0d8da4017d0ec9f7974252 ↩
-
ixo-usb-jtag project: https://github.com/mithro/ixo-usb-jtag ↩
-
24AA128 datasheet: https://ww1.microchip.com/downloads/aemDocuments/documents/MPD/ProductDocuments/DataSheets/24AA128-24LC128-24FC128-128-Kbit-I2C-Serial-EEPROM-20001191U.pdf ↩
-
SDCC 3.3.0 Windows installer: https://sourceforge.net/projects/sdcc/files/sdcc-win64/3.3.0/sdcc-3.3.0-x64-setup.exe/download ↩