Skip to content
VLSI Mentor

Verilog · Chapter 5 · Foundations

Variables & Data Types in Verilog

Chapter 4 taught you to read Verilog source as text. This chapter is about what the declarations in that text actually mean. Every signal you declare belongs to one of two families — a net, which is driven by something else, or a variable, which is assigned by procedural code — and that single distinction explains most of the rules you will meet. It also clears up the most damaging misconception in the language: the word reg does not mean register, and declaring something reg does not create a flip-flop. You will learn what a declaration tells you about width, values and signedness, and, just as importantly, what it deliberately leaves undecided about the hardware.

Foundation21 min readVerilogData TypesNetsVariablesVectors

Chapter 5 · Page 2.1 · Data & Variables

1. What a Declaration Actually Tells You

Here are two declarations:

Azvya Education Pvt. Ltd.VLSI Mentor
two declarations
wire       ready;
reg  [7:0] count;

A reasonable first reading is: ready is a wire on the chip, and count is an 8-bit register.

The first half is roughly right. The second half is wrong, and it is the single most expensive misunderstanding a Verilog beginner can carry forward.

A declaration tells you three things:

  • Which family the signal belongs to — net or variable.
  • How wide it is.
  • How its value may be given to it — driven, or assigned.

It does not, on its own, tell you what hardware you get. That comes from what the rest of the code does with the signal. Hold on to this, because the whole chapter is built on it:

A declaration says what kind of thing a signal is. It does not say what hardware it becomes.

2. The Two Families — Nets and Variables

Every Verilog signal is either a net or a variable.

Azvya Education Pvt. Ltd.VLSI Mentor
one of each
wire       y;        // a net      — something else drives it
reg        q;        // a variable — procedural code assigns it

The difference is about how a value gets there:

  • A net is driven. It carries whatever its driver puts on it, continuously. A wire on its own holds nothing — remove the driver and it floats.
  • A variable is assigned. Procedural code inside an always or initial block writes it, and it keeps that value until something writes it again.

That is the rule that decides which keyword you need:

You want to…UseBecause
drive it with a continuous assigna net (wire)assign connects a driver to a net
drive it from a module or gate outputa net (wire)the instance is the driver
assign it inside always or initiala variable (reg)procedural assignment needs a variable

And it explains the two errors every beginner meets once: you cannot put a wire on the left of an assignment inside an always block, and you cannot put a reg on the left of a continuous assign.

3. wire — Driven by Something Else

Azvya Education Pvt. Ltd.VLSI Mentor
wire.v
wire y;

assign y = a & b;

y is a net. The assign statement is its driver: it connects y permanently to the value of a & b, so whenever a or b changes, y follows.

Two things worth being precise about.

The wire keyword does not create a piece of metal. It declares connectivity in the Verilog model. What a synthesis tool builds for it depends on the design — often it is just routing, but the expression driving it is logic, and the tool is free to implement the required behaviour however it can.

wire does not mean "combinational". It is true that assign y = a & b; describes combinational behaviour — but that comes from the continuous assignment and its expression, not from the word wire. The net is the destination, not the logic.

4. reg — Assigned by Procedural Code

This is the section that matters most in Chapter 5.

reg does not mean register. Declaring a signal reg does not create a flip-flop.

The confusion is historical and entirely understandable: IEEE calls reg, integer and real the register data types, and that name has misled generations of learners. What reg actually means is much narrower:

reg means: this signal is assigned by procedural code — inside an always or initial block.

That is all. It says nothing about storage, nothing about clocks, and nothing about flip-flops. Whether the hardware ends up with storage in it depends entirely on how the procedural code assigns it — which is the subject of the next two sections.

5. The Same Combinational Logic, Written Two Ways

Here is the proof that reg is not a register. These two modules describe the same AND gate:

Azvya Education Pvt. Ltd.VLSI Mentor
way 1 — continuous assignment onto a net
wire y;

assign y = a & b;
Azvya Education Pvt. Ltd.VLSI Mentor
way 2 — procedural assignment onto a variable
reg y;

always @(*) begin
    y = a & b;
