1. The requirement comes first; the design implements it and the testbench checks it
Hardware design and verification connect three things: requirements that specify the behavior, design code that implements it as a circuit, and a testbench that drives inputs and compares outputs with expected values. The circuit being checked is the DUT, the design under test.
| Role | What it does | The question it answers |
|---|---|---|
| Requirement | fixes the inputs, the outputs and the cycle-by-cycle behaviour in words | what has to be built |
| DUT | describes the requirement as a circuit | how it is built |
| Testbench | generates clock and reset, drives the inputs, observes the outputs against expected values, and stops the simulation when done | whether it behaves as required |
The testbench's expected values are computed from the requirement, never from the DUT's code. Write both from the same misunderstanding and the test passes while the design is wrong.
Note. How a testbench is written differs by language, and each language path writes the real code.
In Verilog it is a module of initial blocks and system tasks; in BSV, testbench rules that drive
inputs and print results; in Chisel, a Scala test that sets inputs with poke, advances an edge with
step and reads outputs with peek or expect. This unit covers the roles only, without syntax.
2. Distinguish compilation, elaboration, simulation and synthesis
These four tasks expose different kinds of problems. Tools may combine compilation and elaboration, and synthesis is a separate path to a hardware implementation, not a mandatory step after simulation.
| Stage | What it does | What surfaces here |
|---|---|---|
| Compile | checks syntax and types and builds an internal representation | syntax errors, type errors, undeclared names |
| Elaborate (generate) | expands module instances and fixes parameters and widths | unconnected ports, mismatched widths |
| Simulate | advances time in the order the testbench dictates and computes values | outputs that differ from the requirement, runs that never end |
| Synthesize | maps the circuit onto gates or FPGA resources | constructs that cannot be synthesized, timing |
This site runs simulation and nothing beyond it: Verilog with Icarus Verilog 11, BSV with bsc 2026.01, Chisel with Chisel 6.7.0, chiseltest 6.0.0 and firtool 1.154.0. Gate-level or FPGA technology mapping is not run. A successful execution means that the requested command completed; it does not prove that every requirement was checked. Read the assertions and observations to see what was tested. Whether the design can be synthesized is a separate question.
When an execution does not give the expected result, distinguish these four kinds of problem.
| Outcome | Meaning | Where to look first |
|---|---|---|
| Compile error | the compile or elaborate stage stopped; no simulation started | the file and line in the message |
| Run-time error | the simulation started but did not finish normally | the simulator's last output |
| Test mismatch | the simulation finished and an output differs from the expectation | the first differing cycle |
| Result not received | the request failed or the response could not be received | check the displayed service or connection error before retrying |
Check
A Bool value is assigned to a 4-bit signal and the tool reports a type error. Which stage reports it?
3. Cases come in three kinds: normal, boundary and reset
A requirement is turned into test cases. One case is an input sequence, the output expected for it, and the sentence of the requirement that expectation comes from. Sorting cases into three kinds shows where the gaps are.
| Kind | Meaning |
|---|---|
| Normal | the everyday behaviour the body of the requirement describes |
| Boundary | where the rule changes shape: the maximum, the wrap, two inputs at 1 in the same edge |
| Reset | the starting value and the return to it |
The requirement for counter4 reads: "A 4-bit counter. At an edge where clear is 1, q becomes 0.
With clear at 0 and enable at 1, q increases by 1, and 0 follows 15. With both at 0, q holds.
The starting value is 0." Those sentences give this table.
| Case | Kind | Inputs | Expected q | Why |
|---|---|---|---|---|
| Starting value | reset | before the first edge | 0 | "the starting value is 0" |
| Count once | normal | clear 0, enable 1 for one cycle | 1 | "increases by 1" |
| Hold | normal | from q = 1, enable 0 for two cycles | 1 | "with both at 0, holds" |
| Wrap | boundary | enable 1 for sixteen cycles | 0 | "0 follows 15" |
| Clear while counting | reset | from q = 5, clear 1 for one cycle | 0 | "where clear is 1, 0" |
| Clear and enable together | boundary | both 1 for one cycle | 0 | the clear sentence applies before the enable sentence |
| Count again after clear | normal | clear 0, enable 1 for one cycle | 1 | "increases by 1", from 0 |
The table below packs the wrap and a clear during counting into one input sequence. In cycles 0 to 15
only enable is 1, so q climbs by one and the edge of cycle 15 produces the value after 15. Cycle 17
is an edge, in the middle of counting, where clear and enable are both 1. Write q after every edge.
Predict, then compare · counter4
Fill in each cell before comparing. Empty cells count as a mismatch.
| Cycle | clearinputs sampled at the edge | enableinputs sampled at the edge | qafter the edge |
|---|---|---|---|
| 0 | 0 | 1 | |
| 1 | 0 | 1 | |
| 2 | 0 | 1 | |
| 3 | 0 | 1 | |
| 4 | 0 | 1 | |
| 5 | 0 | 1 | |
| 6 | 0 | 1 | |
| 7 | 0 | 1 | |
| 8 | 0 | 1 | |
| 9 | 0 | 1 | |
| 10 | 0 | 1 | |
| 11 | 0 | 1 | |
| 12 | 0 | 1 | |
| 13 | 0 | 1 | |
| 14 | 0 | 1 | |
| 15 | 0 | 1 | |
| 16 | 0 | 1 | |
| 17 | 1 | 1 | |
| 18 | 0 | 0 |
4. A weak test is strengthened by adding boundary cases
Here is the sequence of a testbench for counter4.
clear = 1, enable = 0 for one cycle → check q == 0 clear = 0, enable = 1 for three cycles → check q == 3 enable = 0 for one cycle → check q == 3 finish
A design can pass all three checks and still violate the requirement. This test never takes q past
3 and never has an edge with clear and enable both 1, so a counter that stops at 15 passes, and so
does one that lets enable win over clear. Strengthening the test means putting the boundary cases
from the table into the sequence: clear to 0, then apply sixteen cycles with clear = 0 and
enable = 1 before checking q == 0. Also add an edge with both inputs at 1 followed by a check for
q == 0.
Play the testbench yourself on the model below. First press the five edges of the weak test exactly
as written and confirm that q is 3. Then leave only enable at 1 and press sixteen more edges to find
the row where q returns to 0, and finally set clear and enable both to 1 and press one edge to
see the row where q is 0. The rows after the weak test ends are the cases it was missing.
Concept experiment · counter4
A browser model of the circuit, not a compiled design. The real toolchain runs in the examples.
Inputs
Outputs
- q
- 0
No edge has happened yet. Set the inputs, then apply a clock edge.
Check
Which case does the test above not check?
5. From the first mismatch to a likely cause
When the simulation finishes and an output differs from the expectation, work in this order.
| Step | What to do |
|---|---|
| 1 | find the first cycle that differs |
| 2 | confirm, in the waveform or the printed output, what inputs the DUT saw at that edge |
| 3 | write down which sentence of the requirement should have applied to those inputs |
| 4 | list the causes that could produce the observed value, and cross out those the input check rules out |
Caution. What the testbench sent and what arrived at the DUT's port can differ. With a wrong port
connection the testbench believes it drove enable = 1 while the DUT saw 0. Step 2 checks the value at
the DUT's port.
Check
From the starting value 0, the testbench drove clear = 0 and enable = 1 for three cycles, yet q is still 0. In the waveform the DUT's clear port was 0 at all three edges. Which is the likely cause?
6. Variation: cases from the requirement of a rising-edge detector
The same method applies to the cycle-based rise-detect model from the previous chapter, with inputs
held constant during each cycle. Its requirement: "Each time in goes
from 0 to 1, rise is 1 for exactly one cycle, and otherwise 0."
| Case | Kind | Inputs | Expected rise |
|---|---|---|---|
| One rise | normal | in 0, 0, 1, 0 | 1 in cycle 2 only |
| Held high | boundary | in 1 for five cycles | 1 in the first of them only |
| 1 from the first cycle | reset | in 1 in cycle 0 | 1 in cycle 0 (prev starts at 0) |
| Two rises | normal | in 1, 0, 1 | 1 in cycles 0 and 2 |
A test without the "held high" case passes a design that wires rise straight to in.
Check
in goes from 0 to 1 and then stays 1 for five cycles. In how many of those five cycles is rise 1?
7. Summary
- The requirement comes first. The DUT implements it, and the testbench checks the DUT against expectations computed from the requirement.
- Compilation, elaboration, simulation and synthesis have different purposes. This site runs compile and simulation commands, not gate-level or FPGA technology mapping.
- When a result is wrong or missing, distinguish compile errors, run-time errors, test mismatches and service or connection failures. Normal completion alone does not prove correctness.
- Cases are sorted into normal, boundary and reset, and a weak test gains boundary cases.
- A mismatch is traced from the first differing cycle: confirm the inputs at the DUT's port, then cross out causes.
This ends the fundamentals. Choose BSV, Verilog or Chisel and start the first chapter of that course. Each course introduces the DUT and testbench with executable code.