Anatomy Of A Verilog Project

July 23, 2026

FPGA + Verilog · Chapter 5 of 7

One design has three different roots: the hardware hierarchy you synthesize, the harness you simulate, and the physical contract you impose on a board.

The top module is not a magic filename. A testbench is not the circuit you ship. A constraints file is not Verilog. Keeping those roles separate removes a surprising amount of beginner confusion.

See the complete seven-chapter course

One counter module feeding a simulation path with a testbench and waveform checks and a hardware path with board constraints, synthesis, place-and-route, and a bitstream
Original Greenforest I/O diagram. The same design module answers two different questions: the testbench asks whether behavior is correct; constraints and implementation ask where the circuit lives and whether it meets physical and timing requirements.

Files Are Containers; Modules Form The Design

A Verilog file may contain one module, several modules, or only verification code. Tools care about the declarations they read and the root you select, not whether the filename happens to be top.v.

A small course project is easier to navigate when each role has a clear file:

counter-project/
├── counter.v          synthesizable design module
├── counter_tb.v       simulation top, stimulus, checks, VCD
├── board.pcf          board-revision pin bindings
├── timing.sdc         clock and timing intent, when the flow uses it
└── Makefile           repeatable simulation and build commands

The supplied lab has counter.v, counter_tb.v, and a Makefile. It intentionally does not pretend to have a universal board.pcf. Pin numbers, oscillator pins, reset polarity, LED polarity, package, and even the meaning of a board name depend on the exact board revision.

For a scratch experiment, putting the design module and the testbench module in one file is legal. Separation is an aid to reasoning and tooling, not a law of the language.

The Synthesis Top Is A Selected Hierarchy Root

The manuscript compares the top module with a software main() function. Keep that only as a rough navigation aid: the top is the root module selected for a particular tool run. It owns the ports at the boundary of the implemented design and instantiates any child modules below it.

In the counter lab, counter can be the synthesis top because its clk, reset, and count ports describe the entire hardware boundary. In a board build, a wrapper might instead become the top:

module board_top (
    input  wire       clock_100mhz,
    input  wire       reset_n,
    output wire [7:0] led
);
    wire [26:0] count;

    counter #(.WIDTH(27)) divider (
        .clk   (clock_100mhz),
        .reset (~reset_n),
        .count (count)
    );

    assign led = count[26:19];
endmodule

The wrapper translates board-facing names and polarity into the reusable counter’s small interface. It also selects slow counter bits so a human can see LEDs change. Whether the LED assignment must be inverted is a board fact, not a Verilog fact.

Yosys can be told which root to use—for example, through hierarchy -top board_top or a synthesis command’s -top option. The official Yosys hierarchy documentation describes that selection directly.

The Simulation Top Is Usually The Testbench

For the supplied Icarus run, counter_tb is the top because it has no external ports and contains the complete simulated world. It creates a clock, controls reset, instantiates counter as the design under test, waits for meaningful events, checks expected outputs, and ends the run.

A useful testbench has at least five responsibilities:

  1. Instantiate the design under test and connect every relevant port.
  2. Generate clocks, resets, transactions, and corner-case stimulus.
  3. Observe outputs at times that respect the simulator’s scheduling rules.
  4. Compare observations with explicit expectations and fail loudly on a mismatch.
  5. Preserve enough evidence—a message, assertion record, waveform, seed, or transaction log—to reproduce the result.

The harness does not have to be Verilog. It may be SystemVerilog, C++ around a Verilator model, cocotb with Python, or another foreign-language interface supported by the simulator. What makes it a testbench is the job it performs, not the file extension.

Name, not definition: “Verilog” was coined from verification and logic. That historical wordplay is worth remembering. It does not mean that every Verilog file is a testbench, and it does not make testbench structure the definition of the language.

Constraints Are The Physical And Timing Contract

When a design leaves simulation and targets an FPGA, its top-level port names must meet the package and board. For the open iCE40 flow, a PCF may bind a port such as clock_100mhz or led[0] to a package pin. That is the literal metal-pad connection the manuscript emphasizes.

But “constraints” is broader than pin binding. A serious implementation can also carry:

Different toolchains divide that information differently. A PCF is chiefly a physical pin-constraint format. An SDC carries timing intent. AMD/Xilinx XDC combines Tcl-based physical and timing constraints. In an iCE40 nextpnr command, a target clock frequency may also enter as --freq. Do not call all of these interchangeable merely because they all constrain implementation.

The Same Port Name Crosses Three Worlds

Take clk as an example. In the synthesizable module it is an input used by an edge-sensitive process. In the testbench it is a signal toggled by simulated time. On a board it must connect to the oscillator’s physical pin and receive an implementation clock requirement.

Design
input wire clk; state captures on a selected edge.
Simulation
The testbench toggles clk with delays and decides when to sample updated state.
Board
The top-level port binds to an oscillator pad; timing intent tells implementation what frequency the path must meet.

A passing behavioral test proves none of the board bindings, electrical standards, or timing closure. A clean place-and-route report proves none of your functional assertions. The two paths are complementary evidence.

The Manuscript’s Canonical Language Reference

The handwritten curriculum linked the same USC EE457 Verilog discussion three times: at the beginning, beside syntax, and beside the later subtleties list. It belongs once, here:

USC EE457 — Verilog Discussion (PDF)

Use that discussion for language reading, then use the concrete lab files for executable behavior. For normative SystemVerilog scope and terminology, consult the IEEE 1800 standard page. Later chapters link back here instead of duplicating the same external reference.

Exit Check

You understand the project anatomy when you can answer these without looking at a filename: Which module is the synthesis root? Which module is the simulation root? What generates the clock in each world? Which artifact connects a named LED port to a package pad? Where is the clock requirement stated? Which result demonstrates behavior, and which result demonstrates implementability?