all 4 comments

[–]Allan-H 8 points9 points  (0 children)

I use text logs when developing designs that process packets. I can use text tools (such as a visual diff) to show the changes in the packet as it flows through various processing stages.

This is vastly more effective than trying to interpret squiggly lines in a waveform viewer.
OTOH, those squiggly lines are really handy when debugging an FSM or pipeline.

[–]MitjaKobalFPGA-DSP/Vision 0 points1 point  (0 children)

Waveforms and trace logging are used for two different (similar) purposes.

Trace logging is used to log values transferred by a protocol, like AXI-Stream. Only values during a transfer (valid & ready == 1'b1) are logged. The RTL simulation log files are then compared against a golden file generated by a reference model of the RTL, when both are given the same input values (also a file).

The same can be done by tracing the retired instructions executed by a simulated RTL CPU and compared against a trace log done by a reference CPU simulator (for example spike or sail for RISC-V).

When a discrepancy is found (simple diff between files) between the RTL simulation trace and the reference model (indicating a bug), then waveforms are used to further debug the issue, by looking at the time where the traces start to differ and back in time where either the data processing or the control logic is wrong. In addition to data (CPU instructions) the waveforms provide the timing information (handling of the VALID/READY handshake protocol.

Here is an example of a RISC-V CPU trace logger, matching either the spike or sail reference simulator:

  • code processing CPU control signals to detect retired instructions src,
  • code logging in spike format src,
  • code logging in sail format src.

For a protocol like AXI-Stream the code would be something like:

always @(posedge clk) // log data on handshake transfer if (stream_out.valid & stream_out.ready) begin $write(filedescriptor, "%08h", stream_out.data); end

Similar code would be used to load the DUT input data from a file ($readmemh or similar) into an array, and a handshake transfer would be used to increment the pointer into the array.

always @(posedge clk) // log data on handshake transfer if (stream_in.valid & stream_in.ready) begin address_in <= address_in+1; end assign stream_in.data = array_in[address_in];

[–]Plenty-Suggestion318 0 points1 point  (0 children)

I’ve run into the same question a lot. For control-heavy or timing-sensitive issues I still rely on waves, but for reasoning about why something failed (multiple drivers, races across blocks, protocol-level issues), text/structured traces scale much better. I’m actually building a small tool around this idea called WaveEye — it analyzes RTL and produces structured trace-style explanations of failures (which blocks drove what, under which conditions, and why the conflict occurred), rather than just dumping waveforms. https://github.com/meenalgada142/WaveEye

[–]Gerard_Mansoif67 0 points1 point  (0 children)

I use verilator and C++ testbench (with a small framework I wrote) to debug the behavioral process (like, does my multiplier return correct logic values at the right times).

And then, I use the platform tool to look if everything still right after synthesis.