FPGA

Surveys the core Verilog data types

By CourseTron Team ·  5 min read ·  Updated Oct 2026 💬 𝕏 in f
Table of Contents
    ? Print / Save as PDF

    In short: Verilog splits its data objects into two families — nets (like wire, driven continuously by hardware) and variables (like reg, integer, real, which hold a value until reassigned) — and only the subset you write in a synthesizable style actually maps to gates, flip-flops, or wires on silicon.

    Choosing the wrong data type is the single most common reason a Verilog design simulates perfectly but synthesizes into something unexpected — an unwanted latch, a truncated bus, or nothing at all. This guide walks through every core Verilog data type, explains the hardware each one represents, and shows exactly where the simulation model and the synthesized gate-level netlist diverge. Everything here maps to IEEE 1364 (classic Verilog) and carries straight into SystemVerilog.

    The Two Families: Nets vs Variables

    Verilog objects fall into two fundamentally different categories, and conflating them is where most beginner bugs start.

    • Nets model a physical connection. A net has no storage of its own — it continuously reflects whatever is driving it, exactly like a metal trace between cells. wire is the one you will use 95% of the time. Other net types (tri, wand, wor, supply0, supply1) exist for buses, tri-state, and power rails.
    • Variables (the LRM renamed them from "registers" to "variables" to stop the confusion) hold their last assigned value. reg, integer, real, time, and realtime are all variables. Crucially, a reg is not automatically a hardware register.

    A reg only becomes a flip-flop or latch if you assign it inside an edge- or level-sensitive always block that stores state. In pure combinational logic, a reg synthesizes to wires and gates — no storage element at all.

    Net (wire) vs variable (reg) NET (wire) VARIABLE (reg) driver load continuous, no memory assign drives it D FF Q holds value on clock edge always / initial drives it CourseTron · coursetron.com
    Nets carry a value continuously from driver to load; variables can retain a value across time, becoming storage when clocked.

    This distinction is the whole reason the reg vs wire question dominates Verilog interviews. The rule of thumb: assign with assign (continuous) → the target must be a net; assign inside always/initial → the target must be a variable.

    Vectors: Multi-Bit Buses

    Any net or variable becomes a vector by adding a range: wire [7:0] data; declares an 8-bit bus. The left index is the most-significant bit by convention. Vectors synthesize to parallel wires or a bank of flip-flops — one per bit.

    Two sizing traps bite everyone:

    • Truncation. Assigning a 10-bit result to an 8-bit vector silently drops the top 2 bits. Synopsys Design Compiler and Cadence Genus both issue a width-mismatch warning (e.g. TRUNC), but simulation won't error — so trust the lint, not the waveform.
    • Part-selects. data[3:0] picks a slice; data[i+:4] is an indexed part-select that synthesizes to a mux. Variable bit-selects with a non-constant index become multiplexers, which can be surprisingly large.

    integer, time, and real

    These are the convenience variables. They are legal in synthesizable code only in restricted ways:

    • integer is a signed 32-bit variable. It's perfect for for-loop counters that the synthesizer unrolls at elaboration — the loop variable never becomes hardware. If you drive a real output with an integer, it maps to a 32-bit bus.
    • time is a 64-bit unsigned variable meant for storing simulation timestamps from $time. It is a simulation-only construct — no synthesizer builds hardware from it.
    • real (and realtime) are IEEE-754 double-precision floating point. They exist for testbenches and behavioral models. No RTL synthesis tool turns real into gates — if you need fractional arithmetic in hardware you build fixed-point on vectors yourself.

    Rule to memorize: real and time are testbench-only. integer is synthesizable but behaves as a 32-bit signed vector, so use a sized reg when you care about exact width.

    How Each Type Synthesizes

    Data typeFamilySimulation meaningSynthesizes to
    wireNetContinuous value from driverInterconnect wire / combinational node
    reg (clocked)VariableHolds value, updated on edgeFlip-flop(s)
    reg (comb, full assign)VariableHolds value, updated on any inputGates / LUTs, no storage
    reg (comb, incomplete)VariableKeeps old valueUnintended latch ⚠️
    integerVariable32-bit signed counter32-bit bus / loop unrolled away
    real / timeVariableFloat / 64-bit timestampNot synthesizable
    tri / wandNetResolved multi-driverTri-state buffer / wired logic

    Animated: A Clocked reg Becoming a Counter

    The clearest way to see "variable becomes flip-flop" is to watch a clocked reg accumulate. Below, each rising clock edge latches the next count value — exactly what always @(posedge clk) q <= q + 1; builds.

    Clocked reg: q <= q + 1 clk edge 1 edge 2 edge 3 edge 4 q[1:0] 00 01 10 11 value latched on each rising edge CourseTron · coursetron.com
    A rising-edge pulse travels along the clock; on each edge the 2-bit variable q updates — the behavioral essence of a synthesized flip-flop bank.

    The Latch Trap

    If you write a combinational always block but forget to assign the output on every path — a missing else, or a case without default — the reg must "remember" its old value. The synthesizer honours this by inferring a transparent latch. Latches complicate timing closure and are flagged by every tool (Design Compiler's LATCH report, Genus warnings). The fix is to give every variable a default assignment at the top of the block. For a deeper treatment of avoiding inferred storage, see our guide to avoiding inferred latches.

    Combinational reg: latch or gates? Incomplete assignment if (en) q = d; (no else) Default assigned q = 0; if (en) q = d; d, en LATCH q q keeps its old value when en = 0 d, en gates q every path assigns q no storage element CourseTron · coursetron.com
    An incompletely assigned combinational reg infers a latch; giving it a default assignment keeps the logic purely combinational.

    If your work touches real tapeout flows rather than classroom examples, the design-services team at Avecas runs these same synthesis checks on production RTL every day — a useful reality check on how type discipline affects QoR.

    Want to go from "it simulates" to "it synthesizes cleanly"? The CourseTron RTL & FPGA track drills data-type discipline, latch avoidance, and real Synopsys/Cadence lint on hands-on labs.

    Frequently Asked Questions

    Is a Verilog reg always a hardware register?

    No. A reg is just a variable that can hold a value in simulation. It becomes a flip-flop only when assigned on a clock edge, a latch when combinational logic is incompletely specified, and plain gates when it drives fully-specified combinational logic.

    Can I synthesize real or floating-point in Verilog?

    Not directly. real is IEEE-754 double precision meant for testbenches and behavioral models. For hardware fractional math you implement fixed-point arithmetic on sized vectors, or instantiate a vendor floating-point IP core.

    When do I use wire versus reg?

    Use a wire (net) for anything driven by a continuous assign or a module output port connection. Use a reg (variable) for any signal assigned inside an always or initial block. SystemVerilog's logic type removes the choice in most cases.

    What happens if I assign a 12-bit value to an 8-bit vector?

    The upper 4 bits are silently truncated. Simulation will not error, but synthesis and lint tools issue a width-mismatch warning. Always size your left-hand side deliberately.

    Advertisement