Verilog Data Types
Verilog provides two fundamental categories of data types: nets and variables. Choosing the correct type is essential for writing code that both simulates correctly and synthesizes into the intended hardware.
Verilog uses a 4-state logic system where every signal can hold one of four
values: 0, 1, X (unknown), or Z (high-impedance).
4-State Logic Values
Value |
Meaning |
|---|---|
|
Logic low / false / ground |
|
Logic high / true / VDD |
|
Unknown — the simulator cannot determine the value (e.g., uninitialized reg) |
|
High-impedance — the signal is not driven (e.g., tri-state bus) |
wire
A wire is a net type. It models a physical wire in a circuit.
Must be driven continuously by an
assignstatement or a module output port.Cannot hold a value on its own.
Default value is
Z.
wire enable; // 1-bit wire
wire [7:0] data_bus; // 8-bit wire (vector)
wire [31:0] addr; // 32-bit address bus
assign enable = a & b; // Continuously driven
reg
A reg is a variable type that holds a value across simulation time steps.
Assigned inside
initialoralwaysprocedural blocks.Despite the name,
regdoes not always infer a hardware flip-flop. Aregassigned in a combinationalalwaysblock synthesizes to combinational logic.Default value at the start of simulation is
X.
reg q; // Single-bit register
reg [3:0] count; // 4-bit register (e.g., counter output)
reg [7:0] byte; // 8-bit register
always @(posedge clk) begin
q <= d; // Infers a D flip-flop
end
Vectors
Both wire and reg can be declared as multi-bit vectors using the
[MSB:LSB] notation.
wire [7:0] data; // 8-bit vector, MSB is bit 7
reg [15:0] result; // 16-bit vector
// Bit-select
wire msb = data[7];
// Part-select
wire [3:0] nibble = data[7:4];
By convention, Verilog vectors are declared [n-1:0] (e.g., [7:0] for a
byte), making index 0 the least significant bit.
integer
integer is a signed 32-bit variable, primarily used in simulation for loop
counters and general arithmetic. It is not recommended for synthesizable RTL.
integer i;
initial begin
for (i = 0; i < 16; i = i + 1) begin
$display("i = %0d", i);
end
end
parameter and localparam
Parameters allow you to write reusable, configurable modules.
parameter— A compile-time constant that can be overridden when the module is instantiated.localparam— A local constant that cannot be overridden from outside. Use it for internal constants like state encodings.
module adder #(
parameter WIDTH = 8
) (
input wire [WIDTH-1:0] a,
input wire [WIDTH-1:0] b,
output wire [WIDTH:0] sum
);
assign sum = a + b;
endmodule
// Instantiate with a different width
adder #(.WIDTH(16)) u_adder (.a(x), .b(y), .sum(s));
// Internal constants
localparam IDLE = 2'b00;
localparam RUN = 2'b01;
localparam DONE = 2'b10;
Arrays and Memories
Verilog supports arrays of reg to model memories.
reg [7:0] memory [0:255]; // 256 x 8-bit memory (RAM model)
reg [31:0] rom [0:15]; // 16 x 32-bit ROM
// Write
memory[0] = 8'hAB;
// Read
wire [7:0] data_out = memory[addr];
Complete Data Type Example
The following module demonstrates all major data types together:
module data_type_example;
wire single_bit_wire;
reg single_bit_reg;
wire [7:0] data_bus;
reg [3:0] counter;
parameter WIDTH = 8;
localparam IDLE = 2'b00;
reg [7:0] memory [0:15];
endmodule
Summary
Type |
Category |
Key Rule |
|---|---|---|
|
Net |
Driven by |
|
Variable |
Assigned in |
|
Variable |
Use for simulation loops only |
|
Constant |
Module-level, overridable at instantiation |
|
Constant |
Module-level, NOT overridable |
See Also
Procedural Blocks in Verilog — How
wireandregbehave inside procedural blocks.Common Verilog Design Examples — Examples of combinational and sequential designs using these types.