Verilog Series · Module 02

Levels of Design Description in Verilog — VLSI Trainers
Verilog Series · Module 02

Levels of Design Description in Verilog

Understand the four abstraction levels Verilog supports — from transistor switches all the way up to behavioral system descriptions.

🏗 Overview — The Four Levels

The components of a target design can be described at different levels of abstraction using Verilog’s constructs. Each level trades off detail for compactness. One of Verilog’s key strengths is that all four can be freely mixed in the same design module.

Fig 1 — Verilog Abstraction Pyramid
4 — Behavioral Level always @(*) / if / while 3 — Data Flow Level assign y = a & b; 2 — Gate Level and g1(y, a, b); 1 — Switch Level nmos n1(out, in, g); Highest abstraction Lowest abstraction

1. Circuit / Switch Level

1
Circuit / Switch Level
Lowest abstraction — closest to transistors
nmos / pmos / cmos
  • The switch is the basic building block — it represents a MOS transistor.
  • Switches can be combined to form inverters and other gates at the next level of abstraction.
  • Verilog has MOS switch primitives built in: nmos, pmos, cmos, tran, etc.
  • Used to build basic circuits: inverters, logic gates, 1-bit dynamic and static memories.
  • Suitable for performance-critical or analog-adjacent circuits where transistor-level behavior matters.
When to use: Rarely — mainly for standard cell design or when you need to control transistor-level drive strength and timing precisely.

Fig 2 — CMOS Inverter at Switch Level

Switch-level Verilog for a CMOS inverter
module inverter (
  output out,
  input  in,
  input  vdd, gnd
);
  // PMOS pulls output high when input is low
  pmos p1(out, vdd, in);

  // NMOS pulls output low when input is high
  nmos n1(out, gnd, in);
endmodule
Circuit topology
     VDD
      |
   [pmos p1]  ← gate = in
      |
 in ──┤── out ──→ output
      |
   [nmos n1]  ← gate = in
      |
     GND

🔗 2. Gate Level

2
Gate Level (Structural Modeling)
Build circuits using ready-made gate primitives
and / or / nand / nor
  • All basic gates are available as built-in “Primitives”and, or, nand, nor, xor, xnor, not, buf.
  • Each primitive is defined by its inputs and outputs and can be instantiated directly.
  • Also called structural modeling — analogous to building a circuit on a breadboard or PCB. You must know the full circuit topology.
  • Hierarchical circuits can be built at this level.
  • Limitation: Beyond 20–30 gate primitives, design descriptions become unwieldy and debugging gets laborious.
Where you see it: Post-synthesis gate-level netlists produced by tools like Synopsys Design Compiler or Cadence Genus.

Fig 3 — AND Gate and NAND Gate at Gate Level

Verilog gate primitives — syntax: gate_type instance_name (output, inputs…)
// 2-input AND gate
and g1(y, a, b);          // y = a & b

// 3-input NAND gate
nand g2(y, a, b, c);      // y = ~(a & b & c)

// Chaining gates to build an AOI function
wire ab, cd;
and  g3(ab, a, b);        // ab = a & b
and  g4(cd, c, d);        // cd = c & d
nor  g5(y,  ab, cd);      // y  = ~(ab | cd)  →  AOI
Built-in gate primitives
and nand or nor xor xnor not buf bufif0/1 notif0/1

🌊 3. Data Flow Level

3
Data Flow Level
Describe logic using continuous assignments
assign
  • All logic is described using the assign keyword — called a continuous assignment.
  • Every assignment runs concurrently — any change on the right-hand side immediately updates the output.
  • All logic and algebraic operations on signals and variables can be represented here.
  • Design descriptions are more compact than gate level — no need to know the gate topology, only the logical relationship.
  • Easily synthesizable — tools map assignments directly to logic cells.
Key rule: The left-hand side of an assign must be a wire (net), not a reg.

Fig 4 — Data Flow Examples

assign keyword — all statements run simultaneously
// Simple logic functions
assign y   = a & b;             // AND
assign y   = a | b;             // OR
assign y   = ~a;               // NOT (inverter)
assign y   = a ^ b;             // XOR

// AOI: AND-OR-INVERT
assign y   = ~((a & b) | (c & d));

// Multiplexer using ternary operator
assign out = sel ? data1 : data0;

// 4-bit adder with carry
assign {cout, sum} = a + b + cin;

// All three assignments below run at the same time
assign p = a & b;
assign q = c | d;
assign r = p ^ q;    // p and q are always up-to-date

🧠 4. Behavioral Level