end

Read the second one carefully:

  • y is declared reg only because it is assigned inside an always block. Verilog requires a variable there. That is a language rule, not a hardware statement.
  • always @(*) means re-evaluate whenever any input changes. There is no clock and no edge.
  • y = a & b; assigns y every time the block runs, for every possible input combination.
  • So y always reflects the current a & b. It never has to remember anything.

That is combinational logic — an AND gate. No flip-flop, no latch, no storage, despite the word reg sitting right there in the declaration.

This is why Chapter 3 could write combinational always blocks without contradiction. Now you know the language reason behind it.

6. What Actually Makes a Flip-Flop

Change one line:

Azvya Education Pvt. Ltd.VLSI Mentor
clocked.v
reg q;

always @(posedge clk) begin
    q <= d;
end
  • q is still just a variable assigned by procedural code — same as y above.
  • What changed is @(posedge clk): the block now runs only on a rising clock edge.
  • Between edges, q must hold its value, because nothing re-evaluates it.

Holding a value between clock edges is exactly what a flip-flop does. So this describes storage — and the reason is the edge-triggered timing control, not the declaration.

Put the whole thing together and you get the chain this chapter exists to teach:

Azvya Education Pvt. Ltd.VLSI Mentor
how a declaration becomes hardware
DECLARATION           HOW IT IS DRIVEN              BEHAVIOUR DESCRIBED       HARDWARE
-----------           ----------------              -------------------       --------
wire y;        →      assign y = a & b;        →    always follows a & b  →   combinational

reg  y;        →      always @(*)              →    always follows a & b  →   combinational
                        y = a & b;

reg  q;        →      always @(posedge clk)    →    holds between edges   →   flip-flop
                        q <= d;

Look down the left column: the declaration alone cannot distinguish rows two and three. Look at the middle column and it is obvious. The driver style decides, not the keyword.

Two details carried forward from Chapter 3 and used correctly above: combinational procedural logic uses blocking =, and edge-triggered sequential logic uses non-blocking <=. Blocking and Non-Blocking Assignments covers why.

7. wire vs reg in One Table

Questionwirereg
Verilog categorynetvariable
Can be the target of a procedural assignment?noyes
Can be the target of a continuous assign?yesno
Automatically means combinational hardware?nono
Automatically means a flip-flop?nono
What decides the hardware?the driving expressionthe procedural block

The two "no" rows are the point of the table. Neither keyword decides the hardware.

8. Width — Scalar and Vector

A declaration with no range is one bit — a scalar:

Azvya Education Pvt. Ltd.VLSI Mentor
scalar.v
wire a;        // one bit
reg  valid;    // one bit

Add a range and you get a vector: several bits treated as one signal.

Azvya Education Pvt. Ltd.VLSI Mentor
vector.v
wire [7:0] data;

Read [7:0] as "bit 7 down to bit 0":

Azvya Education Pvt. Ltd.VLSI Mentor
what [7:0] means
   bit index:   7   6   5   4   3   2   1   0
                ^                           ^
                |                           |
   most significant bit        least significant bit

   total width = 8 bits

The two numbers are the highest and lowest bit index, not a count — the width is the number of indices in the range, here eight.

Once declared, you can select one bit or a slice of bits:

Azvya Education Pvt. Ltd.VLSI Mentor
selecting.v
assign msb   = data[7];      // a single bit — a bit-select
assign lsb   = data[0];      // the other end
assign upper = data[7:4];    // four bits — a part-select

data[7] is one bit wide; data[7:4] is four bits wide. Widths matter here for the same reason they mattered for literals in Number Representation: a value and its destination should agree.

Which brings the two halves together:

A literal has a width. A signal has a width. RTL works cleanly when they match.

Azvya Education Pvt. Ltd.VLSI Mentor
widths that agree
reg [7:0] count;

initial count = 8'd0;     // an eight-bit value into an eight-bit variable

And note what this declaration does not say. reg [7:0] count; means eight bits wide in the Verilog model. It does not mean "eight flip-flops" — whether any storage exists depends, as always, on how count is assigned.

