A complete guide to Verilog HDL β history, design levels, language constructs, data types and operators.
Verilog was one of the first modern hardware description languages, built to model, simulate, and eventually synthesize digital circuits.
Created by Prabhu Goel and Phil Moorby at “Automated Integrated Design Systems” (renamed Gateway Design Automation in 1985). Originally for simulation only β synthesis support was added later. Cadence Design Systems acquired Gateway in 1990, gaining rights to Verilog and the Verilog-XL simulator, the de-facto standard for the next decade.
Cadence transferred Verilog to the public domain under Open Verilog International (OVI) β now Accellera β in response to VHDL’s growing popularity. IEEE standardized it as IEEE 1364-1995. Verilog-A (analog modeling) was also initiated around this time.
A major upgrade. Key additions: 2’s-complement signed nets, new operators (+, -, /, *, >>>), generate/endgenerate for parameterized instantiation, improved file I/O, and always @*. This remains the dominant version in commercial EDA tools.
Minor corrections, spec clarifications, and additions such as the uwire keyword. Verilog-AMS (Analog & Mixed Signal) was formalized as a companion standard.
Verilog and SystemVerilog were merged into one unified standard. SystemVerilog is a superset of Verilog-2005, adding powerful verification and modeling features drawing from Open Vera and SuperLog.
Verilog supports four abstraction levels. One of its greatest strengths is that you can freely mix all four within the same design module.
assign. All assignments run concurrently.
assign y = a & b;// Behavioral Level always @(a, b, c, d) begin y = ~((a & b) | (c & d)); end // Data Flow Level assign y = ~((a & b) | (c & d)); // Gate Level and g1(ab, a, b); and g2(cd, c, d); nor g3(y, ab, cd);
Real hardware is inherently parallel β transistors and gates act simultaneously. Verilog simulators model this through concurrent execution.
always and assign blocks run in parallel, unlike sequential C programs.`timescale 1ns/1ps to set simulation time units and precision per module.always @(posedge clk).Simulation checks functional correctness β a testbench drives inputs and captures outputs. Synthesis translates verified RTL into hardware (FPGA or ASIC). Many behavioral constructs are not directly synthesizable; rewrite those at RTL level if needed.
Testing has two dimensions: functional tests and timing tests. Both use a testbench module that instantiates the design, drives inputs, and checks outputs.
Testbenches are written at the behavioral level. Variables inside nested modules are accessed via hierarchical addressing (e.g., top.dut.signal_name).
Built-in routines prefixed with $, used during simulation only β not part of the synthesized hardware.
$display, $monitor, $strobe β print signal values during simulation.$fopen, $fwrite, $readmemh β read test vectors from or write results to files.$finish, $stop β end or pause simulation at a specific point.$time, $realtime to track progress. $random for constrained-random test generation.Every Verilog design is built from modules β black boxes with named ports. Ports can be input, output, or inout.
// Module definition (done once) module nand_gate ( input [7:0] in, output y ); assign y = ~(&in); endmodule // Positional instantiation nand_gate IC1 (bus_a, out_a); // Named port instantiation (preferred β less error-prone) nand_gate IC2 (.in(bus_b), .y(out_b)); nand_gate IC3 (.in(bus_c), .y(out_c));
Verilog source files are composed of 7 types of lexical tokens:
clk, CLK, and Clk are three different identifiers β just like C.module // begins a module endmodule // ends a module begin end // procedural block boundaries if else // conditional branching always // procedural block (runs continuously) assign // continuous (data-flow) assignment wire reg // net and variable declarations
// β Valid β start with letter or underscore clock enable gate_1 _reset data_32b // β Invalid 1_name // starts with a digit $name // $ cannot be the first character name aa // space splits this into two separate tokens
4'b1010 // 4-bit binary 8'hFF // 8-bit hex (= 255 decimal) 6'd35 // 6-bit decimal 12'o777 // 12-bit octal 4'bx0z1 // x=unknown, z=high-impedance 8'b1010_1100 // underscore for readability (ignored by compiler)
// Single-line comment /* Multi-line comment spans multiple lines β cannot be nested */
Every signal in Verilog can hold one of four logic values:
| Value | Meaning | Typical Scenario |
|---|---|---|
| 0 | Logic low / false | Normal driven-low state |
| 1 | Logic high / true | Normal driven-high state |
| x | Unknown / uninitialized | Power-on state, conflicting drivers, don’t-care |
| z | High impedance | Tri-state bus, floating wire |
z input to a gate behaves as x. Exception: MOS switches β a z input propagates as z to the output.When multiple sources drive the same net, the stronger source wins. Equal strengths driving opposite values produce x.
| Category | Strength Order (Strongest β Weakest) |
|---|---|
| Driving | supply > strong > pull > weak |
| Capacitive | large > medium > small |
| High-Z | highz β weakest of all, represents a floating state |
Verilog data types fall into two categories. Every signal must be declared before use.
z if undriven.$time).// Scalar (no range = 1 bit) wire wr; // 1-bit net reg flag; // 1-bit register // Vectors wire [7:0] data; // 8-bit bus; data[7]=MSB, data[0]=LSB reg [3:0] nibble; // 4-bit register // Signed vectors wire signed [4:0] num; // range: -16 to +15 // Part-selects data[0] // LSB only data[7:4] // upper nibble
parameter WORD_SIZE = 16; parameter MEM_SIZE = 256, FACTOR = WORD_SIZE/2; // Override at instantiation time my_mem #(.WORD_SIZE(32), .MEM_SIZE(1024)) u1 ( ... );
Verilog operators are similar to C, with three forms:
| Type | Form | Example | Description |
|---|---|---|---|
| Unary | op a | ~a | Bitwise NOT |
| Binary | a op b | a & b | Bitwise AND |
| Ternary | a ? b : c | sel ? x : y | If sel=1 β x, else β y |
// Arithmetic a + b a - b a * b a / b a % b // Logical (1-bit result) a && b a || b !a // Bitwise (bit-by-bit, same width as operands) a & b a | b a ^ b ~a a ~^ b // ~^ = XNOR // Reduction (collapses a bus to 1 bit) &a // AND all bits |a // OR all bits ^a // XOR all bits β odd-parity check // Shift a << 2 // logical left shift a >> 2 // logical right shift a >>> 2 // arithmetic right shift (sign-preserving) // Concatenation & Replication {a, b} // join bits of a and b {4{a}} // replicate a four times // Equality a == b // logical equality (x/z β x result) a === b // case equality (x and z must match exactly)