Verilog Syntax and Data Types
Introduction¶
In Verilog, everything is built on signals — the connections and storage elements that represent digital logic.
 Understanding how these signals are declared, connected, and behave is the foundation of writing correct hardware description language (HDL) code.
This guide explains Verilog syntax and data types, focusing on the most used objects in digital design:
 wire, reg, net, and variables — what they mean, when to use them, and how synthesis interprets them.
Basic Syntax in Verilog¶
Before we dive into data types, let’s review the basic structure of a Verilog design.
Example of a simple module¶
module and_gate (
  input  a, b,
  output y
);
  assign y = a & b;
endmodule
Every Verilog file consists of one or more modules, each describing a piece of hardware. Each module has:
- Ports: Inputs, outputs, or inouts.
 - Internal signals: Declared as wire, reg, etc.
 - Assignments or procedural blocks: Define how signals interact.
 
Two Main Classes of Data Types¶
Verilog has two broad categories of data types:
| Type | Represents | Example | Synthesizable? | 
|---|---|---|---|
| Nets (like wire) | Physical connections between hardware elements | wire a; | Yes | 
| Variables (like reg, integer, etc.) | Storage elements holding values until next assignment | reg q; | Yes (if used properly) | 
Nets: Modeling Connections¶
Nets are used to represent physical connections between components in hardware — wires that transmit signals from one point to another. They do not store values. A net continuously reflects the value driven onto it by some source.
| Net Type | Description | Example | 
|---|---|---|
| wire | Most common; carries combinational logic | wire sum; | 
| tri | Tri-state wire (can be high-impedance 'z') | tri bus; | 
| wand | Wired-AND connection | wand signal; | 
| wor | Wired-OR connection | wor signal; | 
wire a, b, y;
assign y = a & b;
Here, y is a wire that carries the AND of a and b. If a or b changes, y automatically updates — no storage involved.
Variables: Modeling Storage¶
Variables hold values until they are reassigned. They appear in procedural blocks such as always or initial. The most common variable type is reg. 
Note
Despite its name, "reg" does not necessarily mean a hardware register — it can synthesize as either combinational or sequential logic, depending on context.
Example 1 — Combinational variable¶
reg y;
always @(*) begin
  y = a & b;  // Blocking assignment
end
Here y behaves like a combinational output, not a flip-flop.
Example 2 — Sequential variable¶
reg [7:0] q;
always @(posedge clk or posedge rst) begin
  if (rst)
    q <= 0;
  else
    q <= d;   // Non-blocking assignment
end
Declaring Data Types¶
You can declare nets and variables with or without bit widths. If no bit-width is given, the signal is 1-bit wide.
| Declaration | Meaning | 
|---|---|
| wire a; | Single-bit wire | 
| reg [3:0] count; | 4-bit register (bits 3 down to 0) | 
| wire [7:0] data_bus; | 8-bit wire bus | 
| reg signed [15:0] value; | Signed 16-bit register | 
The Difference Between wire and reg¶
One of the most confusing parts of Verilog for starters is understanding when to use wire or reg.
| Feature | wire | reg | 
|---|---|---|
| Stores value? | No | Yes | 
| Requires continuous assignment? | Yes (assign) | No | 
| Used in procedural blocks? | No | Yes | 
| Default value | Unknown (x) until driven | Unknown (x) until assigned | 
| Hardware equivalent | Wire (connection) | Latch/FF or combinational node | 
module example (
  input a, b, clk,
  output reg q,       // variable
  output wire y       // net
);
  assign y = a & b;  // continuous assignment
  always @(posedge clk)
    q <= a | b;      // procedural assignment
endmodule
In the above code, y is a wire: continuously driven by assign. y cannot be used inside procedural block (always @). q is a reg: updated only on a clock edge. 
Other Variable Types¶
Verilog supports several variable types besides reg, though they’re mainly for simulation or specific uses.
| Type | Width | Use Case | Synthesizable? | 
|---|---|---|---|
| integer | 32-bit signed | Loop indices, counters | Sometimes | 
| real | Floating point | Simulation only | No | 
| time | 64-bit | Simulation timing | No | 
| realtime | Floating-point time | Simulation only | No | 
integer i;
initial begin
  for (i = 0; i < 8; i = i + 1)
    $display("i=%0d", i);
