Digital Design / Module 3: Verilog that means hardware
12. Modules, ports and hierarchy
Structure a design the way a chip is structured.
See it move
The idea
Verilog looks like a programming language, yet it describes a circuit. A module is a block of hardware with pins, not a function that gets called. Every instance exists permanently and runs at the same time as every other instance. Instantiating a module twice gives you two physical copies, and it costs twice the area.
module mux2(input a, b, sel, output y);
assign y = sel ? b : a;
endmodule
module mux4(input [3:0] d, input [1:0] s, output y);
wire lo, hi;
mux2 u_lo (.a(d[0]), .b(d[1]), .sel(s[0]), .y(lo));
mux2 u_hi (.a(d[2]), .b(d[3]), .sel(s[0]), .y(hi));
mux2 u_top(.a(lo), .b(hi), .sel(s[1]), .y(y));
endmoduleHere mux4 holds three real muxes. The order of those lines doesn't matter, since they all exist at once. The animation above shows the same two-level selection.
Hierarchy
Chips are built in layers: a core contains units, units contain blocks, and blocks contain small modules. A good boundary hides detail and makes a piece easy to test alone. Teams usually register outputs at the edges of large blocks, because this keeps timing paths from running across several blocks.
Named connections
Always connect ports by name, as above. With positional connections, adding a port or reordering one can silently rewire a design with no error at all. Named connections state exactly what goes where.
Common mistake
Thinking of instances as sequential steps, as if u_lo "runs before" u_top. Nothing runs first. Signals propagate through all the hardware continuously. Reading RTL from top to bottom as a program is the most common source of confusion for people arriving from software.
Key ideas
- A module is a block of hardware, not a function call.
- Use named port connections.
- Instances all exist at once and run in parallel.
Your exercise
Interview questions
coreNamed or positional port connection?
Named: reordering ports can't silently miswire it.
basicWhat is the difference between a module and an instance?
A module is the description of a block, like a drawing of a circuit with its pins. An instance is one physical copy of that block placed in a design. Each instance has its own hardware and runs at the same time as every other instance, so two instances cost twice the area.
basicA mux4 module contains three mux2 instances. A design instantiates mux4 four times. How many mux2 circuits end up in the hardware?
Twelve. Every instance is a full copy, so four mux4 instances each bring their own three mux2s: 4 × 3 = 12. Hierarchy organises the design but never shares hardware between instances.
coreIn the lesson's mux4, does u_lo run before u_top because it is written first?
No. All three instances exist at once and operate continuously. When an input changes, the new value travels through the wires and settles through each mux in turn, but that is signal propagation, not execution order. You could write the three lines in any order and get identical hardware.
coreA submodule's port list is reordered from (a, b, y) to (b, a, y). The parent connects by position, as shown. What happens?
module sub(input b, input a, output y); // was (a, b, y) assign y = a & ~b; endmodule sub u0 (x1, x2, o1); // positional
Nothing reports an error, but x1 now drives b and x2 drives a. With x1 = 1 and x2 = 0 the output was 1 before the change and is 0 after, because the module computes a & ~b. Named connections, .a(x1), .b(x2), .y(o1), would have kept the wiring correct.
coreThis compiles, but lo stays at z in simulation. Why, and how can you make the tool catch it?
wire lo; mux2 u_lo (.a(d0), .b(d1), .sel(s), .y(l0));
The port is connected to l0 (digit zero), not lo. Verilog quietly creates an implicit 1-bit wire called l0, so the mux drives that and nothing drives lo. Putting ` default_nettype none `` at the top of the file turns undeclared names into errors, and then the typo is reported at compile time.
coreAn 8-bit signal is connected to a 4-bit input port. Is that an error in Verilog?
No, it is legal. The connection behaves like an assignment, so the upper four bits are dropped and the port sees only the low four bits; going the other way, a narrow signal into a wide port is extended. Simulators and lint tools usually warn about the mismatch, which is why those warnings deserve attention.
advancedWhy do teams usually register the outputs of large blocks?
If a block's output comes straight from a flop, any timing path that leaves the block starts at a clean clock edge. The receiving block then gets almost a full cycle for its own logic, and each block can be timed and closed on its own. Without this, a path can run through logic in several blocks, and no single owner can fix it.
advancedTwo instances both drive their outputs onto the same wire bus. One drives 0 and the other drives 1. What does simulation show, and what does it mean?
drv ua (.v(v1), .y(bus)); // v1 = 0 drv ub (.v(v2), .y(bus)); // v2 = 1
bus shows x, because the wire resolves two strong opposite values to unknown. In hardware it means two outputs fighting, which wastes current and gives an undefined level. It only looks fine when both drivers happen to agree, so the bug can hide. Each net should have exactly one driver, or use a proper mux or tri-state scheme.