Skip to content
VLSI Mentor

Verilog · Chapter 1 · Foundations

Introduction & Overview of Verilog HDL

Verilog is the text that digital hardware is described in. This chapter teaches you to read it as hardware rather than as a program. You will meet a real Verilog module in the first few minutes, then unpack it: what logic the code describes, why hardware behaves concurrently instead of line by line, when a value changes immediately and when it changes only on a clock edge, what a simulator shows you, and what a synthesis tool can build from it. Everything later in this track — data types, operators, modeling styles, timing — assumes the way of reading you build here.

Foundation35 min readRTLHDLVerilogSimulationSynthesis

Chapter 1 · Page 1.1 · Foundations

1. The Engineering Problem

A modern chip contains an enormous number of transistors — billions on a large design. Nobody draws them.

Early digital design worked from schematics: an engineer drew gates and wired them together by hand in a CAD tool. That works for tens or hundreds of gates. It does not work for a million. Drawing by hand does not scale, and neither does reviewing, changing, or sharing a drawing that large.

So engineers stopped drawing hardware and started describing it. They write a text file that says what the hardware should contain and how it should behave. Software tools read that text and produce the actual gate-level implementation.

That text file is written in Verilog.

This is the idea the whole chapter rests on: Verilog is a way of describing hardware in text, so that tools can build it.

2. Why an HDL Exists

A hardware description language (HDL) is a language whose purpose is to describe digital circuits. Verilog is one; VHDL is another.

Text gives you two things a drawing cannot.

First, text scales. A counter is ten lines of Verilog. The same counter as a schematic is dozens of shapes and wires. Text is faster to write, easier to review, and works with ordinary version control — you can diff two revisions of a design the same way you diff two revisions of a program.

Second, you can describe behaviour instead of structure. You do not have to name every gate. You can write what the circuit should compute, and a synthesis tool works out an implementation that does it. That raises how much hardware one engineer can produce, which is what makes large designs practical at all.

There is a trade-off: you give up direct control over exactly which gates appear, in exchange for working at a scale where naming every gate is impossible.

Verilog dates from the mid-1980s, developed at Gateway Design Automation by Phil Moorby and colleagues, and became an IEEE standard in 1995.

2.1 Where the standards sit

Three names come up constantly. Keeping them straight now saves confusion later.

  • Verilog — the hardware description language this track teaches. Its last standalone IEEE standard is IEEE 1364-2005.
  • SystemVerilog / IEEE 1800 — a much larger language that contains Verilog. In 2009 the Verilog standard was merged into IEEE 1800, so since then there is no separate Verilog document being revised; IEEE 1800 is the maintained standard.
  • What that means for you. SystemVerilog adds a great deal on top — especially for verification, where it is the normal choice — and design constructs many teams use for synthesisable code. But its design half is built on the Verilog core: modules, ports, nets, variables, continuous assignments, procedural blocks, clock edges.

This track teaches that core deliberately. It is the part that does not change, it is what you will read in existing code, and it is what the SystemVerilog track builds on.

3. Look at One First

Before any more theory, here is real Verilog. This is a complete, valid module.

Azvya Education Pvt. Ltd.VLSI Mentor
and_gate.v — a complete Verilog module
module and_gate (
    input  wire a,
    input  wire b,
    output wire y
);

    assign y = a & b;

endmodule

This code describes one small piece of combinational hardware: a two-input AND function. a and b are inputs, y is the output, and y is always the AND of the two inputs.

Do not worry yet about what each keyword means. The point of showing it now is the shape of the thing: a named block of hardware, with inputs and outputs, and a statement describing what the output is. Almost every Verilog file you ever open has that shape.

The next several sections build the way of reading that this code needs. Then §8 comes back and unpacks it line by line.

4. A Blueprint, Not a Recipe

Treat that as a mental model, not a literal account of what tools do. A blueprint has a one-to-one relationship with the building; Verilog does not have a one-to-one relationship with a specific set of gates. A synthesis tool is free to implement your description in many different ways, and it will choose based on the target technology and the speed, area, and power goals it is given. What stays fixed is the behaviour you described — not the exact gates that end up implementing it.

So the useful habit is not "which gate is this line?" It is:

What hardware behaviour does this code describe, and when does it change?

