palmarci's blog

a random blog mostly for myself, so i can remember stuff

OpenOCD on the Nexys3 FPGA development board


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.
alt text

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.
alt text

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.
alt text

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 24AA128128K I2C EEPROM. alt text

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.
alt text

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)

alt text

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-jtag4 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:
alt text

For fun, I also checked out the RAM dump in Ghidra and it decompiled very nicely:
alt text

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.
alt text

By checking out the usbjtag-nexys.hex file, we can see the follwing memory regions being used:
alt text

This corresponds to the following memory regions, which are all RAM: alt text

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:
alt text

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:
alt text

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:
alt text