end
integer here is fine for simulation; not meant for hardware logic storage.
Continuous Assignments (for Nets)¶
Nets are driven by continuous assignments, which use the keyword assign.
assign y = a & b;
The expression on the right of assign continuously drives the wire y. If a or b changes, y updates instantly. Multiple drivers can drive the same wire, but the simulator resolves values (e.g., with wired-OR, wired-AND).
Procedural Assignments (for Variables)¶
Variables (e.g., reg) are updated using procedural assignments inside an always or initial block.
Two types of assignments:
| Type | Symbol | Behavior | 
|---|---|---|
| Blocking | = | Executes immediately (like software) | 
| Non-blocking | <= | Executes concurrently at end of time step (used for sequential logic) | 
always @(*) begin
  y = a & b;       // Blocking
end
always @(posedge clk) begin
  q <= d;          // Non-blocking
end
Vectors and Bit Slicing¶
Verilog allows you to create vectors/bus (multi-bit signals or multi-width wires).
wire [7:0] data_bus;
reg  [3:0] nibble;
Bit and part selection
data_bus[0]       // LSB
data_bus[7:4]     // Upper nibble
Concatenation
assign full_byte = {upper, lower};  // Join two nibbles
Replication
assign pattern = {4{a}}; // Repeat 'a' 4 times
Nets and Variables in Hierarchical Designs¶
When connecting modules, you’ll often use nets (wire) between them.
module adder(input [3:0] a, b, output [4:0] sum);
  assign sum = a + b;
endmodule
module top;
  wire [3:0] x, y;
  wire [4:0] result;
  adder u1 (.a(x), .b(y), .sum(result));
endmodule
In the above code, x, y, and result are wires connecting the submodule adder to the top module. You cannot connect reg directly across modules; use wire for that.
Signed vs Unsigned Numbers¶
By default, Verilog treats numbers as unsigned. To handle negative values or signed arithmetic, declare signals as signed.
reg signed [7:0] a, b;
wire signed [8:0] sum;
assign sum = a + b;
This ensures proper sign extension and arithmetic interpretation.
Default Values and Initialization¶
In simulation:
- Uninitialized wire → z (high-impedance)
 - Uninitialized reg → x (unknown)
 
In synthesis:
- Uninitialized registers don’t have defined power-on values (unless FPGA supports it).
 
Use reset logic for predictable hardware behavior.
Data Type Best Practices¶
Do¶
- Use wire for combinational interconnections.
 - Use reg in procedural blocks.
 - Define bit widths explicitly ([n:0]).
 - Use signed if negative arithmetic is required.
 - Add reset for all sequential logic.
 
Don't¶
- Assign to wire inside an always block.
 - Drive a reg with multiple procedural blocks.
 - Mix blocking and non-blocking in same block.
 - Omit bit widths in large designs.
 
Example: Full Design with Data Types¶
module counter_4bit (
  input clk, rst,
  output [3:0] count
);
  reg [3:0] q;       // variable (storage)
  assign count = q;  // wire output
  always @(posedge clk or posedge rst) begin
    if (rst)
      q <= 0;
    else
      q <= q + 1;
  end
endmodule
In the above code, q is a reg — holds count value. count is a wire — continuously reflects q.
Quick Comparison Table between wire, reg, integer and real¶
| Feature | wire | reg | integer | real | 
|---|---|---|---|---|
| Represents | Physical connection | Variable/storage | Loop variable | Floating point | 
| Used in | Continuous assign | Procedural blocks | Testbenches, counters | Simulation | 
| Default width | 1 bit | 1 bit | 32 bits | 64 bits | 
| Synthesizable | Yes | Yes | Limited | No | 
| Holds value? | No | Yes | Yes | Yes | 
| Multiple drivers | Yes | No | No | No |