๐Ÿ”ฒ Chip Design Institute
Educational Resources

Verilog / HDL

Hardware description languages are how engineers turn ideas into silicon. Learn Verilog syntax, simulation, synthesis, and the patterns that produce correct, efficient hardware.

HDL Overview

A Hardware Description Language (HDL) describes the structure and behavior of digital circuits. Unlike software programming languages, HDL statements execute concurrently, modeling the parallel nature of hardware. The two dominant HDLs are Verilog and VHDL.

Verilog

Created by Phil Moorby and Prabhu Goel at Gateway Design Automation in 1984. Acquired by Cadence, then donated to IEEE in 1995 (IEEE 1364). C-like syntax. Dominant in the US and Asia. Extended to SystemVerilog (IEEE 1800) in 2005, adding object-oriented verification features, assertions, and improved synthesis constructs.

VHDL

VHSIC Hardware Description Language. Created under a U.S. Department of Defense program in 1983. IEEE 1076. Ada-like syntax โ€” strongly typed, verbose, explicit. Dominant in Europe and defense/aerospace. More verbose than Verilog but catches more errors at compile time.

Verilog / SV
IEEE 1364 / 1800
C-like syntax
Industry standard
VHDL
IEEE 1076
Ada-like syntax
Europe/defense
Chisel / Amaranth
Scala / Python
Meta-HDL
Generates Verilog

Modern Alternatives

💻 Normal programming languages (like Python or JavaScript) tell a computer WHAT to do step by step. Verilog is different โ€” it describes HARDWARE. You're not writing instructions, you're designing actual circuits! It's like the difference between writing a recipe (software) and building a kitchen (hardware). Engineers use Verilog to design the chips inside your phone and computer.

Syntax Basics

Behavioral — algorithm (always, if/else)
RTL — register transfers (assign, always @)
Gate-level — and, or, not primitives
Transistor-level — nmos, pmos, cmos

Data Types

Operators

Modules & Hierarchy

The module is the fundamental building block in Verilog. It encapsulates a piece of hardware with defined inputs and outputs. Designs are built hierarchically: a top-level module instantiates sub-modules, which instantiate smaller sub-modules, down to primitive gates.

Module Declaration

module adder #(
  parameter WIDTH = 8       // parameterized width
)(
  input  wire [WIDTH-1:0] a,
  input  wire [WIDTH-1:0] b,
  input  wire             cin,
  output wire [WIDTH-1:0] sum,
  output wire             cout
);
  assign {cout, sum} = a + b + cin;
endmodule

Module Instantiation

// Named port connection (recommended)
adder #(.WIDTH(16)) u_adder16 (
  .a    (operand_a),
  .b    (operand_b),
  .cin  (carry_in),
  .sum  (result),
  .cout (carry_out)
);

Parameters and Generate

Always Blocks

Always blocks are procedural blocks that describe both combinational and sequential logic. The sensitivity list determines when the block executes.

Combinational Always Block

// Verilog-2001: use @(*)
always @(*) begin
  case (sel)
    2'b00: out = a;
    2'b01: out = b;
    2'b10: out = c;
    2'b11: out = d;
  endcase
end

// SystemVerilog: always_comb (preferred)
always_comb begin
  unique case (sel)
    2'b00: out = a;
    2'b01: out = b;
    2'b10: out = c;
    2'b11: out = d;
  endcase
end

Use blocking assignments (=) in combinational blocks. The always_comb keyword in SystemVerilog enforces that the block describes combinational logic and triggers at time 0.

Sequential Always Block

// Flip-flop with synchronous reset
always @(posedge clk) begin
  if (rst)
    q <= 0;
  else
    q <= d;
end

// SystemVerilog: always_ff (preferred)
always_ff @(posedge clk) begin
  if (rst)
    q <= '0;
  else
    q <= d;
end

Use non-blocking assignments (<=) in sequential blocks. This ensures all flip-flops sample their inputs simultaneously at the clock edge, modeling the parallel nature of hardware correctly.

Blocking vs Non-Blocking

Testbenches

A testbench is a Verilog module with no ports that instantiates the design under test (DUT), drives stimuli, and checks outputs. Testbenches are not synthesizable โ€” they use the full language including delays, file I/O, and system tasks.

Basic Testbench Structure