9. Range Direction

You will almost always see descending ranges:

Azvya Education Pvt. Ltd.VLSI Mentor
descending — the normal form
wire [7:0] data;

Ascending ranges are also legal Verilog:

Azvya Education Pvt. Ltd.VLSI Mentor
ascending — legal, but unusual in RTL
wire [0:7] data;

Both declare eight bits. The difference is which end index counts as bit 0, and therefore how bit numbering lines up with the usual most-significant-first way of writing a value.

RTL convention is overwhelmingly [7:0], because it matches how numbers are written — most significant on the left. Use descending ranges unless you have a specific reason not to, and be careful when connecting to code that does the opposite.

10. Signed and Unsigned — Same Bits, Different Reading

A declaration may carry the signed modifier:

Azvya Education Pvt. Ltd.VLSI Mentor
signed.v
reg        [7:0] a;      // unsigned — the default
reg signed [7:0] b;      // signed

Both are eight bits. The signed keyword adds no bits and changes no bits — it is exactly the bits-versus-interpretation idea from Number Representation §10, now applied to a declaration instead of a literal:

Azvya Education Pvt. Ltd.VLSI Mentor
the same idea, one level up
BITS                          1111_1111
        +
INTERPRETATION       unsigned  ->  255
                     signed    ->   -1

Signedness starts to matter when the value takes part in something — a comparison, arithmetic, a shift, or a change of width. Those rules belong to Verilog Operators and Operands, Chapter 10, where they can be taught alongside the operators that apply them.

One fact worth remembering now: reg and wire are unsigned by default, and integer is signed.

11. Four Values, Not Two

Every bit of a net or a reg carries one of four values:

ValueMeansTypically seen when
0logic lowdriven low
1logic highdriven high
xunknowna variable never assigned, or drivers in conflict
zhigh-impedancenothing is driving the net

This is the same four-state model you met for literals in Chapter 4.4 §9, and the same caution applies: x and z are values in Verilog's model, not voltages on silicon. An x in a waveform means the model does not know, which is useful precisely because it is visible.

integer is four-state too — it can hold x, and at time zero it does.

12. What Everything Starts As

Before any initial or always block runs, the simulator gives each signal a starting value:

FamilyValue at time zero
wire and most netsz — nothing driving yet
tri0 / tri10 / 1
supply0 / supply10 / 1, held
reg, integer, timex — unknown
real, realtime0.0

This is why a forgotten reset shows up as x spreading through a waveform. That is the model being honest: nothing has defined the value yet. Real silicon has no x — a flip-flop powers up at some definite 0 or 1 you cannot predict — so write a proper reset rather than relying on any starting value.

13. The Type Catalogue

You do not need to memorise these. Read them once for orientation; each has its own page.

Nets — driven, never procedurally assigned:

Net typeBehaviourWhere used
wiretakes its driver's valuethe default; almost all RTL
trisame as wiresignals intentional tri-state drivers
wand / triandwired-AND of its driversany 0 driver wins
wor / triorwired-OR of its driversany 1 driver wins
tri0 / tri1pulls to 0 / 1 when undrivenpull-down / pull-up models
triregretains its last driven valuecapacitive charge storage; modelling
supply0 / supply1constant 0 / 1power and ground ties

Variables — procedurally assigned:

Variable typeWidthNotes
regas declaredthe workhorse; combinational or sequential, depending on the block
integer32 bitssigned, four-state; loop counters and calculations
realfloating-pointsimulation and modelling, not ordinary RTL signals
realtimefloating-pointa real-valued time variable
time64 bitstime values from $time

For everyday synthesisable RTL the working set is small: wire, reg, and a vector range. The rest are for tri-state buses, power modelling and testbenches.

14. Where to Go Next

The twelve sub-topics below are live and each drills one type properly.

5.1 Physical Data Types — the net family in full.

5.2 Register Data Types — the variable family, and the deeper treatment of everything in §4–§6 above.

15. Common Mistakes

Reading reg as "register". It means procedurally assigned. A reg in always @(*) with every branch assigned is combinational logic.