Two words matter there. Behaviour — because that is what you control. When — because hardware exists in time, and that is the part beginners miss.

5. Hardware Exists Concurrently

This is the single idea that separates reading Verilog from reading a program, so it is worth doing properly rather than just asserting.

Here is a small module with two continuous assignments:

Azvya Education Pvt. Ltd.VLSI Mentor
and_or.v — two assignments, written in one order
module and_or (
    input  wire a,
    input  wire b,
    input  wire c,
    output wire y
);

    wire x;

    assign x = a & b;
    assign y = x | c;

endmodule

Now the same module with the two assignments written in the opposite order:

Azvya Education Pvt. Ltd.VLSI Mentor
and_or.v — the same two assignments, written in the other order
module and_or (
    input  wire a,
    input  wire b,
    input  wire c,
    output wire y
);

    wire x;

    assign y = x | c;
    assign x = a & b;

endmodule

These two modules describe exactly the same hardware. Both describe:

  • an AND function producing x from a and b,
  • an OR function producing y from x and c,
  • a connection carrying x from the first to the second.

In the second version, the y assignment is not "running before x has a value" and it is not "waiting" for the other line. Neither line runs. Both describe connections that exist at the same time. If a changes, the AND logic responds, x changes, and because the OR logic is permanently connected to x, it responds too. The order you typed them in never enters into it.

Swapping two lines of a program usually changes the result. Swapping two continuous assignments changes nothing at all — which is what concurrent means: everything described inside a module is present simultaneously.

6. Where Verilog Fits in the VLSI Flow

Verilog is not the whole design process; it is one artefact near the start of it, and almost everything downstream is derived from it.

Where Verilog sits

data flow
Where Verilog sitsSpecificationwhat it must doVerilog RTLdesign, as textSimulationdoes it behave?SynthesisRTL → gatesImplementationplace, routeSilicon / FPGAthe real device
The Verilog source is the design; everything downstream is derived from it.

A mistake in that source is the cheapest kind to find and the most expensive kind to miss.

One thing from this picture matters for Chapter 1: your source is read by two very different tools, and they want different things from it. A simulator runs your description to show how it behaves; a synthesis tool produces hardware from it. Part of the language exists only to control a simulation and cannot be built at all. §12 is about that split.

The full industrial flow has many more stages than the six above — architecture, lint, timing analysis, physical design, sign-off. That is the next chapter, Typical VLSI Design Flow. This simplified spine is all Chapter 1 needs.

7. The Module — Inputs, Outputs, and Hierarchy

A module is a block of hardware with inputs and outputs. That is the whole idea; the formal wording — Verilog's unit of hardware description and of hierarchy — says the same thing more precisely. Everything you write in Verilog lives inside a module.

and_gate module with inputs a and b on the left and output y on the rightand_gate2-input AND · combinational2-input AND · combinationalaby6
A module seen from outside — a named box with signals entering and leaving.

Whoever uses your module only needs to know that boundary; what is inside is your problem to get right.

Three terms, defined once:

  • Port — a signal on the module's boundary. Ports are how a module connects to the outside world.
  • Input / output — the direction of a port. An input is driven from outside; an output is driven by this module.
  • Internal signal — a signal declared inside the module that does not appear on the boundary. wire x; in §5 was one: it carries a value between two pieces of logic and is invisible from outside.

7.1 Modules can contain other modules

A module can use another module inside it. This is called instantiation, and it is how real designs are built: small blocks combined into larger ones.

Azvya Education Pvt. Ltd.VLSI Mentor
and_pair.v — one module using another module twice
module and_pair (
    input  wire a0,
    input  wire b0,
    input  wire a1,
    input  wire b1,
    output wire y0,
    output wire y1
);

    // Two separate instances of and_gate. Each instance is its own hardware.
    and_gate u_and0 (.a(a0), .b(b0), .y(y0));
    and_gate u_and1 (.a(a1), .b(b1), .y(y1));

endmodule

Read and_gate u_and0 (.a(a0), .b(b0), .y(y0)); as: "place a copy of and_gate here, call this copy u_and0, and connect its port a to my signal a0, its b to b0, its y to y0." The .port(signal) form is named port connection — the style to use, because it says explicitly which port goes where and so keeps working if the port list later changes order.

