Skip to content

Verilog · Chapter 11.1 · Gate-Level Modeling

Predefined Gate Primitives in Verilog — and, or, not, xor & Tri-State Gates

Verilog ships with a set of built-in gate primitives, logic gates you can instantiate directly with no definition needed. They are the alphabet of gate-level structural modeling: the multi-input logic gates such as and, nand, or, nor, xor, and xnor, the buffers and inverters buf and not, and the tri-state gates that drive a high-impedance value under control. This lesson drills their syntax, including the terminal-ordering rule that the output comes first, the multi-input and multi-output forms, and the tri-state control behaviour, and how they wire together into structural circuits. You read gate primitives far more often than you write them, since synthesized netlists are made of them, so the goal here is fluency in recognizing and reasoning about gate-level structure rather than authoring functional RTL this way.

Foundation15 min readVerilogGate PrimitivesStructuralTri-StateNetlistRTL Design

Chapter 11 · Section 11.1 · Gate-Level Modeling

1. The Engineering Problem

Open a synthesized netlist and you see thousands of lines like `and U123 (n45, n12, n33);`. To read it — to follow how the gates connect, debug a gate-level simulation, or understand a library cell — you must know the gate primitives and the one rule that governs them:

Verilog's built-in gate primitives instantiate logic gates directly, with the output terminal first and inputs after. Reading gate-level structure means knowing the primitives and this terminal order.

This page teaches the primitives — the logic gates, buffers, and tri-state gates — and how they compose. It is the vocabulary for reading the netlist level.

2. Mental Model — Gates Instantiated Like Tiny Modules

3. Multi-Input Logic Gates

The core logic gates take any number of inputs and produce one output:

logic-gates.v
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
   and  (y, a, b);          // y = a & b
   and  (y, a, b, c, d);    // y = a & b & c & d   (any number of inputs)
   nand (y, a, b);          // y = ~(a & b)
   or   (y, a, b);          // y = a | b
   nor  (y, a, b);          // y = ~(a | b)
   xor  (y, a, b);          // y = a ^ b
   xnor (y, a, b);          // y = ~(a ^ b)
  • The first terminal is the output, the rest are inputs.
  • They accept two or more inputs`and (y, a, b, c, d)` is a 5-input AND. The function extends naturally (AND of all inputs, OR of all inputs, XOR/parity of all inputs).
  • These are the structural equivalents of the bitwise operators (10.4) on scalars — `and (y, a, b)` is the gate-level form of `assign y = a & b;`.

4. Buffers and Inverters

buf (buffer) and not (inverter) have one input but may drive multiple outputs — so their terminal order is reversed: outputs first, the single input last.

buf-not.v
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
   not (y, a);              // y = ~a
   buf (y, a);              // y = a   (drives/strengthens the signal)
 
   not (y1, y2, a);         // TWO outputs, one input: y1 = ~a, y2 = ~a
   buf (z1, z2, z3, a);     // three outputs, one input
  • `not` inverts; `buf` passes through (used to drive a signal to multiple loads or strengthen it).
  • The last terminal is the single input; all earlier terminals are outputs. This is the inverse of the logic-gate convention — a frequent point of confusion.
  • The multi-output form is a structural convenience (fan-out from one input).

5. Tri-State Gates

The tri-state gates drive their output or put it in high-impedance (z) based on a control input — the structural form of a tri-state driver (Chapter 5):

tristate.v
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
   bufif1 (y, a, ctrl);     // y = ctrl ? a    : 1'bz   (drive when ctrl=1)
   bufif0 (y, a, ctrl);     // y = ctrl ? 1'bz : a      (drive when ctrl=0)
   notif1 (y, a, ctrl);     // y = ctrl ? ~a   : 1'bz   (inverting, drive when ctrl=1)
   notif0 (y, a, ctrl);     // y = ctrl ? 1'bz : ~a     (inverting, drive when ctrl=0)
  • Terminals: output, input, control`bufif1 (out, in, ctrl)`.
  • `bufif1` drives when control is 1, high-impedance otherwise; `bufif0` is the opposite polarity; the `notif` variants invert the data.
  • These build tri-state buses: multiple `bufif` gates driving a shared net, one enabled at a time (the shared net is a tri, Chapter 5.1.1). If two drive at once, the net contends.

6. Building Structural Circuits

Gate primitives compose into circuits by wiring their terminals through internal nets:

structural-mux.v
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
module mux2_gates (
    input  a, b, sel,
    output y
);
    wire nsel, a_path, b_path;
    not (nsel, sel);              // nsel = ~sel
    and (a_path, a, nsel);        // a when sel=0
    and (b_path, b, sel);         // b when sel=1
    or  (y, a_path, b_path);      // combine
endmodule

This 2:1 mux is four gate instances and three internal nets — the structural equivalent of `assign y = sel ? a : b;` (Chapter 13.2). Notice the verbosity: four lines and three named nets for what dataflow does in one line. That contrast is exactly why gate-level is reference, not authoring: you read this in a netlist, but you write the dataflow form.

Visual A — gate primitives wire into a structural circuit

Structural 2:1 mux from gate primitivesnot (nsel, sel)invert selectand (a_path, a, nsel)a when sel=0and (b_path, b, sel)b when sel=1or (y, a_path,b_path)combine12
A 2:1 mux built from gate primitives: a NOT inverts sel, two ANDs gate a and b on the select, and an OR combines them — four gate instances wired by three internal nets. This is the structural form of assign y = sel ? a : b. The verbosity (four gates and three nets vs one dataflow line) is why gate-level is read, not authored.

