Electronic – How is debugging build implemented in VHDL

debuggingvhdl

I come from C background and am being introduced to VHDL. I read about the syntax and the concurrency/consecutiveness of actions.

Now I am getting to wonder how are development-only features implemented. Things like assert() and #ifndef NDEBUG LOG_MSG_UART("99 bottles of beer").

The scenario, that I am thinking of, is this. Let us have a development board with an FPGA and several debugging headers. Various signals are output to those debug headers for measurement with an oscilloscope or logic analyzer. In the release version, there will be no such headers. How does one write the code so that they can easily switch between the Release and Debug builds?

An idiomatic example would help a lot.

Best Answer

In VHDL, the basic ASSERT statement is used to ensure that when you are simulating, you catch all those conditions. Simulation is one step of the debugging process, which is most software-like, as you have access to everything within the design.

You can also (with access to sufficiently high-calibre tools) use PSL to write more complex assertions which can involve timings as well as simple conditionals.

Once you have simulated to your satisfaction, if you need to debug the real hardware, then you can use the following tools:

  • embedded logic analyser (Xilinx: Chipscope, Altera: SignalTap) - you build this in at compile time and can then trigger and monitor signals. The signals are captured in real-time to internal memory, so there is a limit on how many and for how long, but it does give excellent visibility. It can be time-consuming though as each time you change your mind about the setup, you have to rebuild the FPGA (which is a process measured in tens of minutes or even hours, depending ont he complexity of the design)
  • spare pins - with or without LEDs. Bring out critical internal signals and monitor them with an oscilloscope and logic analyser. Again, rebuild each time you change it. This can also be done more dynamically in Xilinx-land with the FPGA editor, so you can make relatively quick updates to the bitstream, if you can find the signal you want within the optimised netlist!

As Brian pointed out, you will also need an oscilloscope (and potentially logic analyser) to debug the external interfaces - checking the timing etc.


Regarding the issue of having "debug" and "release" builds, that is not handled in a "standard" way (unlike in the software world). The behaviour would not be wildly different in most cases: As the FPGA is very deterministic, you don't lose speed by having debug logic in there (or if you do, it still meets the required spec, as otherwise you couldn't debug the chip!). You do end up with more logic than you need, but again, it has to fit int he device you have (unless you are planning to downsize for release, but given the step ups in device size, you'd need a lot of debug logic for that to be worthwhile!).

Also note that (as far as I've heard) no-one build with different optimiser settings for debug vs. release, which can make finding the signals you want tricky, so you have to add attributes to them to stop them being as optimised as they otherwise would be, which is good as the rest of the design gets optimised. Not so good that you have to rebuild to change the attributes. (At least there's plenty of time for keeping your documentation up-to-date while you wait for the builds :)

If you do want to do this then I would suggest a couple of ways:

  • Have a boolean generic on the top level instance - it can default to debugging off, and you can override it on the command-line/from the GUI of your synthesiser.
  • Have a boolean constant in a package that you use in your main code - select between the two modes by editing this file

With the first option, only the top-level can see the state of the debug status (unless you pass it down the hierarchy, but that can get nasty quickly as you usually need to pass the debug signals back up then too!).

With the second, any entity can get at the debug constant, and make use of it - again you need to pass signals up the tree.

You can use the boolean in an if..generate..else generate to instantiate the logic you want (or don;t want) depending on the "mode".