Hierarchy: module and_pair at the top with two and_gate instances u_and0 and u_and1 below itu_and0and_gateu_and1and_gateand_pairtop module
and_pair contains two instances of and_gate — instance name above, module type below.

Real designs nest this many levels deep: a chip is a module containing subsystems, containing blocks, containing gates.

Module instantiation and port mapping get a full treatment in Design and Testbench Creation (Chapter 9). Here you only need the idea: modules nest.

8. Reading the AND Gate Line by Line

Back to the module from §3, now with everything it needs to be a real file:

Azvya Education Pvt. Ltd.VLSI Mentor
and_gate.v — the same module, read closely
// Turn off implicit nets: a typo becomes a compile error, not a silent bug.
`default_nettype none

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

    // y is permanently the AND of a and b.
    assign y = a & b;

endmodule

Line by line:

  • `default_nettype none — a compiler directive. Without it, Verilog silently invents a one-bit wire for any name it does not recognise, so a misspelled signal compiles cleanly and quietly does nothing. With it, the misspelling is an error. Put it at the top of design files. (Compiler directives are Chapter 7.)
  • module and_gate ( ... ); — begins a module and names it. The parentheses hold the port list. input wire a declares a port named a, direction input, type wire; output wire y likewise.
  • wire — the type for a signal continuously driven by something else. It models a connection: it stores nothing and carries whatever drives it. (Nets are Chapter 5.1.1.)
  • assign y = a & b; — a continuous assignment. y is always equal to the expression on the right, so whenever a or b changes, y follows. (& is bitwise AND; operators are Chapter 10.)
  • endmodule — ends the module. No semicolon.

What hardware does this describe? Logic that continuously produces the AND of two signals. There is no clock and nothing is stored: the output depends only on the inputs as they are right now. That is what combinational means.

8.1 Signals wider than one bit

Real designs move groups of bits — bytes, addresses, counters — not single wires. Verilog writes that with a range in square brackets:

Azvya Education Pvt. Ltd.VLSI Mentor
and8.v — the same idea, eight bits wide
`default_nettype none

module and8 (
    input  wire [7:0] a,
    input  wire [7:0] b,
    output wire [7:0] y
);

    assign y = a & b;

endmodule

[7:0] means eight bits, numbered 7 down to 0. Bit 7 is the most significant; bit 0 is the least significant. A signal like this is called a vector.

assign y = a & b; is unchanged, and it now means something bigger: bit 0 of y is the AND of bit 0 of each input, bit 1 of y the AND of bit 1 of each, and so on. One line, eight independent AND functions, all operating at the same time. That is §5's concurrency again.

You will also meet literals written as 8'h00. Read that as "eight bits wide, in hex, value 00" — width, then base, then digits.

That is as much as Chapter 1 needs. Vectors, literals, arrays, and the full type system are Variables & Data Types (Chapter 5).

9. Driving It — Anatomy of a Testbench

You now have a module. How do you find out whether it works?

You write a second module whose job is to feed the first one inputs and report what came out. That second module is a testbench, and the module being tested is the DUT (device under test).

Azvya Education Pvt. Ltd.VLSI Mentor
and_gate_tb.v — exercising every input combination
`timescale 1ns/1ps
`default_nettype none

module and_gate_tb;                    // no ports — a testbench has no boundary

    reg  a, b;                         // driven by this testbench
    wire y;                            // driven by the DUT, observed here

    and_gate u_dut (.a(a), .b(b), .y(y));   // the design under test

    initial begin
        $display("time(ns)  a  b  |  y");
        $display("--------------------");

        a = 0; b = 0;  #10  $display("%8d  %b  %b  |  %b", $time, a, b, y);
        a = 0; b = 1;  #10  $display("%8d  %b  %b  |  %b", $time, a, b, y);
        a = 1; b = 0;  #10  $display("%8d  %b  %b  |  %b", $time, a, b, y);
        a = 1; b = 1;  #10  $display("%8d  %b  %b  |  %b", $time, a, b, y);

        $finish;
    end

endmodule

Take it apart:

  • A testbench is also a module. Same keyword, same structure. Nothing new to learn.
  • It has no ports. Nothing outside connects to it — it is the outermost thing in the simulation. That empty boundary is how you recognise a testbench at a glance.
  • It declares signals for the DUT's ports and instantiates the DUT with named port connections, exactly as in §7.1.
  • `timescale 1ns/1ps sets the file's time unit to 1 ns, which is what makes #10 mean 10 ns. (timescale is Chapter 7.3.)
  • initial begin ... end is a procedural block: it starts once at the beginning of the simulation and runs its statements in order. Inside a procedural block, order does matter — the one place in Verilog where sequence is meaningful, because writing a test is naturally a sequence of steps. (Procedural blocks are Chapter 14.1.)
  • #10 waits 10 ns of simulation time. $display prints a line; $finish ends the run. (System tasks are Chapter 8.)
  • These are testbench constructs, not design constructs. They exist to script a simulation and describe no hardware. Keep them in test files, out of the modules you intend to build.