7. Industry Perspective

  • Netlists are gate primitives (or cells). A synthesized netlist instantiates standard-cell modules (or, for simple cases, gate primitives) wired by nets — reading it is reading gate-level structure.
  • Tri-state gates model real bus drivers. `bufif` structures model on-chip and off-chip tri-state buses, where multiple drivers share a net under enable control.
  • Hand gate-level is rare and deliberate. Engineers occasionally hand-instantiate a specific gate (a particular cell, a clock buffer, a tri-state driver) where they need exact control, but functional logic is written in dataflow/behavioural.
  • Terminal order is a reading discipline. Knowing output-first for logic gates and output(s)-first/input-last for buffers is essential to correctly follow signal flow in a netlist.

8. Common Mistakes

  1. Misreading the output terminal as an input — the output is first for logic gates (§2/§3).
  2. Confusing buf/not terminal order — buffers/inverters put outputs first and the single input last (§4).
  3. Tri-state contention — two `bufif` gates enabled onto one net at once contend (§5).
  4. Hand-writing gate-level for functional logic — verbose and error-prone; use dataflow (§6).
  5. Expecting to define primitives — they are built in; no module definition (Ch 11 overview).

9. Debugging Lab

Two gate-primitive debug post-mortems

Pitfall 1 — output and input terminals swapped
Buggy Code
module and_gate (input a, b, output y);
  // Intent: y = a & b. But the terminals are in the wrong order.
  and (a, y, b);              // BUG: 'a' treated as output, 'y' as input
endmodule

// The first terminal of 'and' is the OUTPUT. Here 'a' is in the output
// position, so the gate drives 'a' (an input port!) from y & b — backwards
// and illegal (driving an input).
Symptom

A gate-level AND fails to compile (driving an input port) or, if the signals were internal, computes the wrong thing — the gate appears to drive the wrong net. The logic 'looks' like an AND of a and b.

Root Cause

Terminal order. For a logic-gate primitive, the FIRST terminal is the OUTPUT and the rest are inputs. Writing 'and (a, y, b)' puts 'a' in the output position, so the gate tries to drive 'a' from 'y & b' — backwards from the intended 'y = a & b', and illegal when 'a' is an input port.

The fix is to put the output terminal first: and (y, a, b).

Fix
module and_gate (input a, b, output y);
  and (y, a, b);             // output first: y = a & b
endmodule

// Output terminal first, inputs after. (For buf/not it is reversed:
// outputs first, the single input last.)
Pitfall 2 — two tri-state drivers enabled at once
Buggy Code
module bus_driver (
  input  a, b, en_a, en_b,
  output y
);
  // Intent: a or b drives the bus 'y', one at a time. But both enables
  // can be high together.
  bufif1 (y, a, en_a);
  bufif1 (y, b, en_b);       // both bufif1 drive 'y' when en_a & en_b
endmodule

// If en_a and en_b are both 1, both buffers drive 'y' at once. Where a and
// b disagree, the shared net contends and resolves to x.
Symptom

A tri-state bus shows x (unknown) values intermittently — specifically when two sources are enabled simultaneously and disagree. With one enable high at a time it works.

Root Cause

Tri-state contention. Two bufif1 gates drive the same net 'y'. When both controls (en_a, en_b) are high, both buffers drive at once; where their data disagree, the shared net (a tri) resolves to x. A tri-state bus requires that AT MOST ONE driver is enabled at any time — the enables must be mutually exclusive.

The fix is to guarantee one-at-a-time enables (e.g. drive them from a one-hot decoder, 13.2) so only one bufif drives the bus.

Fix
module bus_driver (
  input  a, b, sel,
  output y
);
  // Mutually-exclusive enables from a single select:
  bufif1 (y, a, ~sel);       // a drives when sel=0
  bufif1 (y, b,  sel);       // b drives when sel=1
endmodule

// Exactly one buffer is enabled for any 'sel', so the bus never contends.

10. Interview Q&A

11. Exercises

Exercise 1 — Read the gate

Give the function of each: (a) and (y, a, b, c); (b) nor (y, a, b); (c) not (z, x); (d) bufif0 (y, d, en); (e) xor (p, a, b, c).

Exercise 2 — Identify the output

For each instance, name the output terminal: (a) or (w, x, y, z); (b) buf (a, b); (c) not (m, n, p); (d) nand (q, r, s).

Exercise 3 — Build structurally

Write a gate-level (structural) half adder: sum = a ^ b, carry = a & b, using gate primitives.

Exercise 4 — Fix the gate-level bugs

Identify and fix each: (a) and (a, b, y) intending y = a & b; (b) not (a, y1, y2) intending two inverted outputs of one input.

12. Summary

Verilog's built-in gate primitives instantiate logic gates directly for structural (gate-level) modeling:

  • Multi-input logicand, nand, or, nor, xor, xnor: output terminal first, then any number of inputs.
  • Buffers/invertersbuf, not: output(s) first, single input last; can fan out to multiple outputs.
  • Tri-statebufif0/1, notif0/1: output, input, control; drive or high-impedance, for tri-state buses with mutually-exclusive enables.

The discipline this page instils:

  • Output terminal first for logic gates (and outputs-first/input-last for buffers) — the key reading rule.
  • One enable at a time on a tri-state bus — multiple drivers contend.
  • Read gate-level, author dataflow — netlists are gate primitives; new RTL is not.

The next page adds timing: Chapter 11.2 Gate Delays covers the delay specifications you can put on gate primitives — rise, fall, and turn-off delays, the min:typ:max form, and why they are a simulation-only modeling tool.