4
Behavioral Level
Highest abstraction — describe what the circuit does, not how
always / initial
  • The highest level of design description — essentially describes system behavior.
  • Uses always and initial procedural blocks, with if/else, case, for, while — looks like a C program.
  • Statements are dense in function — a few lines can describe complex behavior.
  • Makes development fast and efficient. Ideal for testbenches, complex controllers, algorithms.
  • Caution: Not all behavioral constructs are synthesizable. Synthesis tools may produce incorrect or redundant hardware from some constructs.
Synthesis note: If a behavioral block doesn’t synthesize correctly, rewrite it at data-flow or gate level. Always check synthesis reports for unintended latches or logic.

Fig 5 — Behavioral Examples

Procedural blocks — always and initial
// Combinational logic (always @* — sensitive to all inputs)
always @(*) begin
  if (sel)
    out = data1;
  else
    out = data0;
end

// Sequential logic — D flip-flop with synchronous reset
always @(posedge clk) begin
  if (reset)
    Q <= 1'b0;
  else
    Q <= D;
end

// Case statement — 4-to-1 mux
always @(*) begin
  case (sel)
    2'b00: out = in0;
    2'b01: out = in1;
    2'b10: out = in2;
    2'b11: out = in3;
  endcase
end

// Initial block — testbench only (not synthesizable)
initial begin
  clk = 0;
  reset = 1;
  #10 reset = 0;
  #100 $finish;
end

🔀 Mixed-Mode Design

One of Verilog’s most powerful characteristics is that all four levels can coexist seamlessly within a single design module. You are not forced to stay at one level.

Fig 6 — Mixing Abstraction Levels in One Design
Top level
Behavioral
Controller logic
always @(*)
Mid level
Data Flow
Datapath ops
assign sum = a+b
Low level
Gate Level
Critical path
and / nand / nor

A common real-world pattern:

module top ( ... );

  // Behavioral — controller FSM
  always @(posedge clk) begin
    state <= next_state;
  end

  // Data Flow — combinational datapath
  assign result = op_a + op_b;

  // Gate Level — instantiate a critical cell manually
  nand g_fast(fast_out, p, q);

  // Module instantiation — structural composition
  my_adder u1 (.a(x), .b(y), .sum(s));

endmodule
Best practice: Use behavioral for control logic, data-flow for arithmetic/combinational datapaths, and gate-level only for timing-critical paths or post-synthesis netlists.

📊 Level Comparison Table

A quick side-by-side reference of all four levels:

Level Basic Element Key Construct Synthesizable? Compactness Typical Use
Switch MOS transistor nmos, pmos ✅ Yes Very verbose Standard cell design
Gate Logic gate and, nor, xor ✅ Yes Verbose Post-synthesis netlists
Data Flow Logical expression assign ✅ Yes Compact Combinational datapaths
Behavioral Procedural statement always, if, case ⚠️ Mostly Most compact Controllers, testbenches
⚠️ Behavioral synthesis caution: Constructs like initial, delays (#10), and some loop patterns are not synthesizable. Use them only in testbenches, not in RTL that will go through synthesis.

Concurrency in Verilog

In a real electronic circuit, all components are active and changing simultaneously. Verilog simulators are designed to model this parallel reality.

🔄
Parallel Execution
All always blocks and assign statements run in parallel — unlike sequential C programs where one line executes after another.
Simulation Time Steps
The simulator advances in equal time steps (smaller than the smallest propagation delay). All events at one step complete before moving to the next.
🕐
Simulation vs Real Time
Time step values are simulation time, not real time. Timescales can be redefined using `timescale to match your technology node.
📋
Sequential Exception
Sequential behavior (registers, memories) is modeled using always @(posedge clk) — concurrency and sequential operation are not mutually exclusive in Verilog.

Fig 7 — Concurrent vs Sequential Execution

Both always blocks below run at the same simulated time
// These two blocks run CONCURRENTLY — both respond to clk at the same time

always @(posedge clk) begin
  reg_a <= data_in;        // Block 1
end

always @(posedge clk) begin
  reg_b <= reg_a;          // Block 2 — reg_a here is the OLD value
end

// ⚠️ Non-blocking (<=) ensures both blocks read old values before any update
// This is why flip-flop chains work correctly in Verilog
Non-blocking vs Blocking: Use <= (non-blocking) inside clocked always blocks to correctly model flip-flops. Use = (blocking) in combinational always @(*) blocks. Mixing them incorrectly is a common source of simulation vs synthesis mismatches.

Leave a Comment

Your email address will not be published. Required fields are marked *

Scroll to Top