Verilog Data Types

Verilog has two main categories of data types: nets (like wire) and variables (like reg). Understanding when to use each is crucial for correct synthesis.

Net Types (wire)

Nets represent physical connections between hardware elements. They don't store values – they simply carry signals driven by other components.

Wire Declaration
// Single-bit wires
wire a;
wire b;
wire y;
// Multi-bit wire (bus)
wire [7:0] data_bus;    // 8-bit bus, MSB:LSB
wire [31:0] address;    // 32-bit bus
// Wire with initial value (for simulation only)
wire [3:0] default_val = 4'b0000;
// Array of wires
wire [7:0] mem_data [0:255];  // 256 x 8-bit wires

Key Point

Wires must be continuously driven. Use them with assign statements or as outputs from module instantiations. They cannot be assigned inside always blocks.

Variable Types (reg)

reg is a variable type that can hold a value. Despite the name, it doesn't always synthesize to a register – it depends on context.

Reg Declaration
// Single-bit reg
reg q;
reg enable;
// Multi-bit reg
reg [7:0] counter;
reg [15:0] data_reg;
// Reg with initial value
reg [3:0] state = 4'b0001;
// Memory array (RAM/ROM modeling)
reg [7:0] memory [0:1023];  // 1KB memory

When does reg become a flip-flop?

  • If assigned in an always @(posedge clk) block → becomes a register
  • If assigned in a combinational always @(*) block → becomes a wire

wire vs reg

This is one of the most common sources of confusion. Here's a simple rule:

Use wire when... Use reg when...
Connecting module outputs to other inputs Assigning inside always or initial blocks
Using assign statements Creating flip-flops or latches
Modeling physical connections Testbench stimulus generation
wire vs reg Example
module example (
    input  wire clk,
    input  wire a, b,
    output wire y_comb,    // Combinational output
    output reg  y_seq      // Sequential output
);
    // wire with assign (combinational)
    assign y_comb = a & b;
    // reg in always block (sequential)
    always @(posedge clk) begin
        y_seq <= a & b;
    end
endmodule

Integer, Real, and Time

These types are primarily used in testbenches and are not synthesizable:

Other Data Types
// Integer: 32-bit signed value
integer i;
integer count = 0;
integer loop_var;
// Real: floating-point (double precision)
real voltage;
real delay_time = 1.5;
// Time: 64-bit unsigned for simulation time
time start_time;
time end_time;
// Example usage in testbench
initial begin
    start_time = $time;
    #100;
    end_time = $time;
    $display("Elapsed: %0t", end_time - start_time);
end

Not Synthesizable

integer, real, and time are for simulation only. Never use them in design code intended for synthesis.

Parameters and Localparams

Parameters allow you to create configurable, reusable modules:

Parameter Usage
// Module with parameters
module counter #(
    parameter WIDTH = 8,          // Overridable
    parameter MAX_COUNT = 255
) (
    input  wire             clk,
    input  wire             rst_n,
    output reg  [WIDTH-1:0] count
);
    localparam HALF_MAX = MAX_COUNT / 2;  // Cannot be overridden
    always @(posedge clk or negedge rst_n) begin
        if (!rst_n)
            count <= 0;
        else if (count == MAX_COUNT)
            count <= 0;
        else
            count <= count + 1;
    end
endmodule
// Instantiation with parameter override
counter #(.WIDTH(16), .MAX_COUNT(1000)) my_counter (
    .clk(system_clk),
    .rst_n(reset_n),
    .count(counter_value)
);

Common Interview Questions

  1. What is the difference between wire and reg?

    wire is a net type for continuous connections; reg is a variable type that can be assigned in procedural blocks.

  2. Does reg always synthesize to a flip-flop?

    No. A reg in a combinational always @(*) block synthesizes to combinational logic, not a register.

  3. What is the difference between parameter and localparam?

    parameter can be overridden during instantiation; localparam cannot be changed and is local to the module.