Seyed Masoud Hosseini · Overview · Study log · Weekly summaries · Ideas · Search · Transcript · RSS feed
FPGA & Verilog Design · Lecture 7 of 12 · 27:03
Part 7: Verilog Testbenches and Simulation
Study guide
What this lecture covers
This lecture answers how to verify a Verilog design without uploading it to real hardware every time. It uses the clock divider module from Part 6 as a running example, building a test bench that drives its inputs, simulating it with Icarus Verilog, and inspecting the results as waveforms in GTKWave.
By the end you can write a test bench with an internal clock generator and a reset pulse, dump signal changes to a .vcd file, and read a waveform viewer closely enough to catch a genuine off-by-one bug in the clock divider's max-count parameter - which the lecture deliberately left unfixed in Part 5 to demonstrate here. It ends with a challenge to simulate the button-debounce design from Part 5.
Key ideas
- Unit under test (UUT): the module being verified, instantiated inside the test bench just like it would be in a top-level design, but with no physical pins involved.
- Test bench code doesn't need to be synthesizable: constructs like delays (
#),initialblocks, and system tasks ($dumpfile,$finish) are valid for simulation but have no hardware equivalent. - `
timescale ``: a compiler directive setting the time unit and precision used for delays in the test bench, analogous to setting the time-axis resolution on an oscilloscope. - Simulated clock generation: since there's no physical oscillator in simulation, the test bench toggles a clock register in a loop using delays to approximate the target frequency.
- Value change dump (
.vcd):$dumpfileand$dumpvarsrecord how signals change over the simulation run, viewable afterward in GTKWave. - apio's
_tbconvention:apio simlooks for a file ending in_tb.vto identify the test bench and runs Icarus Verilog and GTKWave automatically. - Finding the bug: measuring the divided clock's period in GTKWave showed it was longer than intended, revealing that the max-count parameter needed a
- 1because the counter starts at zero.
Walkthrough
Why simulate before using real hardware (1:12)
The lecture explains that synthesizing and uploading a design takes time, and that observing real hardware at megahertz speeds requires equipment like an oscilloscope or logic analyzer. Simulating a module with a test bench and viewing the output in a waveform viewer is presented as a faster, cheaper way to catch bugs.
Structuring the test bench module (6:55)
The test bench for the clock divider module has no ports, since everything is internal. It declares registers for clock and reset (so they can be driven directly) and a wire for out, and sets initial values for the clock and reset registers - something only valid in simulation.
Generating a clock and pulsing reset (8:33)
An always block with no sensitivity list toggles the clock register every ~41.67 ns to approximate a 12 MHz signal, using the # delay syntax. A separate initial block pulses the reset line high briefly near the start of the simulation, running concurrently with the clock-generation block.
Instantiating the unit under test with scaled-down parameters (11:12)
The clock divider is instantiated as uut, overriding its count_width and max_count parameters to much smaller values than real hardware would use, so the simulation only needs to run a manageable number of clock cycles instead of waiting for a full-scale divide ratio.
Dumping signals to a VCD file (14:15)
$dumpfile names the output .vcd file, and $dumpvars(0, ...) records every signal in the test bench and all instantiated modules beneath it. A fixed simulation duration and $finish ensure the simulation stops instead of running indefinitely.
Debugging with GTKWave (19:59)
After running apio sim, the lecture loads the clock, counter, reset, and divided-output signals into GTKWave, uses markers to measure the divided clock's period, and finds it's longer than the intended 500 ns. Because the counter starts at zero, the max-count parameter needs to be one less than expected; adding - 1 and re-simulating confirms the fix.
Before you watch
- Complete Part 6 ("Verilog Modules and Parameters"), since this lecture tests the same clock divider module built there.
- Recall the finite state machine from Part 5; its clock-divider timing bug is the one diagnosed in this lecture.
Check your understanding
- Why can test benches use constructs like delays and
initialblocks that wouldn't be valid in synthesizable code? - How does the test bench generate an approximate 12 MHz clock without real hardware?
- What does
$dumpvars(0, ...)do, and how would using1instead of0change what gets recorded? - Why does apio require a test bench file to be named with a
_tbsuffix? - What was the actual bug found in the clock divider, and why did the counter starting at zero cause it?
Vocabulary
- test bench (noun)
- Code written to simulate and verify a design's behavior without real hardware.
The test bench drives the clock divider's inputs during simulation. - unit under test (UUT) (noun)
- The specific module being verified inside a test bench.
The clock divider is instantiated as the unit under test. - synthesizable (adjective)
- Able to be turned into a real hardware circuit, not just simulated.
Delay statements are valid in a test bench but not synthesizable. - compiler directive (noun)
- An instruction to the compiler that isn't part of the actual hardware logic.
The timescale directive sets the simulation's time resolution. - initial block (noun)
- A Verilog block that runs once at the start of simulation.
An initial block sets the starting values for the clock and reset. - waveform (noun)
- A visual graph showing how a signal's value changes over time.
GTKWave displays the signal changes as a waveform. - value change dump (VCD) (noun)
- A file format that records how signals change throughout a simulation.
The test bench writes its results into a VCD file. - off-by-one bug (phrase)
- An error caused by a count being one higher or lower than it should be.
The clock divider had an off-by-one bug in its max-count value. - marker (noun)
- A tool in a waveform viewer used to measure time between two points.
Markers in GTKWave measure the divided clock's period. - logic analyzer (noun)
- A tool that captures and displays multiple digital signals over time from real hardware.
A logic analyzer could show the same signals on real hardware. - verify (verb)
- To check that something works or is correct.
Simulation is a fast way to verify a design before uploading it. - convention (noun)
- A commonly agreed way of naming or doing something.
apio's naming convention expects a file ending in _tb.v. - precision (noun)
- The level of exactness or fine detail in a measurement.
The timescale directive sets the simulation's time precision. - analogous (adjective)
- Similar in a useful way to something else already known.
Setting the timescale is analogous to setting an oscilloscope's resolution. - approximate (verb)
- To get close to an exact value without matching it perfectly.
The test bench toggles a register to approximate a 12 MHz clock. - override (verb)
- To replace a default value with a different one for a specific case.
The test bench overrides the module's default parameters. - scaled-down (adjective)
- Made smaller than the real version to keep things manageable.
The simulation uses scaled-down parameters to run faster. - indefinitely (adverb)
- Without any planned end point.
Without $finish the simulation would keep running indefinitely. - diagnose (verb)
- To find the exact cause of a problem.
GTKWave helps diagnose the off-by-one timing bug. - genuine (adjective)
- Real and not a mistake or false alarm.
The lecture catches a genuine bug in the clock divider. - port (noun)
- An input or output connection point of a module.
The test bench module has no ports since everything is internal. - internal (adjective)
- Existing inside something rather than connecting to the outside.
The test bench uses only internal signals, with no physical pins. - cost-effective (adjective)
- Giving good results without spending too much time or money.
Simulation is a cheaper, more cost-effective way to catch bugs. - manageable (adjective)
- Easy enough to handle or control.
Smaller parameters keep the simulation to a manageable length. - equipment (noun)
- The tools or devices needed to do a task.
Observing real hardware at high speed requires expensive equipment.
Chapters
- 0:00 <Untitled Chapter 1>
- 1:12 Test Benches in Verilog
- 3:17 Loading the Dump File in a Waveform Viewer
- 6:55 Internal Wires and Registers
- 7:15 Setting an Initial Value Clock and Reset
- 8:33 Clock Signal
- 9:24 Delay in Verilog
- 11:12 Parameters
- 19:59 Reset Signal
From the YouTube description
A field-programmable gate array (FPGA) is an integrated circuit (IC) that lets you implement custom digital circuits. You can use an FPGA to create optimized digital logic for things like digital signal processing (DSP), machine learning, and cryptocurrency mining. Because of the FPGA’s flexibility, you can often implement entire processors using its digital logic. You can find FPGAs in consumer electronics, satellites, and in servers used to perform specialized calculations.
In this series, we will see how an FPGA works and demonstrate how to create custom digital logic using the Verilog hardware description language (HDL).
Previously, we showed how to create modules in Verilog and use parameters to change the functionality of instantiated modules (https://youtu.be/0BKyiY8R5NU). We’ll build on those concepts in this video, where we demonstrate how to create a testbench in Verilog, simulate the design with Icarus Verilog (iverilog), and view the output waveform with GTKWave.
The solution to the challenge at the end of the episode can be found here: https://www.digikey.com/en/maker/projects/introduction-to-fpga-part-7-verilog-testbenches-and-simulation/1b741d1b8b864afeacbe28075b1427cd
All code examples and solutions for this series can be found here: https://github.com/ShawnHymel/introduction-to-fpga
Uploading your design to a real FPGA can sometimes take a while (especially for larger designs and denser FPGAs). Additionally, to check the timing and operation for fast-changing signals (think RAM bus or USB signals), you would need other specialized test equipment, such as a logic analyzer. Connecting all of the FPGA pins to a logic analyzer can also be a time-consuming processor.
To save us time, we can write Verilog code that tests our design (known as a “testbench”). We use a special simulation program (Icarus Verilog, in our case) to run the testbench code. The testbench code should instantiate the module(s) under test (often called a “unit under test” or “uut”) and toggle the necessary input lines.
The simulation will run our testbench, and it will log all how and when the various signals/wires change in the design. It will store this log in a “value change dumpfile” (.vcd). We can use a waveform viewer, such as GTKWave, to visualize these changes. The waveforms should look similar to what you might find on a logic analyzer.
Your challenge is to create a Verilog testbench for your button debouncing code from episode 5. You are welcome to use my solution to that challenge as a starting point (https://github.com/ShawnHymel/introduction-to-fpga/tree/main/05-finite-state-machines/solution-button-debouncing). Note that you might need to make some changes to the original code to allow for passing parameters to the design.
Product Links:
https://www.digikey.com/en/products/detail/lattice-semiconductor-corporation/ICE40HX1K-STICK-EVN/4289604
Related Videos:
https://www.youtube.com/watch?v=z8Oldd-nrfs
https://www.youtube.com/watch?v=5kNXX67mchE
https://www.youtube.com/watch?v=iwcxLQ6AB88
Related Project Links:
https://www.digikey.com/en/maker/projects/introduction-to-fpga-part-7-verilog-testbenches-and-simulation/1b741d1b8b864afeacbe28075b1427cd
Related Articles:
https://www.digikey.com/en/pdf/r/renesas-electronics-america/powering-fpga-applications
https://www.digikey.com/en/videos/d/dsp/edge-machine-deep-learning-on-fpga
Learn more:
Maker.io - https://www.digikey.com/en/maker
Digi-Key’s Blog – TheCircuit https://www.digikey.com/en/blog
Connect with Digi-Key on Facebook https://www.facebook.com/digikey.electronics/
And follow us on Twitter https://twitter.com/digikey
← Part 6: Verilog Modules and Parameters · Part 8: Memory and Block RAM →