9.1 Why a is reg and y is wire

Two shortcuts you will hear are both wrong: "reg means input, wire means output," and "wire is combinational, reg is sequential." Here is the actual rule.

Verilog has two families of signal:

  • A net (wire) models a connection. It holds nothing; it carries whatever is driving it. You drive a net with a continuous assignment or by connecting it to a module output.
  • A variable (reg) is assigned by procedural statements — the ones inside initial and always blocks — and keeps the value last assigned to it until something assigns it again.

In this testbench, a and b are set inside an initial block, so they must be variables: reg. y is driven by the DUT's output port, so it must be a net: wire.

The rule is about how a signal is assigned, not about direction and not about what hardware it becomes. reg is short for "register," which makes it sound like declaring one creates storage. It does not. Whether procedural code describes combinational logic, storage, or simulation-only behaviour depends entirely on how the block is written — §13 shows the same keyword doing two different jobs. Read reg as "procedurally assigned," never as "flip-flop." Nets and variables get their full treatment in Variables & Data Types (Chapter 5).

9.2 What the simulation prints

Running the DUT and the testbench together produces:

Azvya Education Pvt. Ltd.VLSI Mentor
Simulation output
time(ns)  a  b  |  y
--------------------
      10  0  0  |  0
      20  0  1  |  0
      30  1  0  |  0
      40  1  1  |  1

$time returns the current simulation time in the file's time unit, which `timescale 1ns/1ps set to 1 ns — so these are nanoseconds. Each line is printed after a #10 wait, so it reports the inputs that were applied 10 ns earlier, along with the output they produced.

Read the right-hand column on its own: 0, 0, 0, 1. That is the AND truth table. The module does what it claims.

10. Watching It — the Waveform

Printed text is fine for four lines. For anything real you want a waveform: every signal's value drawn against time. Here is the same run.

and_gate — four input combinations

8 cycles
and_gate — four input combinations0 & 0 = 00 & 0 = 00 & 1 = 00 & 1 = 01 & 0 = 01 & 0 = 01 & 1 = 11 & 1 = 1abyt0t1t2t3t4t5t6t7
Inputs on top, derived output below — y re-derives whenever a or b changes.

Two things to read off it:

  1. Inputs change, and the output responds. There is no clock here and none is needed. The output is a function of the inputs as they currently are, and it is never stored — cover the inputs and you cannot say what y should be.
  2. Compare against what you expected. That is what a waveform is for. You predicted an AND truth table before opening it; each marker confirms one row.

11. Adding Time — Your First Flip-Flop

Everything so far has been combinational: output determined by inputs, right now. Useful hardware also needs to remember — counters, state machines and pipelines all hold a value from one moment to the next.

A circuit that remembers has state, and in Verilog you describe state by saying when a value should be captured. The smallest possible example:

