Running simulations using testbenches are an important part of HDL logic design, but there is an element to the development process that requires the realtime view of of the design in action when actually connected to the peripherals they are driving. This is done through the use of an integrated logic analyzer (ILA).
As FPGAs have evolved into more complex parts by integrating components such as physical processors to create today's System on Chip (SoC) components, the implementation of ILAs in the logic of the FPGA's fabric has also become more complex. This complexity comes from the structure of how the processing system and programmable logic are interconnected and their boot sequence.
Looking at the Zynq and Zynq UltraScale/UltraScale+ parts from AMD with physical ARM-core processors fabricated directly into their programmable logic, the ARM-core processor is the first in line for the overall boot sequence. This is because the package pins on the Zynq parts for signals such as the input clock from the oscillator are routed directly to the ARM processor. The ARM processor is then responsible for providing a system clock to the programmable logic.
Reading between the lines here, this means that in order for the programmable logic to be able to run a bitstream the ARM-core processor of the Zynq must at least have had a first stage boot loader application executed on it to bring it up so it can provide the system clock to the programmable logic.
This is a detail that can be easily missed because the JTAG boundary chain interface is connected directly to the programmable logic on all AMD FPGA chips, so the programmable logic is always available to have a bitstream uploaded to it regardless of the state of the ARM-core processor. The design just won't actually execute until the processor is booted up to provide a system clock to it.
Overall, this boils down to a specific sequence of steps that need to be followed between Vivado and Vitis in order to get ILAs up and running in the HDL design on Zynq and Zynq UltraScale/UltraScale+ parts. This process was fairly straightforward in the past, but threw me for a loop after I upgraded to the new Vitis Unified IDE with version 2023.2 so I decided that it was worth its own dedicated write-up.
The outline of these steps are the following:
1 - Add the ILA where needed in the HDL of the design in Vivado.
2 - Export the hardware design from Vivado.
3 - Create a platform component in Vitis from the exported hardware file.
4 - Create a standalone (no-OS) application from the Hello World example in Vitis.
5 - Launch a debug run of the Hello World application in Vitis on the target Zynq board.
6 - Open Hardware Manager in Vivado and connect to the target Zynq board.
7 - End the debug session in Vitis and disconnect from the target Zynq board.
8 - Close Hardware Manager in Vivado to disconnect it from the target Zynq board.
Note: I am using a project on my Kria KD240 Drives Starter kit as the example for this write-up but the steps are applicable to any Zynq and Zynq UltraScale/UltraScale+ board. This workflow is also specific to the Vitis Unified IDE which for versions 2023.2 and later.
Add ILAsILAs can added either in the block design to instantiated directly into HDL code. I am personally doing the latter and instantiating them directly into my Verilog code, so I need to pull up the ILA IP in the IP catalog to be able to configure it for my needs.
Select IP Catalog from the Flow Navigator window, and search for "ILA":
Double-click on the option for ILA (Integrated Logic Analyzer) and select the option to Customize IP when prompted:
This will bring up the configuration window for the ILA IP where the sample buffer depth, number of probes, interface type, etc. can be configured.
My design is looking at 9 discrete signals, none of which are AXI interfaces so I set the Monitor Type to Native. Since my system clock is running at 100MHz (which is what the ILA's sample rate will be) I extended the memory buffer since my target signals are going to be somewhere on an order of one magnitude slower.
Click OK to save and close the ILA's IP configuration window and follow the prompts to generate the output products for the IP.
A cool feature about IP from the IP Catalog in Vivado is that they will generate an instantiation template for you to copy+paste into your Verilog or VHDL (depending on which language you have set as the default in the Vivado project settings).
Once the ILA has been generated (see progress in Design Runs tab). Switch to IP Sources in the Sources tab and expand the Instantiation Template option under the ILA's name. Double-click on the HDL file to open it where you'll find the instantiation for the ILA we just configured:
Copy + paste the instantiation into the desired HDL source file and replace with your target signal names:
One odd "feature" I found in the Vitis Unified IDE is that the option to execute debug runs to use the debugger to step through standalone (no-OS) applications is missing if the underlying hardware platform (.xsa file) is from a Vivado project configured as a Vitis Extensible Platform (ie - has the hooks for hardware acceleration).
So if this option is enabled, it needs to be disabled under Settings > General > Project is an extensible Vitis platform. and a new bitstream generated.
Since I will want to come back and re-enable the option for hardware acceleration in the future for this design, I opted to apply this change to a new synthesis/implementation run so that my platform settings will be cached when I come back to switch. So I selected Yes when Vivado prompted me to apply the changed to a new run:
Then to keep things straight, I appended "no_platform" to the title of the new run:
Once generated, in the Design Runs tab, right-click in the new run and select Launch Runs... to kick off the new synthesis, implementation, and bitstream generation:
If you want this to be the same run that is launched when selecting the Run Synthesis/Implementation options from the Flow Navigator window, also select the option for Make Active:
Once the new bitstream has been generated, go through the process of exporting the hardware design again still ensuring that the option to include the bitstream is selected.
Once the hardware has been exported, launch the Vitis Unified IDE.
You can either open an existing workspace or create a new one.
I opted to create a new one dedicated to debugging with my ILAs since the software I'm creating here serves no other purpose other than to be the bare minimum to get the ARM-core processor of my KD240's Zynq up and running.
Once the new workspace opens, select the option to Create Platform Component:
Give the platform component the desired name and point it to the hardware XSA file that we exported from Vivado in the previous steps.
Do not configure anything under the option for Emulation in the Flow tab and select standalone on the default processor core under the OS and Processor tab. Also be sure the options to generate boot artifacts and PMU firmware are enabled.
Once the platform components populates in the Vitis workspace, run a quick build on it.
Application ComponentSwitching back to the Welcome tab in the Vitis workspace, select Examples under Get Started to open the application template catalog.
Select the Hello World option from the list on the left to open the info tab about it. Then select Create Application Component from Template:
This will bring up the application configuration window. Give the application component the desired name, then point it to the platform component created in the previous step under the Hardware tab. Leave the default selections under the Domain tab.
Again, once the application component populates in the Vitis workspace, run a quick build on it.
No changes to the C code are necessary here; again, the idea is just something that builds and will boot the Zynq's processor.
Launch Debug RunTo launch a debug run in Vitis, set the application component as the target in the Flow window (lower left side). Then single left-click the Debug option. This is of course after your target FPGA development board is powered on and connected to the host PC via JTAG.
The debugger will set an automatic break point at the first line after entering the main function of the applicaiton.
Use the step over option to step past the init_platform() function.
At this point, the ARM-core processor has been booted, the programmable logic flashed with the design bitstream, and is running off the system clock provided by the ARM.
Connect to ILAs with Vivado Hardware ManagerSwitching back to Vivado, select Open Hardware Manager > Open Target > Open New Target... in the Flow Navigator window.
Step through the connection manager windows to connect to the target Zynq device:
Since the bitstream that was uploaded to the programmable logic by the debugger in Vitis was the same one that has the ILAs in it, they will appear automatically as the Hardware Manager connects to the target Zynq device.
Otherwise, you can select the option to program the device to specify the proper bitstream with debug nets (.ltx) file.
At this point, the ILAs can be run and triggered as normal. Once you're done debugged using the ILAs, close the Hardware Manager to disconnect it in Vivado then return to Vitis to end the debug session.
End & Close Debug Session in VitisClick green "play" button to finish running Hello World application. Then click the red "stop" button to disconnect the debug session.
Finally, click the house icon to exit the debug view and return to the development view. This does not happen automatically when a debug sessions ends/is disconnected.
And that's it! Hopefully this helps save someone else a bit of time as I confused myself for quite the afternoon on this since I'm just too dependent on my ILAs to not invest the time into figuring out their workflow.
Comments
Please log in or sign up to comment.