3.2 Reading waveforms and debugging
Why this matters
A testbench is only useful if you can read what it produced. When a circuit misbehaves, the waveform is the whole evidence: every signal's value at every moment, and nothing else. Reading one quickly, and knowing which signal to add when the answer is not yet visible, is the main debugging skill in this course, and the same skill is what lets you read every timing diagram in this book.
Learning goals
Section titled “Learning goals”- Read a waveform: the signal names, the time axis, one-bit lanes, bus values, and the unknown value X.
- Choose the radix that matches how a bus is meant to be read, and say what a radix does and does not change.
- Name the three common causes of an unknown value and recognize each in a design or a testbench.
- Trace a wrong output backward through a module's internal signals to find where the design went wrong.
- Decide what a waveform needs to show before you send it to someone else.
Intuition first
Section titled “Intuition first”Picture a spreadsheet in which each row is a signal and each column is a moment of simulated time. The simulator fills in every cell as it runs. A waveform is that spreadsheet drawn as a picture: a one-bit signal is a line that is high or low, and a bus is a row of boxes with the value written in each.
Debugging with a waveform is the same as debugging a program with a log. You start from the symptom, a wrong output at some moment, and read backward through the log to the first value you cannot explain. In software you would add a print statement and rerun. Here you add the internal signal to the viewer and look at what it did at that moment.
The analogy breaks in one way. In a program the log is in the order the statements ran. A waveform has no order of statements: every part of the circuit is working at every moment, and the picture shows all of it at once.
What a waveform shows
Section titled “What a waveform shows”Time in ps; one column is 10 ps.
Timing diagram from simulation, ch03/guess-trace: time in ps from 0 to 80, 8 columns of 10 ps.
guess (3 bits, bin): 000 at 0, then 001 at 10, 010 at 20, 011 at 30, 100 at 40, 101 at 50, 110 at 60, 111 at 70.
dut.judge.diff (3 bits, bin): 110 at 0, then 111 at 10, 000 at 20, 001 at 30, 010 at 40, 011 at 50, 100 at 60, 101 at 70.
less: 1 at 0, then 0 at 20, 1 at 60.
equal: 0 at 0, then 1 at 20, 0 at 30.
greater: 0 at 0, then 1 at 30, 0 at 60.
Description: A timing diagram of guess in binary, the internal signal dut.judge.diff in binary, and the one-bit outputs less, equal and greater, over eight steps. guess counts from 000 to 111, one value per step.
Figure 3.2.1 is a typical waveform, and it has the parts every waveform has.
- Names on the left. Each lane is one signal.
guessis a signal of the testbench. The namedut.judge.diffis a path: inside the testbench, the instancedut, inside it the instancejudge, and inside that a signal calleddiff. A viewer can show any signal anywhere in the hierarchy, not only the ports of the module under test. - Time along the bottom. Time runs left to right in the simulator's time units. The grid line spacing is printed under the figure.
- One-bit signals as lines. A high line is 1 and a low line is 0.
- Buses as boxes. A signal several bits wide is drawn as a row of boxes, each with its value written inside. A new box begins where the value changes. The value is written in a radix, and the lane name says which one.
- Hatching and special values. A signal whose value is completely unknown is hatched, and a signal that is partly unknown shows its bits one at a time, such as
1x0z.
The radix of a displayed bus is the number base in which its bits are written: binary, decimal or hexadecimal. A radix changes only how the value is written on the screen. The bits of the signal are the same in every radix.
The values in each of the next three figures are the same eight 4-bit codes, 8 to 15, written in three radices. The binary lane shows every bit. The decimal lane reads the bits as an unsigned number. The hexadecimal lane writes four bits as one digit, which is the shortest way to read a wide bus.
Time in ps; one column is 20 ps.
Timing diagram from simulation, ch03/bcd-bin: time in ps from 160 to 320, 8 columns of 20 ps.
bcd (4 bits, bin): 1000 at 160, then 1001 at 180, 1010 at 200, 1011 at 220, 1100 at 240, 1101 at 260, 1110 at 280, 1111 at 300.
Description: A timing diagram of one 4-bit lane in binary over eight steps, from 1000 to 1111.
Time in ps; one column is 20 ps.
Timing diagram from simulation, ch03/bcd-dec: time in ps from 160 to 320, 8 columns of 20 ps.
bcd (4 bits, dec): 8 at 160, then 9 at 180, 10 at 200, 11 at 220, 12 at 240, 13 at 260, 14 at 280, 15 at 300.
Description: A timing diagram of one 4-bit lane in decimal over eight steps, from 8 to 15.
Time in ps; one column is 20 ps.
Timing diagram from simulation, ch03/bcd-hex: time in ps from 160 to 320, 8 columns of 20 ps.
bcd (4 bits, hex): 8 at 160, then 9 at 180, A at 200, B at 220, C at 240, D at 260, E at 280, F at 300.
Description: A timing diagram of one 4-bit lane in hexadecimal over eight steps, from 8 to F.
Both waveform viewers shown in the section slides let you change, for each signal, how its bits are displayed without changing the bits (ModelSim's Radix menu, Surfer's Format menu); the common choices are binary, unsigned, decimal (the slides call it a signed integer) and hexadecimal. (fact ch03/radix-menu) The decimal setting of a viewer may therefore be signed or unsigned: check which one yours uses. The book's figures use decimal only for unsigned values, so a signed reading is written out in the text.
Radix matters because the same bits mean different numbers. A 3-bit signed number has the range −4 to 3, as Section 2.6 describes, so the three bits 100 are the number 4 when read as unsigned and −4 when read as signed. Choose the radix that matches what the signal means, and the picture will say the same thing you do.
In SystemVerilog
Section titled “In SystemVerilog”The rest of this section works with real modules and testbenches, first to see where unknown values come from and then to track down a wrong answer.
Three causes of an unknown value
Section titled “Three causes of an unknown value”A signal in a simulation can hold four values: 0, 1, X and Z. X is the value to worry about: it says that the simulator has no definite 0 or 1 to report. Lecture 2 lists X as unknown, uninitialized or contention (multiple drivers), and Z as floating, with no driver. (fact ch03/x-meanings) Three situations produce an X, and the cause decides the fix.
Nothing has given the signal a value. A signal starts as X, and stays that way until something assigns it. The common case in a testbench is an input that is never set. The testbench below never drives the upper bit of d.
// A testbench that forgets to drive the upper bit of d.module x_undriven_tb(); logic [1:0] d; logic [1:0] q;
x_undriven dut(.*);
initial begin d[0] = 1; #10; d[0] = 0; #10; $stop; endendmoduleThe book's checking tools reject this testbench, and the message below is their output. Your own simulator would run it, and d[1] would be unknown for the whole run, so the output bit computed from it by an inverter would be unknown too. An unknown does not always reach the output: a gate with a controlling input on another pin, such as an AND with a 0, gives a known value, so the X can be hidden for some input values. Do not count on that, and give every input a value.
hdl/ch03/s02/x_undriven_tb.sv:1:1: error: [tb-inputs-at-t0] the DUT input "d" is not assigned before the first timing control, so it is X at the start of the simulation (define every input at t = 0)The other common case is the state of a circuit that has memory, which holds an unknown value until it is reset. Figure 4.7.1 in Section 4.7 begins that way.
The section slides warn that Surfer shows a partly driven 10-bit output as all z in its default view, and that switching that signal to binary shows the bits that are driven. (fact ch03/surfer-zzz) That is a quirk of one viewer, not a cause of X. If a bus looks unknown or floating, display it in binary before deciding anything.
Two sources disagree. A signal driven by two different sources at once is in contention, and a simulator that allows it reports X for the clash. With every signal declared logic, as in this book, the tools refuse the design, so you meet this as an error message and not as a waveform:
// Does not compile: two continuous assignments drive the same signal.module two_drivers ( input logic a, input logic b, output logic y); assign y = a; assign y = b;endmodulehdl/ch03/s02/bad/two_drivers.sv:8:10: error: cannot have multiple continuous assignments to variable 'y' [-Wmultiple-cont-assigns]
assign y = b;
^
hdl/ch03/s02/bad/two_drivers.sv:7:10: note: also assigned here
assign y = a;
^The fix is to make sure every signal has exactly one source, such as one assign or one always_comb.
You wrote an X. A designer can write X on purpose. The decoder of Section 3.1 assigns 7'bX to its output for input codes that are not digits, and the hatched lane in Figure 3.1.4 is that choice, not a mistake. An X you wrote yourself is the only one of the three that is meant, and a waveform tells it apart from the others only by your knowing what the design says.
A debugging example
Section titled “A debugging example”Section 2.7 built a guessing game on a first-attempt comparator and tried six friendly guesses against a secret of 2. All six came out right. Here the same two modules, unchanged, are tried with every guess there is. The game compares a 3-bit guess with the secret, which is fixed in the design at 2, and the guess is a signed number. Its three lights are LEDR[2] for less, LEDR[1] for equal and LEDR[0] for greater, and they are on only while the check switch SW[3] is on. The comparison is done by a module that subtracts, then looks at the answer.
// A first attempt at a comparator for 3-bit signed numbers, built on subtraction.module compare3(input logic [2:0] a, b, output logic lt, eq, gt); logic [2:0] diff;
assign diff = a - b; assign eq = ~|diff; // every bit of the difference is 0 assign lt = diff[2]; // the difference looks negative assign gt = ~eq & ~lt;endmodule// A guessing game with a fixed secret. SW[2:0] is the guess and SW[3] says "check my guess".// LEDR[0] lights when the guess is greater than the secret, LEDR[1] when it is equal, LEDR[2] when it is less.module guessing_game(input logic [3:0] SW, output logic [2:0] LEDR); logic guess_lt, guess_eq, guess_gt;
compare3 judge(.a(SW[2:0]), .b(3'b010), .lt(guess_lt), .eq(guess_eq), .gt(guess_gt)); // the secret is 3'b010
assign LEDR[0] = guess_gt & SW[3]; assign LEDR[1] = guess_eq & SW[3]; assign LEDR[2] = guess_lt & SW[3];endmoduleThe testbench holds the check switch on and tries every guess, in binary order. It gives the three lights the names less, equal and greater, so that each has a lane of its own in the waveform.
// Plays all eight guesses against the secret in Section 2.7's game, with the check switch on.// The light outputs are named for what they mean: less is LEDR[2], equal is LEDR[1], greater is LEDR[0].module guessing_game_tb(); logic [2:0] guess; logic less, equal, greater;
guessing_game dut(.SW({1'b1, guess}), .LEDR({less, equal, greater}));
initial begin for (int i = 0; i < 8; i++) begin guess = i[2:0]; #10; end $stop; endendmoduleThe run is the waveform of Figure 3.2.1. Go through it the way you would go through a log.
Step 1: compare each output with what you expect. The eight guesses, in the order the testbench tries them, are 0, 1, 2, 3, then −4, −3, −2 and −1, because the bits 100 through 111 are the negative numbers. Against a secret of 2, the guesses 0 and 1 should give less, the guess 2 should give equal, and the guess 3 should give greater. The four negative guesses should all give less. In the figure, less is high in the first and second steps, equal is high in the third step, and greater is high in the fourth, fifth and sixth steps. That matches until the fifth step, where guess is 100, the number −4. There less is low and greater is high. The design says −4 is greater than 2. The sixth step, where guess is 101, the number −3, goes wrong in the same way. In the seventh and eighth steps less is high again, as it should be.
Step 2: look at the signal just before the output. greater is computed from less and equal, and less comes from the internal signal diff, so add diff to the waveform. That is the extra lane in the figure. In the fifth step, with guess equal to 100, the lane for diff reads 010, and in the sixth, with guess equal to 101, it reads 011. less is taken from the top bit of diff, which is 0 in both. So the design concluded that the difference is not negative.
Step 3: ask what the subtraction really did. The 3-bit signed range is −4 to 3. The exact difference −4 − 2 is −6, which does not fit. The subtraction keeps only 3 bits, so the result wraps around to 010, which is 2:
| 3-bit pattern | signed | |
|---|---|---|
| A | 100 | -4 |
| − B | 010 | 2 |
| = | 010 | 2 |
The guess −3 does the same: −3 − 2 is −5, which also does not fit, and the 3-bit result is 011.
| 3-bit pattern | signed | |
|---|---|---|
| A | 101 | -3 |
| − B | 010 | 2 |
| = | 011 | 3 |
Every signal in the figure has the value its own line of code says it should. The mistake is in the idea: the top bit of a difference tells you its sign only when the difference fits.
That is as far as this section can take the explanation. It shows where the wrong answer comes from: a true difference outside the range, cut to three bits. It does not yet say how a circuit can notice that a result does not fit, or what a correct comparator looks like. Section 4.3 treats two's complement arithmetic properly, and Section 4.4 fixes this comparator.
Step 4: find all the pairs that break. The secret was 2, so only two guesses expose the problem. Other secrets would expose others. The table has one row for every pair of a guess A and a secret B; the guess is the module's a and the secret is its b. FirstLt is what the module's less says, TrueLt is the right answer when both numbers are signed, and Wrong is 1 where they disagree. The 16 pairs where the module gets less wrong are highlighted. The exercises at the end of this section read their answers from this table.
| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
| 0 | 0 | 0 | 0 | 0 | 1 | 1 | 1 | 0 |
| 0 | 0 | 0 | 0 | 1 | 0 | 1 | 1 | 0 |
| 0 | 0 | 0 | 0 | 1 | 1 | 1 | 1 | 0 |
| 0 | 0 | 0 | 1 | 0 | 0 | 1 | 0 | 1 |
| 0 | 0 | 0 | 1 | 0 | 1 | 0 | 0 | 0 |
| 0 | 0 | 0 | 1 | 1 | 0 | 0 | 0 | 0 |
| 0 | 0 | 0 | 1 | 1 | 1 | 0 | 0 | 0 |
| 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 |
| 0 | 0 | 1 | 0 | 0 | 1 | 0 | 0 | 0 |
| 0 | 0 | 1 | 0 | 1 | 0 | 1 | 1 | 0 |
| 0 | 0 | 1 | 0 | 1 | 1 | 1 | 1 | 0 |
| 0 | 0 | 1 | 1 | 0 | 0 | 1 | 0 | 1 |
| 0 | 0 | 1 | 1 | 0 | 1 | 1 | 0 | 1 |
| 0 | 0 | 1 | 1 | 1 | 0 | 0 | 0 | 0 |
| 0 | 0 | 1 | 1 | 1 | 1 | 0 | 0 | 0 |
| 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
| 0 | 1 | 0 | 0 | 0 | 1 | 0 | 0 | 0 |
| 0 | 1 | 0 | 0 | 1 | 0 | 0 | 0 | 0 |
| 0 | 1 | 0 | 0 | 1 | 1 | 1 | 1 | 0 |
| 0 | 1 | 0 | 1 | 0 | 0 | 1 | 0 | 1 |
| 0 | 1 | 0 | 1 | 0 | 1 | 1 | 0 | 1 |
| 0 | 1 | 0 | 1 | 1 | 0 | 1 | 0 | 1 |
| 0 | 1 | 0 | 1 | 1 | 1 | 0 | 0 | 0 |
| 0 | 1 | 1 | 0 | 0 | 0 | 0 | 0 | 0 |
| 0 | 1 | 1 | 0 | 0 | 1 | 0 | 0 | 0 |
| 0 | 1 | 1 | 0 | 1 | 0 | 0 | 0 | 0 |
| 0 | 1 | 1 | 0 | 1 | 1 | 0 | 0 | 0 |
| 0 | 1 | 1 | 1 | 0 | 0 | 1 | 0 | 1 |
| 0 | 1 | 1 | 1 | 0 | 1 | 1 | 0 | 1 |
| 0 | 1 | 1 | 1 | 1 | 0 | 1 | 0 | 1 |
| 0 | 1 | 1 | 1 | 1 | 1 | 1 | 0 | 1 |
| 1 | 0 | 0 | 0 | 0 | 0 | 1 | 1 | 0 |
| 1 | 0 | 0 | 0 | 0 | 1 | 0 | 1 | 1 |
| 1 | 0 | 0 | 0 | 1 | 0 | 0 | 1 | 1 |
| 1 | 0 | 0 | 0 | 1 | 1 | 0 | 1 | 1 |
| 1 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 |
| 1 | 0 | 0 | 1 | 0 | 1 | 1 | 1 | 0 |
| 1 | 0 | 0 | 1 | 1 | 0 | 1 | 1 | 0 |
| 1 | 0 | 0 | 1 | 1 | 1 | 1 | 1 | 0 |
| 1 | 0 | 1 | 0 | 0 | 0 | 1 | 1 | 0 |
| 1 | 0 | 1 | 0 | 0 | 1 | 1 | 1 | 0 |
| 1 | 0 | 1 | 0 | 1 | 0 | 0 | 1 | 1 |
| 1 | 0 | 1 | 0 | 1 | 1 | 0 | 1 | 1 |
| 1 | 0 | 1 | 1 | 0 | 0 | 0 | 0 | 0 |
| 1 | 0 | 1 | 1 | 0 | 1 | 0 | 0 | 0 |
| 1 | 0 | 1 | 1 | 1 | 0 | 1 | 1 | 0 |
| 1 | 0 | 1 | 1 | 1 | 1 | 1 | 1 | 0 |
| 1 | 1 | 0 | 0 | 0 | 0 | 1 | 1 | 0 |
| 1 | 1 | 0 | 0 | 0 | 1 | 1 | 1 | 0 |
| 1 | 1 | 0 | 0 | 1 | 0 | 1 | 1 | 0 |
| 1 | 1 | 0 | 0 | 1 | 1 | 0 | 1 | 1 |
| 1 | 1 | 0 | 1 | 0 | 0 | 0 | 0 | 0 |
| 1 | 1 | 0 | 1 | 0 | 1 | 0 | 0 | 0 |
| 1 | 1 | 0 | 1 | 1 | 0 | 0 | 0 | 0 |
| 1 | 1 | 0 | 1 | 1 | 1 | 1 | 1 | 0 |
| 1 | 1 | 1 | 0 | 0 | 0 | 1 | 1 | 0 |
| 1 | 1 | 1 | 0 | 0 | 1 | 1 | 1 | 0 |
| 1 | 1 | 1 | 0 | 1 | 0 | 1 | 1 | 0 |
| 1 | 1 | 1 | 0 | 1 | 1 | 1 | 1 | 0 |
| 1 | 1 | 1 | 1 | 0 | 0 | 0 | 0 | 0 |
| 1 | 1 | 1 | 1 | 0 | 1 | 0 | 0 | 0 |
| 1 | 1 | 1 | 1 | 1 | 0 | 0 | 0 | 0 |
| 1 | 1 | 1 | 1 | 1 | 1 | 0 | 0 | 0 |
In the rows where B is 010, the secret of the game, only the guesses 100 and 101 are highlighted: the two steps of the waveform that went wrong. The equal output is never wrong, and one of the exercises asks why. The module is not repaired here.
Making a waveform that communicates
Section titled “Making a waveform that communicates”A waveform you send to someone else, in a report or a question, has to be readable without you in the room. Five habits help.
- Show the whole run, not a slice. If it does not fit on one screen, split it into consecutive pictures and say how they connect.
- Keep every signal name and every value legible. Shorten long hierarchical names to the last part of the path, and widen the panel before you shrink the text.
- Pick the radix that matches what the signal means: binary for a pattern of bits, decimal for a number, hexadecimal for a wide bus. Never leave a signed number in unsigned decimal.
- Show the signals that tell the story: the inputs, the outputs, and the internal signal that explains the surprise.
- Write about specific times in the text. "At the step where
guessis100,greateris high" is something a reader can check.
Course conventions
Section titled “Course conventions”How CSE 369 writes this
The viewers you use differ in their menus and their quirks, and this book describes none of them step by step. The figures here are drawn by the book's own tools and look different from either viewer.
Signed numbers use two's complement, with the most significant bit weighing a negative power of two. Chapter 4 develops that arithmetic; this section only needs the 3-bit range −4 to 3.
Pitfalls
Section titled “Pitfalls”Common pitfall
- Reading a bus in the wrong radix, such as taking the bits
100as 4 when the signal is a signed number. - Skimming past hatched or X values at the start of a waveform, or treating X as if it were 0. An X means the simulator has no value to report.
- Staring at the wrong output without adding the internal signals that produce it. Work backward from the wrong output until you reach the first signal whose value you cannot explain.
- Assuming that a subtraction of two -bit numbers fits in bits. Here the difference of two 3-bit signed numbers can be as large as 7 or as small as −7.
- Sharing a waveform with names missing, the time axis cut off, or values in a radix nobody can read.
Check your understanding
Section titled “Check your understanding”Take the quiz (5 questions)
You change a bus in the waveform viewer from binary to hexadecimal. What changes?
What number do the three bits 110 stand for, when read as a signed 3-bit number?
110 is 6. As a signed number the top bit weighs −4, so the value is −4 plus 2, which is −2. A value of −6 is a sign flipped onto the unsigned reading.A testbench declares logic en; and never assigns it, and the module under test has assign y = ~en;. What does y show in the waveform?
y. An X does not always spread this far: a controlling input can decide an output anyway, so X AND 0 is 0 and X OR 1 is 1. Initialize every testbench input rather than relying on that.The comparator of this section subtracts 3-bit patterns. For the guess 010 and the secret 101, what is diff?
010 minus 101 wraps around to 101. The pattern 011 is what you get by subtracting in the wrong order, 101 minus 010.In Figure 3.2.1, at the step where guess is 100, which statement is true?
100 in 3 bits gives 010, as the lane shows. greater is correctly computed from the two flags it is given. The error is in the idea that the top bit is the sign of the difference.Exercises
Section titled “Exercises”A tester tries the guess 3 against the secret −2, in the same 3-bit comparator. In bits these are 011 and 110. Without simulating, predict diff, and then say whether less is right.
Hint
Solution
Subtracting 110 from 011 in 3 bits gives 101:
| 3-bit pattern | signed | |
|---|---|---|
| A | 011 | 3 |
| − B | 110 | -2 |
| = | 101 | -3 |
The top bit of diff is 1, so the module reports less. But 3 is greater than −2, so the answer is wrong. The true difference is 5, which does not fit in the range −4 to 3, so the 3-bit result wrapped around to a pattern that looks negative.
Each description below produces an unknown value in a simulation. Say which of the three causes it is, and what you would change.
- A testbench declares
logic [3:0] data;and the module under test has a 4-bit inputdata, but no line of the testbench assigns it. - A
casestatement ends withdefault: out = 4'bX;, and the testbench tries a code that no other branch covers. - Two
assignstatements both drive the signalready.
Hint
Solution
- Nothing has given the signal a value, so
datais X from the start. Assigndatain the first line of the testbench's stimulus, before the first delay. - A designer wrote the X. The output for that code is unknown by design, which is correct only if the design does not care what that output is. If it does, give the code a real value or add a branch for it.
- Contention. Two sources drive
readyand the tools refuse the design. Keep one driver: combine the two conditions into oneassign, or onealways_comb.
The game is changed so that the secret is −1 (bits 111) instead of 2. Using the table of Example 3.2.1, find every guess whose less output is wrong, and explain the arithmetic.
Hint
B bits are 111 and whose Wrong column is 1.Solution
Among the rows where B2 B1 B0 are 111, only the row with A2 A1 A0 equal to 011 has a 1 in Wrong. So only the guess 3 is wrong. The subtraction there is 3 − (−1), which is 4, and 4 does not fit in the range −4 to 3. The result wraps to the pattern 100, whose top bit says "negative", so the module reports less for a guess that is greater than the secret.
| 3-bit pattern | signed | |
|---|---|---|
| A | 011 | 3 |
| − B | 111 | -1 |
| = | 100 | -4 |
In the table of Example 3.2.1 only less is compared with the right answer. Explain why the equal output is never wrong, and why greater is wrong for exactly the pairs where less is wrong.
Hint
greater from the other two flags?Solution
equal is 1 when all three bits of diff are 0. The 3-bit difference of two 3-bit patterns is 0 exactly when the patterns are the same, since the difference wraps around only by multiples of 8, and two different patterns differ by between 1 and 7 in unsigned value, never by 8. So equal is right for every pair.
greater is computed as "not equal and not less". For a pair that is not equal, greater is the opposite of less, so it is wrong exactly when less is wrong. For an equal pair both are 0 and less is right. So the pairs where less is wrong are the same pairs where greater is wrong.