Verilog Explained

varilog_

Verilog Explained: A Complete Guide to Hardware Description Language for Beginners

If you're stepping into the world of digital electronics, FPGA design, or ASIC development, there's one language you simply can't avoid: Verilog. In this post, we'll break down what Verilog is, why it exists, its core building blocks, and walk through real code examples you can try yourself.

What is Verilog?

Verilog is a Hardware Description Language (HDL) used to model, design, and verify digital electronic circuits. Unlike software programming languages such as C or Python — which describe a sequence of instructions executed by a processor — Verilog describes hardware structure and behavior. It tells a tool how logic gates, flip-flops, and entire processors should be built and how they behave over time.

Verilog was created in 1984 by Phil Moorby and Prabhu Goel at Gateway Design Automation, later becoming an IEEE standard (IEEE 1364) in 1995. Today it remains one of the two dominant HDLs, alongside VHDL, and its successor SystemVerilog extends it with verification-focused features.

Why does Verilog matter? Every chip in your phone, laptop, or smart device — from a simple counter to a full CPU — is designed and verified using an HDL like Verilog before it's ever manufactured in silicon.

Verilog vs. Software Languages: The Key Mindset Shift

The biggest hurdle for beginners is realizing Verilog code doesn't run "top to bottom" like software. Instead, it describes concurrent hardware blocks that all operate simultaneously, just like real circuits do. A block of code doesn't "finish" and move to the next line — it represents a physical piece of hardware that exists and reacts continuously.

The Basic Building Block: The Module

Every piece of hardware in Verilog is described inside a module. Think of a module as a black box with inputs and outputs — similar to a function, but representing a physical circuit block.

module and_gate (
    input  wire a,
    input  wire b,
    output wire y
);

    assign y = a & b;   // continuous assignment

endmodule
  

This describes a simple 2-input AND gate. The assign statement creates a continuous, always-active connection — exactly like a real wire driven by a gate.

Data Types You'll Use Most

  • wire – represents a physical connection; driven continuously by assign or a gate/module output.
  • reg – holds a value between procedural assignments (used inside always blocks). Despite the name, it doesn't always mean a physical register.
  • integer – a 32-bit signed variable, mainly for simulation/loop counters.
  • parameter – a compile-time constant, useful for configurable widths or values.

Two Modeling Styles: Structural and Behavioral

1. Structural modeling — you connect predefined gates or modules like wiring a circuit diagram:

module mux2to1_structural (
    input  wire a, b, sel,
    output wire y
);
    wire not_sel, and1, and2;

    not (not_sel, sel);
    and (and1, a, not_sel);
    and (and2, b, sel);
    or  (y, and1, and2);
endmodule
  

2. Behavioral modeling — you describe what the circuit should do, and let the synthesis tool figure out the gates:

module mux2to1_behavioral (
    input  wire a, b, sel,
    output reg  y
);
    always @(*) begin
        if (sel)
            y = b;
        else
            y = a;
    end
endmodule
  

Sequential Logic: The always Block and Clocking

Most real designs need memory — flip-flops and registers that update on a clock edge. This is where the always @(posedge clk) construct comes in.

module d_flip_flop (
    input  wire clk,
    input  wire rst_n,
    input  wire d,
    output reg  q
);
    always @(posedge clk or negedge rst_n) begin
        if (!rst_n)
            q <= 1'b0;      // asynchronous reset
        else
            q <= d;         // non-blocking assignment
    end
endmodule
  

Notice the <= operator — this is a non-blocking assignment, used almost exclusively inside clocked always blocks. It models the fact that all flip-flops update simultaneously on the clock edge, not one after another. Combinational logic, on the other hand, typically uses the blocking assignment = inside always @(*) blocks.

Rule of thumb: Use <= for sequential (clocked) logic and = for combinational logic. Mixing them incorrectly is one of the most common beginner bugs.

A Practical Example: 4-Bit Counter

module counter_4bit (
    input  wire clk,
    input  wire rst_n,
    output reg [3:0] count
);
    always @(posedge clk or negedge rst_n) begin
        if (!rst_n)
            count <= 4'b0000;
        else
            count <= count + 1'b1;
    end
endmodule
  

Verifying Your Design: The Testbench

A testbench is a separate, non-synthesizable module used purely for simulation. It generates stimulus (like a clock) and checks outputs.

module tb_counter;
    reg clk = 0;
    reg rst_n = 0;
    wire [3:0] count;

    counter_4bit uut (.clk(clk), .rst_n(rst_n), .count(count));

    always #5 clk = ~clk;   // 10ns clock period

    initial begin
        rst_n = 0;
        #12 rst_n = 1;
        #100 $finish;
    end

    initial
        $monitor("Time=%0t count=%0d", $time, count);
endmodule
  

Common Operators Cheat Sheet

Category Operators
Bitwise& | ^ ~
Logical&& || !
Relational== != > < >= <=
Arithmetic+ - * / %
Shift<< >>
Concatenation{a, b}

Tools to Get Started

  • Icarus Verilog – free, open-source simulator, great for beginners.
  • Verilator – fast open-source Verilog-to-C++ simulator, industry-grade speed.
  • ModelSim/QuestaSim – widely used in industry for simulation.
  • Xilinx Vivado / Intel Quartus – for synthesizing designs onto real FPGAs.
  • EDA Playground – browser-based, no installation needed, perfect for quick experiments.

Where Verilog Is Used

Verilog powers the design of ASICs (custom chips), FPGAs (reconfigurable chips), CPUs, GPUs, memory controllers, communication protocols (like UART, SPI, I2C), and even entire open-source processor cores such as RISC-V implementations.

Final Thoughts

Verilog isn't just "another programming language" — it's a way of thinking about hardware as parallel, timed, physical structures rather than sequential instructions. Start small: build a gate, then a mux, then a flip-flop, then a counter, and simulate each one. Once the concurrency mindset clicks, everything else — FSMs, pipelines, even full CPUs — builds naturally on these same fundamentals.

Got questions about a specific Verilog construct or want the next post to cover Finite State Machines? Drop a comment below!

Post a Comment

0 Comments