Expecting the declaration to tell you the hardware. reg [7:0] count; does not say whether count is storage. Look at how it is assigned.

Putting a wire on the left inside always. Procedural assignment needs a variable. Declare it reg.

Putting a reg on the left of assign. A continuous assignment drives a net. Declare it wire.

Treating [7:0] as a count. It is a range of bit indices — highest to lowest. The width is how many indices that range covers.

Thinking signed changes the bits. It changes how the same bits are interpreted, nothing more.

16. Exercises

Work these out before reading the answers.

Exercise 1 — Which declaration?

Azvya Education Pvt. Ltd.VLSI Mentor
exercise-1.v
always @(*) begin
    y = a | b;
end

Must y be declared wire or reg, and why?

Exercise 2 — Does this imply a flip-flop?

Azvya Education Pvt. Ltd.VLSI Mentor
exercise-2.v
reg y;

always @(*) begin
    y = a & b;
end

Does reg y; mean y becomes a flip-flop? Explain what hardware this describes.

Exercise 3 — Width and indexing

Azvya Education Pvt. Ltd.VLSI Mentor
exercise-3.v
wire [7:0] data;

How wide is data? Which bit does data[7] select? How wide is data[7:4]?

Exercise 4 — Spot the difference

Azvya Education Pvt. Ltd.VLSI Mentor
exercise-4.v
// A
reg q;
always @(*)            q = d;

// B
reg q;
always @(posedge clk)  q <= d;

Both declare q as reg. What hardware does each describe, and what makes them different?

Exercise 5 — Signed

Azvya Education Pvt. Ltd.VLSI Mentor
exercise-5.v
reg        [7:0] a;
reg signed [7:0] b;

How many bits does each hold? What does signed change?

Answers

Exercise 1. reg. The assignment is inside an always block, which is procedural, and procedural assignment requires a variable. This is a language requirement — it says nothing about the hardware, which here is an OR gate.

Exercise 2. No. y is declared reg only because it is assigned procedurally. The block is always @(*) with no clock and no edge, and y is assigned on every execution, so y always reflects the current a & b and never has to remember anything. This describes combinational logic — an AND gate.

Exercise 3. data is 8 bits. data[7] selects the most significant bit — a single bit. data[7:4] is a part-select of the top four bits.

Exercise 4. Both are variables assigned by procedural code, which is why both are reg.

  • A re-evaluates whenever d changes and always tracks it, so it describes combinational logic — a buffer, effectively.
  • B runs only on a rising clock edge, so q must hold its value between edges. That is a flip-flop.

The difference is entirely in the timing control — @(*) versus @(posedge clk) — not in the declaration, which is identical in both.

Exercise 5. Both hold eight bits. signed changes nothing about the bits; it says those bits should be read as a signed (two's complement) value rather than an unsigned one. The same pattern 1111_1111 reads as 255 unsigned and −1 signed.

17. Summary

  • A declaration says what kind of thing a signal is, not what hardware it becomes.
  • Nets are driven; variables are assigned. wire needs a driver — a continuous assign or an instance output. reg is written by procedural code in an always or initial block.
  • reg does not mean register. It means procedurally assigned. IEEE's name for the family is historical and misleading.
  • The driver style decides the hardware. always @(*) with complete assignment describes combinational logic; always @(posedge clk) describes storage. The same reg q; appears in both.
  • A range is bit indices, not a count. [7:0] is eight bits, numbered 7 down to 0.
  • signed changes the reading, not the bits.
  • Four values, not two — 0, 1, x, z, all of them model values rather than voltages.

Next, Physical Data Types takes the net family in full, and Register Data Types takes the variable family — including every synthesis outcome a reg can produce.

Standards & specifications

Governing standard
IEEE Std 1364 (Verilog)(opens IEEE in a new tab)

Defines the Verilog language and its simulation semantics, including the event scheduling model. Synthesis support is defined by tools, not by this standard.

This page also covers RTL structure, verification approach and debugging technique. Those are engineering practice built on the standard, not requirements the standard itself imposes.

Where this fits

Part of the Verilog HDL curriculum.