Azvya Education Pvt. Ltd.VLSI Mentor
dff.v — a D flip-flop
`default_nettype none

module dff (
    input  wire clk,
    input  wire d,
    output reg  q
);

    // On each rising edge of clk, q takes the value d had at that edge.
    always @(posedge clk)
        q <= d;

endmodule

Read it slowly:

  • d is the value waiting to be stored. It can change whenever it likes.
  • clk is the clock — a signal that alternates between 0 and 1 and decides when storage happens.
  • posedge clk means the rising edge: the instant clk goes from 0 to 1.
  • always @(posedge clk) means: every time that instant arrives, do what follows. Between those instants, do nothing.
  • q <= d; samples d at that edge and updates q from the sampled value. Read <= for now as "the value of d at this edge becomes the new q"; why it is written that way rather than = is Blocking and Non-Blocking Assignments (Chapter 14.3).
  • output reg q — q is assigned inside a procedural block, so it is a variable, per §9.1.

The behaviour in one sentence: q changes only at a rising clock edge, and between edges it holds. In the AND gate the output had no choice — it followed its inputs continuously. Here d can wander around and q ignores it until an edge arrives.

What hardware does this describe? Something that stores a bit and updates it on a clock edge — a flip-flop. Whatever the target technology, the implementation needs a storage element with a clock input.

D flip-flop with data input d, clock input clk, and output qD-FFdDclkqQ
A D flip-flop — d in, clk on the edge-triggered input, q out.

The triangle at the clock input is the standard symbol for edge-triggered: it marks the one input that decides when, rather than what.

11.1 Driving the flip-flop

The testbench needs one thing the previous one did not: a clock.

Azvya Education Pvt. Ltd.VLSI Mentor
dff_tb.v — a clock and a changing d
`timescale 1ns/1ps
`default_nettype none

module dff_tb;

    reg  clk;
    reg  d;
    wire q;

    dff u_dut (.clk(clk), .d(d), .q(q));

    // Free-running clock: 10 ns period, so a rising edge every 10 ns
    // starting at 5 ns.
    initial begin
        clk = 1'b0;
        forever #5 clk = ~clk;
    end

    // Change d between edges, never on one, so what each edge captures
    // is unambiguous.
    initial begin
        d = 1'b0;
        #10  d = 1'b1;      // at 10 ns
        #20  d = 1'b0;      // at 30 ns
        #10  $finish;       // at 40 ns
    end

    // Print 1 ns after each edge, once q has settled.
    always @(posedge clk)
        #1 $display("%8d  edge: captured d = %b  ->  q = %b", $time, d, q);

endmodule
Azvya Education Pvt. Ltd.VLSI Mentor
Simulation output
       6  edge: captured d = 0  ->  q = 0
      16  edge: captured d = 1  ->  q = 1
      26  edge: captured d = 1  ->  q = 1
      36  edge: captured d = 0  ->  q = 0

One detail worth naming: the stimulus changes d at 10 ns and 30 ns — between rising edges, never on one — so there is no doubt about which value each edge sampled. Driving a signal at the exact instant a flip-flop samples it is genuinely ambiguous, and disciplined testbenches avoid it.

11.2 The sequential waveform

dff — q follows d, but only at rising clock edges

8 cycles
dff — q follows d, but only at rising clock edges1 · d=0 → q=01 · d=0 → q=02 · d=1 → q=12 · d=1 → q=13 · d=1 → q=13 · d=1 → q=14 · d=0 → q=04 · d=0 → q=0clkdqt0t1t2t3t4t5t6t7
The rule for reading any sequential waveform: at each rising edge, look at d. That value becomes the new q. Everywhere else, q holds.

Work through it once, and the mental model is yours:

  • At edge 1, d is 0. So q becomes 0.
  • Between edge 1 and edge 2, d rises to 1. q does not move. There is no edge, so nothing is sampled. This is the important bit: d changed and q did not.
  • At edge 2, d is 1. So q becomes 1.
  • At edge 3, d is still 1. q stays 1.
  • At edge 4, d is back to 0. So q becomes 0.

Note what decides the delay between d changing and q changing: not a fixed clock period, but how long it is until the next active edge. Here d rose in the middle of a cycle, so q waited until the following edge. Had d risen shortly before an edge, that same edge would have sampled it. The rule is only ever "at each active edge, sample d; between edges, hold."

You now have the two halves of the model — combinational, which changes whenever its inputs change, and sequential, which changes only at a clock edge. For any line of Verilog you read from here on, ask which one it is. Asking that question is most of what reading RTL consists of.

12. Simulation and Synthesis — Two Questions, One Language

The same Verilog file is read by two kinds of tool, and each is asking a different question.

A simulator asks: "What will this design do over time?" It models the behaviour your code describes and runs it against your testbench's stimulus, recording every signal at every moment. Output: logs and waveforms.

A synthesis tool asks: "What hardware can implement this behaviour?" It maps your description onto the resources of a chosen target — standard cells for an ASIC, lookup tables and flip-flops for an FPGA — optimising as it goes. Output: an implementation that later stages turn into a working device.

Because the questions differ, so does what each tool can use:

ConstructIn simulationFor synthesis
assign y = a & b;Re-evaluates whenever an operand changesCombinational logic
always @(posedge clk) q <= d;Updates q at each rising edgeA storage element with a clock
#10Advances simulation time by 10 unitsNo hardware meaning — keep it out of design code
$display, $finishPrints, and ends the runNot hardware — testbench services
initialRuns once at the startTarget-dependent — see below

On initial specifically. You will read that initial is never synthesisable. That is too absolute: it is overwhelmingly a simulation and testbench construct, and that is how this track uses it, but some FPGA flows do support limited initialisation. Whether it means anything depends on your target and tool. So rather than memorising a rule that is not universally true, adopt the portable habit — give state a defined starting value through your design's intended reset methodology, not through an initial block. Reset arrives in RTL Designing (Chapter 3); the flip-flop in §11 was left without one only to keep the first sequential example small.

13. Common Beginner Mistakes

Three mistakes, all of them mental-model failures rather than typos. Each one follows directly from something earlier in this chapter.

Mistake A — expecting source order to be execution order

The bug this produces is the accidental second driver. A beginner wants y to be a & b normally and c in some other situation, and reaches for a second assign.

❌ Two drivers on one net
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
assign y = a & b;
assign y = c;        // a second driver, not a replacement

Both statements describe permanent connections to y. Two sources now drive the same net at once, and where they disagree simulation resolves y to x — unknown.

✅ One driver, selection inside it
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
assign y = use_c ? c : (a & b);

One connection to y. The choice between the two values is made by logic inside the single driver, which is what a multiplexer is.

The general rule: a net should have exactly one driver. If you want a signal to take different values in different situations, express the choice as logic, not as two statements.

Mistake B — thinking reg always means a hardware register

reg says how a signal is assigned, not what hardware it becomes. The surrounding block is what decides.

reg y — describes combinational logic
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
reg y;

always @(*) begin
    y = a & b;
end

This block reacts to its inputs. y is re-derived whenever a or b changes, with no clock involved — the same behaviour as assign y = a & b;. No storage. y is reg only because it is procedurally assigned.

reg q — describes storage
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
reg q;

always @(posedge clk) begin
    q <= d;
end

This block runs only at rising clock edges. Between edges q keeps its value, so storage is described. Same keyword, different hardware — because the sensitivity is different.

The details of always @(*) are Behavioural Modeling (Chapter 14). The point here is only that the declaration tells you nothing on its own — look at what triggers the block.

Mistake C — letting testbench habits into a design module

1

A design module that kept its testbench habits

SIMULATION / HARDWARE MISMATCH
Buggy Code
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// Intended as a synthesisable design block.
module pulse_gen (
    input  wire clk,
    output reg  pulse
);

    initial pulse = 1'b0;      // set the starting value here

    always @(posedge clk) begin
        #2 pulse <= ~pulse;    // "wait 2 ns, then toggle"
    end

endmodule
Symptom

The RTL simulation looks exactly right — pulse starts at 0 and toggles every clock. After synthesis the tool warns about the delay, and the implemented hardware does not match: the 2 ns offset is gone, and on an ASIC target pulse has no guaranteed starting value.

Root Cause

Two testbench constructs ended up in a design module.

#2 is a simulation time control: it tells a simulator to pause and describes no hardware, so there is nothing for synthesis to build from it. Whether the tool warns, drops it, or rejects the file, simulated and implemented behaviour diverge.

initial pulse = 1'b0; was doing the job that reset should do, and its effect at power-on depends on the target and tool — an FPGA flow may honour it, an ASIC flow will not.

Fix
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
module pulse_gen (
    input  wire clk,
    input  wire rst_n,         // active-low reset
    output reg  pulse
);

    always @(posedge clk) begin
        if (!rst_n) pulse <= 1'b0;   // defined starting value
        else        pulse <= ~pulse; // timing comes from the clock
    end

endmodule

Timing now comes from the clock, which is the only thing that sequences hardware, and the starting value comes from an explicit reset that exists in the implemented design. Simulation and hardware agree, on any target.

14. Practical Debugging

When a design does not do what you expected, the productive routine is the same every time. It is a search for the first thing that is wrong, not an inspection of the thing that looks wrong.

  1. Find the first wrong signal, at the first wrong moment. Open the waveform and move backwards in time until the last point where everything was still correct. Wrong values spread, so where you noticed the problem is almost never where it started.
  2. Find what drives that signal. Every signal has one source — a continuous assignment, a procedural block, or a module output. Check its inputs, then repeat on those. The bug is where a source's inputs are right but its output is not.
  3. State what you expected before you look. Say it precisely — "at this edge, q should capture 1." Vague expectations produce vague debugging. Then compare, and see which half was wrong: your expectation, or the design.
  4. Check starting values. Much "strange behaviour at the beginning" is state that was never given a defined value. A signal showing x (unknown) from the start means storage with no reset.
  5. Shrink the failing case. A failure you can reproduce in three clock cycles is a failure you can understand.

Simulators also have precise rules about the order in which events are processed within a single moment of simulation time — the reason <= exists. A real topic, but not a first-chapter one: see Timing Regions (Chapter 19) and Blocking and Non-Blocking Assignments (Chapter 14.3).

15. Where Verilog Is Used

Briefly, so you know what you are learning toward.

RTL design. Writing the synthesisable modules that become the chip — datapaths, control logic, interfaces. This is the work everything in this track leads to.

Verification. Writing the test code that proves a design is correct before it is built, which is at least as much effort as designing it. Verification teams typically work in SystemVerilog, but every testbench begins with what §9 showed: instantiate the design, drive its inputs, check its outputs.

FPGA and ASIC. Two destinations for the same source.

ASICFPGA
What it isCustom silicon manufactured for one designAn off-the-shelf chip of programmable logic, configured to behave like your design
Cost shapeVery high one-time cost, very low per unitLow one-time cost, higher per unit
TurnaroundMonths from finished design to first chipsMinutes to hours from edit to running hardware
SuitsHigh volume productsPrototyping, lower volumes, designs that change

The Verilog you write can be largely the same for both; what differs is the synthesis tool and the hardware it targets. FPGAs are also how most people first run their own RTL on real hardware, which makes them an excellent way to learn.

To follow along you need a simulator. Free options such as Icarus Verilog and Verilator are more than enough for everything in these chapters, and the language is the same as in the commercial tools production teams use. Learn one well before trying a second.

16. Knowledge Check

Answer these in your own words before reading the answers. If an answer is only a definition you can recite, it has not landed yet.

17. Learning Roadmap

The Verilog track is nineteen chapters in five groups. Where this chapter sits, and what follows:

  • Foundations (Chapters 1–4). This page, then Typical VLSI Design Flow for the full path from specification to silicon, RTL Designing for the register-plus-logic style that real designs are written in, and Lexical Conventions for the rules every line of Verilog obeys.
  • Data & Variables (Chapters 5–7). Variables & Data Types develops the nets and variables introduced in §9.1, along with vectors and arrays. Then constants, and the compiler directives that `default_nettype and `timescale belong to.
  • System Tasks & Design (Chapters 8–9). System Tasks & Functions covers $display and its relatives properly; Design and Testbench Creation turns §9 into a full method, including module instantiation and port mapping.
  • Operators & Modeling (Chapters 10–14). The operator set, then the three modeling styles: gate-level, dataflow (where assign is developed in depth), and behavioural (procedural blocks, conditionals, loops, and the = versus <= question this chapter deferred).
  • Advanced Topics (Chapters 15–19). Tasks and functions, user-defined primitives, delay modeling, timing checks, and Timing Regions — the event-ordering rules underneath everything else.

Chapters 2 and 3 are the natural next steps and are best read in order.

18. Exercises

Work these before reading the answers below them. Writing a wrong answer and finding out why is worth more than reading a right one.

Exercise 1 — Code to hardware

For each snippet, say what hardware it describes, and whether the output changes as soon as an input changes or only at a clock edge.

Azvya Education Pvt. Ltd.VLSI Mentor
exercise-1a.v
assign y = a | b;
Azvya Education Pvt. Ltd.VLSI Mentor
exercise-1b.v
always @(posedge clk)
    count_q <= count_q + 1'b1;
Azvya Education Pvt. Ltd.VLSI Mentor
exercise-1c.v
assign y = a & b;
assign z = y | c;

Exercise 2 — Write a multiplexer

A 2-to-1 multiplexer passes one of two inputs through to its output, chosen by a select signal. Write a module mux2 with:

  • inputs sel (1 bit), a and b (8 bits each),
  • output y (8 bits),
  • behaviour: when sel is 0, y is a; when sel is 1, y is b.

Use `default_nettype none and a single continuous assignment. The conditional operator cond ? value_if_true : value_if_false is the usual way to write it.