module tb_adder;
  reg  [7:0] a, b;
  reg        cin;
  wire [7:0] sum;
  wire       cout;

  // Instantiate the DUT
  adder #(.WIDTH(8)) dut (
    .a(a), .b(b), .cin(cin),
    .sum(sum), .cout(cout)
  );

  initial begin
    // Dump waveforms
    $dumpfile("adder.vcd");
    $dumpvars(0, tb_adder);

    // Test case 1
    a = 8'd100; b = 8'd50; cin = 0;
    #10;
    if (sum !== 8'd150 || cout !== 0)
      $error("Test 1 FAILED");

    // Test case 2: overflow
    a = 8'd200; b = 8'd100; cin = 0;
    #10;
    if ({cout, sum} !== 9'd300)
      $error("Test 2 FAILED");

    $display("All tests passed");
    $finish;
  end
endmodule

Clock Generation

reg clk = 0;
always #5 clk = ~clk;  // 100 MHz clock (10ns period)

SystemVerilog Verification

🧪 A testbench is like a robot that tests your circuit design before you build it for real. It pokes your design with different inputs and checks if the outputs are correct โ€” like a teacher grading a math test automatically. If something is wrong, it tells you BEFORE you spend millions making the actual chip!

Simulation

Simulation runs the Verilog design as a software model, checking functionality before committing to hardware. There are two main types: event-driven simulation and cycle-based simulation.

Event-Driven Simulation

Cycle-Based Simulation

Waveform Viewing

Simulations dump signal values to VCD (Value Change Dump) or FST (Fast Signal Trace) files. View with GTKWave (open-source, VCD/FST) or Surfer (modern, Rust-based). Waveform debugging is the primary way to diagnose hardware design bugs โ€” you can see every signal at every point in time.

Synthesis

Synthesis converts RTL code into a gate-level netlist โ€” a circuit composed of standard cells (NAND, NOR, DFF, etc.) from a target library. The synthesizer optimizes for area, timing, and power.

Synthesizable vs Non-Synthesizable

Synthesis Tools

Timing Constraints

You must tell the synthesis tool the target clock frequency. Synopsys Design Constraints (SDC) format: create_clock -period 10 [get_ports clk] (100 MHz). The tool optimizes the circuit to meet this timing, reporting slack (positive = met, negative = violated). Input/output delays, multicycle paths, and false paths are also specified in SDC.

Common Patterns

Shift Register

always_ff @(posedge clk)
  if (rst)  shift_reg <= '0;
  else      shift_reg <= {shift_reg[N-2:0], data_in};

Counter with Enable and Load

always_ff @(posedge clk)
  if (rst)        count <= '0;
  else if (load)  count <= load_val;
  else if (en)    count <= count + 1;

FSM (Finite State Machine)

typedef enum logic [1:0] {
  IDLE, ACTIVE, DONE
} state_t;

state_t state, next_state;

// State register
always_ff @(posedge clk)
  if (rst) state <= IDLE;
  else     state <= next_state;

// Next-state logic (combinational)
always_comb begin
  next_state = state;  // default: hold
  unique case (state)
    IDLE:   if (start) next_state = ACTIVE;
    ACTIVE: if (done)  next_state = DONE;
    DONE:              next_state = IDLE;
  endcase
end

// Output logic
assign busy = (state == ACTIVE);

Synchronizer (Clock Domain Crossing)

// Two-flop synchronizer for single-bit signals
reg [1:0] sync_reg;
always_ff @(posedge clk_dst)
  sync_reg <= {sync_reg[0], async_signal};
wire synced = sync_reg[1];

Edge Detector

reg signal_d;
always_ff @(posedge clk) signal_d <= signal;
wire rising_edge  = signal & ~signal_d;
wire falling_edge = ~signal & signal_d;

Parameterized Multiplexer

module mux #(
  parameter INPUTS = 4,
  parameter WIDTH  = 8
)(
  input  wire [$clog2(INPUTS)-1:0] sel,
  input  wire [WIDTH-1:0]          in [INPUTS],
  output wire [WIDTH-1:0]          out
);
  assign out = in[sel];
endmodule

Gotchas

Common mistakes that cause simulation-synthesis mismatches, silent bugs, or synthesis failures.

Latches from Incomplete Assignments

Sensitivity List Errors

Blocking in Sequential Blocks

Multi-Driven Signals

Integer Overflow

Signed vs Unsigned

Resources

HDLBits

140+ interactive Verilog exercises with instant feedback. The best way to learn Verilog by doing. From simple wires to FSMs and serial protocols.

Free | Browser-based

ChipVerify Verilog Tutorial

Comprehensive Verilog and SystemVerilog tutorial. Data types, operators, procedural blocks, synthesis, testbenches. Well-organized reference.

Free | Reference

Verilator

Fastest open-source Verilog simulator. Compiles to C++. Excellent linting mode catches common RTL mistakes before simulation.

GitHub | Open-source

Icarus Verilog

Open-source event-driven Verilog simulator. Lightweight, easy to install, good for learning. Supports Verilog-2005.

GitHub | Open-source

ZipCPU Blog & Tutorials

Practical Verilog and FPGA tutorials. Formal verification, AXI bus, DDR controllers. Real-world design wisdom from an experienced engineer.

Blog | Free

ASIC World: Verilog

Classic Verilog tutorial covering synthesis, simulation, and system tasks. Comprehensive reference for Verilog constructs and coding styles.

Free | Reference