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:
- Instantiate the design under test and connect every relevant port.
- Generate clocks, resets, transactions, and corner-case stimulus.
- Observe outputs at times that respect the simulator’s scheduling rules.
- Compare observations with explicit expectations and fail loudly on a mismatch.
- 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:
- clock definitions, periods, waveforms, and generated-clock relationships;
- I/O standards, drive strength, slew, input and output delays;
- timing exceptions such as false paths and multicycle paths;
- placement regions or fixed resource locations; and
- tool- and device-specific implementation directives.
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.
input wire clk; state captures on a selected edge.clk with delays and decides when to sample updated state.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?