Then say what hardware you have described, and whether y changes immediately or at a clock edge.

Exercise 3 — Predict a flip-flop waveform

Using the dff module from §11, determine q after each rising clock edge. d is listed as the value it holds at the moment of each edge.

Rising edged at the edgeq after the edge
11?
21?
30?
40?
51?

Then answer: between edge 2 and edge 3, d falls from 1 to 0. What is q during that interval, before edge 3 arrives?

Answers

Exercise 1a. Combinational logic producing the OR of a and b. y changes whenever a or b changes — no clock is involved and nothing is stored.

Exercise 1b. A counter: storage holding count_q, with combinational logic computing count_q + 1 feeding back into it. count_q changes only at rising clock edges; between edges it holds. Both kinds of logic are present — the adder is combinational, and the storage is what makes it a counter rather than just an adder.

Exercise 1c. Two pieces of combinational logic in series: an AND producing y, and an OR producing z from y and c. Both change whenever a relevant input changes; no clock, no storage. The two statements could be written in either order and describe the same hardware — §5 again.

Exercise 2.

Azvya Education Pvt. Ltd.VLSI Mentor
mux2.v
`default_nettype none

module mux2 (
    input  wire       sel,
    input  wire [7:0] a,
    input  wire [7:0] b,
    output wire [7:0] y
);

    // sel = 0 selects a; sel = 1 selects b.
    assign y = sel ? b : a;

endmodule

Check the polarity deliberately: sel of 1 yields b, sel of 0 yields a. That matches. Writing sel ? a : b gives a working multiplexer with the selection reversed — a bug that compiles cleanly and is easy to miss.

The hardware is combinational: eight 2-to-1 selections in parallel, one per bit. y changes as soon as sel, a or b changes; nothing is stored, because a multiplexer chooses rather than remembers. Note that a and b are both connected at all times — sel decides which reaches the output, not which one "runs."

Exercise 3.

Rising edged at the edgeq after the edge
111
211
300
400
511

q simply takes the value d had at each edge.

The follow-up is the one that matters. Between edge 2 and edge 3, d falls to 0 — and q stays 1 for that whole interval, because q only moves at an edge and the next edge has not arrived. If you answered that q follows d down immediately, re-read §11.2: that is the combinational reflex this chapter exists to replace.

19. Summary

The ideas worth carrying out of this chapter:

  • Verilog describes hardware. It is text that says what a circuit contains and how it behaves — not instructions that run in order.
  • Modules are blocks of hardware with inputs and outputs, and they nest. Instantiating a module twice creates two pieces of hardware.
  • Hardware exists concurrently. Everything described in a module is present at the same time. Reordering continuous assignments changes nothing.
  • assign describes combinational logic — a permanent relationship, with no memory. Its output depends only on its current inputs.
  • Storage introduces state, and state is what lets a design remember anything.
  • Clock edges decide when sequential state updates. Between edges, stored values hold — no matter what their inputs do.
  • Testbenches drive and observe a design in simulation. They are modules with no ports, and they use simulation-only constructs that do not belong in design code.
  • Simulation predicts behaviour over time; synthesis maps a synthesisable description onto hardware. The same file, two different questions.

And the habit underneath all of it — the question to ask of every line of Verilog you read from here on:

What hardware does this code describe, and when does it change?

If you can answer both halves, you are reading Verilog the way an RTL engineer reads it. Chapter 2 widens the view to the full design flow this description sits inside.

Standards & specifications

Governing standard
IEEE Std 1364 (Verilog)(opens IEEE in a new tab)

Defines the Verilog language and its simulation semantics, including the event scheduling model. Synthesis support is defined by tools, not by this standard.

This page also covers RTL structure, verification approach and debugging technique. Those are engineering practice built on the standard, not requirements the standard itself imposes.

Where this fits

Part of the Verilog HDL curriculum.