Most lessons follow the same order, so you always know where you are.
Block | What it is for |
|---|---|
Why this matters | The problem the lesson solves, and what you can do after it. |
Predict first | A question asked before the answer or the run. Commit to an answer, then open it. |
Terminal | The output the simulator really printed when the example ran. |
Common pitfall and Interview | The mistake people make, and how the idea is asked in interviews. |
Check yourself | A question after the idea, to test that it stuck. |
Project step | One optional piece of the PacketFIFO project that uses this lesson. |
Remember | Three lines to keep. The part hubs collect them into a revision sheet. |
How this was checked | Collapsed. Which simulator ran the example, and what the run does not prove. |
A complete example has a design and a testbench in one listing. Its code block has an Open in Code Lab button that copies it into the editor, where you pick a simulator and run it.
Simulator | Use it for |
|---|---|
Icarus Verilog 13 | Plain Verilog, and examples that show X values (it models 0, 1, X and Z). |
Verilator 5.048 | Classes, randomization, assertions and most SystemVerilog. It models only 0 and 1, so X shows as 0. |
Each listing that needs a particular simulator says so. When neither free simulator can run a listing, the lesson says what is missing, and it never shows invented output.
Every runnable testbench in the course ends the same way: one line that starts with PASS or FAIL. The FAIL branch uses $fatal, which also makes the simulator exit with an error status, so a script running many tests sees the failure too.
module majority3 (
input wire a,
input wire b,
input wire c,
output wire y
);
assign y = (a & b) | (a & c) | (b & c);
endmodule
module tb_majority3;
reg a, b, c;
wire y;
integer i;
integer errors = 0;
majority3 dut (.a(a), .b(b), .c(c), .y(y));
initial begin
for (i = 0; i < 8; i = i + 1) begin
{a, b, c} = i[2:0];
#1;
if (y !== ((a + b + c) >= 2)) begin
errors = errors + 1;
$display(" mismatch: a=%b b=%b c=%b y=%b", a, b, c, y);
end
end
if (errors == 0) $display("PASS: majority3 matched the reference on all 8 inputs");
else $fatal(1, "FAIL: majority3 differed on %0d of 8 inputs", errors);
$finish;
end
endmodulePASS: majority3 matched the reference on all 8 inputsVerilator printed this, and exited with status 0:
PASS: majority3 matched the reference on all 8 inputs
- majority3.sv:27: Verilog $finishA testbench that cannot fail proves nothing. So the course often asks you to plant a bug and run again. Here, change (a & c) to (a | c) in the design.
Two. a | c is 1 whenever a or c is 1. It only changes the answer when exactly one of a and c is 1 and b is 0: inputs 001 and 100.
With the planted bug, Verilator printed this and exited with status 1:
mismatch: a=0 b=0 c=1 y=1
mismatch: a=1 b=0 c=0 y=1
[8] %Fatal: majority3.sv:26: Assertion failed in tb_majority3: FAIL: majority3 differed on 2 of 8 inputs
%Error: majority3.sv:26: Verilog $stop
Aborting...No. A missing verdict is a failure: the run crashed, hung or ended early. Only a PASS line, with an exit status of 0, counts as a pass.
Run with Icarus Verilog 13 (iverilog -g2012) and Verilator 5.048 (--binary --timing) on 2026-10-18; both printed the PASS line shown, with no warnings.
The planted bug ((a | c) in place of (a & c)) was run on Verilator 5.048: it printed the two mismatches and the $fatal line shown, and exited with status 1. Icarus 13 reported the same two mismatches.