In short: Use reg for any signal you assign inside a procedural block (always/initial) and wire for anything driven by a continuous assign or a module/gate output — the keyword chooses the assignment mechanism, not whether the hardware is a flip-flop.
Ask a fresh RTL engineer to explain the difference between reg and wire and you will usually hear "reg is a register and wire is a wire." That answer is wrong often enough to cause real bugs, and it is one of the most common ways candidates trip in a VLSI interview. The two keywords are not about storage elements in silicon at all — they are about how a net gets its value in the Verilog language. This article untangles the two so you stop fighting your simulator and start reading synthesis results correctly.
Two different value-resolution models
Verilog splits objects into two families. A net type (wire, tri, wand, wor…) models a physical connection with no storage: its value is continuously recomputed from whatever is driving it, exactly like a metal wire that always reflects the voltage of its driver. A variable type (reg, integer, real, time) holds the last value written to it until the next procedural write, like a memory location in the simulator's data structure.
The crucial consequence: a wire must have a driver, and if two drivers disagree you get a resolved value such as x or z. A reg has exactly one writer domain at a time and simply retains its bits. This is why the LRM calls them "nets" and "variables" — the names reg and wire are historical baggage.
Key fact: A reg does not imply a flip-flop. always @(*) y = a & b; declares y as reg, yet Synopsys Design Compiler and Cadence Genus both synthesise it to a plain AND gate — pure combinational logic, zero sequential cells.
Which one do I declare? The decision rule
The choice is mechanical and admits no exceptions in Verilog-2001:
- Assigned inside a procedural block (
always,initial, task, function)? → it must bereg. - Driven by a continuous
assign, a primitive gate, or a module instance output? → it must be awire. - Any module port can be read as a
wireon the input side; anoutputis awireunless you assign it procedurally, in which case declareoutput reg.
Storage vs connectivity, seen in motion
The clearest way to feel the difference is to watch a value propagate. A wire tracks its driver with (in simulation) zero delay — change the source and the wire follows instantly. A reg written with a non-blocking assignment in a clocked block only updates on the active clock edge, then holds. The animation below shows a bit riding a continuous net straight through, versus the same bit having to wait for the clock to latch into a register.
Side-by-side summary
| Aspect | wire (net) | reg (variable) |
|---|---|---|
| Assigned by | assign, gate, instance output | always, initial, task/function |
| Value model | continuously re-driven; no memory | holds last written value |
| Multiple drivers | allowed; value is resolved (may be x/z) | last write wins; multi-driver is a race/error |
| Default value | z (high-impedance) | x (unknown) |
| Synthesises to | net / interconnect | combinational or sequential, per block style |
Key fact: Whether a reg becomes a flip-flop is decided by the sensitivity list and coding style: always @(posedge clk) infers a register; always @(*) that writes the variable on every path infers combinational logic. Miss a branch in the combinational block and the tool infers an unintended latch — a classic lint warning in Siemens Questa and Synopsys SpyGlass.
A worked example
Consider a 2-to-1 mux written two legal ways:
- Continuous:
wire y; assign y = sel ? a : b;—yis a net, re-evaluated wheneversel,a, orbchanges. - Procedural:
reg y; always @(*) y = sel ? a : b;—yis a variable because it is written inside the block, but it still synthesises to the same mux gate.
Same gates, different keyword. The moment you wrap the assignment in always @(posedge clk) and switch to y <= sel ? a : b;, the identical reg now infers a D flip-flop. The keyword never changed — the timing model did. SystemVerilog resolved this confusion by introducing logic, which can be driven either procedurally or by a single continuous assign, so most modern RTL simply uses logic and lets the compiler check driver legality. If your training targets classic Verilog or legacy IP, the reg/wire rule above is still exactly what you need.
For a broader tour of every Verilog object family, see our deeper write-up on Verilog data types, and if timing is where you keep getting stung, read blocking vs non-blocking assignments. When you are ready to put this into a full synthesis-to-GDS flow, our hands-on VLSI courses walk through it on real tools. Teams that need the RTL built and taped out for them can also look at Avecas's silicon design services.
Want interview-ready RTL fluency? CourseTron's RTL Design & Verilog track turns rules like this into muscle memory with graded labs on industry simulators — explore the curriculum.
Frequently asked questions
Does reg always create a flip-flop in hardware?
No. reg only means the signal is assigned procedurally. Whether it becomes sequential logic depends on the block: a clocked always @(posedge clk) infers flip-flops, while a fully-specified always @(*) infers combinational gates.
Can I use assign on a reg?
Not in standard Verilog. A continuous assign targets a net, so its left-hand side must be a wire. Trying to continuously assign a reg is a compile error in Synopsys VCS, Cadence Xcelium, and Siemens Questa alike.
Why does SystemVerilog have logic then?
logic is a single 4-state type that may be written procedurally or by one continuous driver, eliminating the need to pick reg vs wire upfront while still catching illegal multiple drivers at elaboration. It cannot model a resolved multi-driver bus — use a net type like wire for that.
What is the default value of each?
An undriven wire floats at z (high impedance); an unwritten reg sits at x (unknown). Seeing x on a signal at time 0 is a strong hint it is an uninitialised variable.