Many individuals have read my previous posts and have wondered what my debugging philosophy actually is. They’ve asked me how I would recommend debugging a design. This post attempts to outline the general approaches I used to debug my own FPGA designs.
In quick sum:
Simulation: I recommend using a simulator that allows allows you to simulate all of the external components of your design in a fully integrated fashion
Hardware testing: I recommend including some form of integrated logic analyzer or scope within your design when you move into hardware.
While I tend to use open source products, I have nothing against commercial products that will help a designer accomplish his purpose.
That said, let’s take a look at my own debugging philosophy in more detail.
Because implementing logic on an FPGA can take so long to do, I am a firm believer in using a simulation.
FPGA’s often need to communicate with external devices, though, and those external devices need to respond to the simulated logic and the test designer as though they were present in hardware.
I recommend, therefore, for those components of an FPGA design that need to interact with an external device, that the simulation facility provide an external component simulator and interface validator for each external component the digital logic needs to interact with. By component simulator, I mean something that creates inputs and treats outputs like the real hardware component would. By interface validator, I mean something that will quickly draw the developer’s attention to any violations in the interface protocol.
This means that the minimum capability I would require of any simulation capability is the ability to simulate all of the external components on my design. Were this a commercial capability, I would want to be able to integrate my own external component simulations as well as any external component simulations produced by multiple (possibly competing) vendors.
This minimum capability would allow me to simulate my entire, integrated design, as shown in Fig 2. That is, I should be able to integrate all of these component simulators into an integrated design simulation.
Does your design have a UART within it? Your simulation should then be able to simulate a UART. Your design should be able to create a UART waveform, and your external component simulator should be able to process it and perhaps place the result on your simulation terminal. You should be able to type into that simulation terminal anything and have it sent to your external UART simulator. The external component simulator should then translate anything it reads, and send it into your design as a proper UART signal.
Does your design have a flash component within it? You should be able to start up, erase, program, and read from that flash as a part of your simulation.
Does your design include buttons or switches? You should be able to simulate buttons and switches, and your simulations should be good enough to test any debouncing capability you might have.
Does your design have an SD card within it? You should be able to communicate with the simulated SD card, and even have a simulation that can match the SD card you wish to use in your design.
Does your design have a VGA within it? Your simulation should then be able decode your VGA output, to prove that you are producing the correct synchronization signals, and then to draw the pixels to the screen in a way that you can verify that your VGA code works.
Does your design have an EDID component to it? Your simulator should be able to communicate EDID information to your design over a proper I2C port.
Does your design have a CPU within it? Your simulator should be able to simulate the CPU, it’s booting process (using flash, if that’s what you have), and it should allow you to see what’s going inside the CPU as it boots. You should be able to trace the instructions your CPU executes, together with any logic used within your design. Do you want to be able to run a program on your CPU? You should be able to do that within the CPU, and it should be able to interact with its environment in a manner similar to its real environment.
This is my philosophy on simulation.
As you can see, I am a firm believer in simulating your whole design, not just the components.
Verilator meets these requirements. Do you know of any other capability that can? Please feel free to comment about it in the discussion at the end of this post.
I’m also not so naive as to believe that a design will work the first time it’s placed in an actual FPGA. For this reason, I am a firm believer in testing on the actual hardware as well.
Hardware testing includes both component testing (externally directed, often without the CPU), as well as integrated design testing.
Using your hardware, you should be able to test components by:
Issuing individual commands to them, and verifying that individual interactions work
Then issuing more complex strings of commands
In both cases, you should be able to start from a (roughly) known condition, command the hardware to begin the test, and then be able to measure the results of the test. Doing this necessitates some form of internal logic analyzer, such as the wishbone scope that I use.
I like to issue commands over some form of debugging bus, such as the hexbus debugging bus we’ve just built together. This allows me to command various tests, and to read information and status back out of the FPGA. If you have a CPU on board, such as the ZipCPU, you may wish to command your tests in a faster and more coordinated fashion from software.
Trace data itself can be drawn from something as simple as your own user designed scope, or Gisselquist Technology’s wishbone scope. We’ll be discussing in the near future how you can add the capability to create a VCD file to your scope. That will finish off the discussion on how to build your own debugging facility.
Commercial products exist that can record trace information from within your chip. Xilinx, for example, includes their Integrated Logic Analyzer (ILA) as part of the Vivado Design Suite. You’ll need more than the free webpack license, though, in order to use it. Given how easy such an analyzer is to build, it’s probably not work the $3k necessary to pay for a full Design Suite license just to use this capability.
One of the benefits of rolling your own, is that integrating your own logic analyzer into your own logic can be done with your favorite interface. For example, I’ve often used the ZipCPU to trigger the scope or to examine the outputs of it. Further, unlike a commercial scope which may be restricted to using the JTAG for control and output, I can get the outputs via whatever debugging bus I’m already using.
Your own choices
These two components outline the philosophy I use to debug my own FPGA designs.
I am a firm believer in simulation.
I grew up testing on the hardware itself, and see no problems with it as long as you can get an internal trace from your hardware.
Do you have a different debugging philosophy? Do you know of other or better tools? Feel free to post and discuss them below.
For his God doth instruct him to discretion, and doth teach him. (Is 28:26)