Skip to content
๐Ÿ“‘ Verilog Syntax Reference

๐Ÿ“‘ Verilog Syntax Reference

This notebook summarizes the core syntax elements of Verilog HDL. Each construct is annotated with its purpose, behavior, and contrast with similar features. Designed for semantic clarity, vault-grade pedagogy, and rapid onboarding into digital design workflows.


๐Ÿงฑ Module Declaration

module my_module (
    input wire a, b,
    output wire y
);
    // internal logic
endmodule
  • Purpose: Defines a reusable hardware block with named inputs/outputs.
  • Difference: Unlike functions in software, modules describe physical logic and can be instantiated multiple times in a design hierarchy.

๐Ÿ”— Data Types

TypeUsageNotes
wireFor continuous assignmentsCannot hold state
regFor procedural assignmentsCan hold state in always blocks
integerSimulation-only countersNot synthesizable
logicSystemVerilog extensionCombines wire and reg behavior

๐Ÿ“ Vector Declaration

wire [7:0] byte_data; // 8-bit bus
reg [3:0] nibble;
  • MSB on the left, LSB on the right.
  • Match widths during assignment to avoid synthesis errors.

๐Ÿ” Continuous Assignment

assign y = a & b;
  • Purpose: Describes combinational logic outside procedural blocks.
  • Difference: Unlike always blocks, assign is static and updates automatically when inputs change.

โฐ Procedural Blocks

Sequential Logic

always @(posedge clk) begin
    q <= d;
end
  • Purpose: Models flip-flop behavior triggered by clock edges.
  • Difference: Uses non-blocking <= to avoid race conditions.

Combinational Logic

always @(*) begin
    y = a & b;
end
  • Purpose: Describes logic that reacts to input changes.
  • Difference: Uses blocking = and must include all relevant signals in sensitivity list.

๐Ÿ”„ Conditional Statements

if (a > b)
    y = x;
else
    y = z;
  • Purpose: Implements decision-making logic.
  • Difference: Incomplete conditions may infer latchesโ€”use else or default to avoid.

Latch Inference โ€” What It Means and Why It Matters In Verilog, a latch is inferred when a signal inside an always @* block is not assigned in every possible condition. This causes the synthesizer to generate hardware that remembers the last valueโ€”just like a physical latch.

The term “latch” comes from mechanical and electrical systems: a latch is a device that holds its state until explicitly changed. In digital logic, a latch behaves similarlyโ€”it remains transparent when enabled and retains its value when disabled.

Example of latch inference:

always @* begin
  if (enable)
    q = d;  // โŒ No else โ†’ q retains previous value when enable is 0
end

This creates a level-sensitive latch because q is not updated when enable is false.

โœ… Best Practice: Always assign outputs in all branches of conditional logic to avoid unintended latch behavior.

๐Ÿ”€ Case Statements

case (sel)
    2'b00: y = a;
    2'b01: y = b;
    default: y = 1'bx;
endcase
  • Purpose: Selects output based on discrete input values.
  • Difference: More readable than nested if statements for multi-way branching.

๐Ÿ”ฃ Operators

OperatorMeaningNotes
~Bitwise NOTInverts each bit
&Bitwise ANDANDs each bit
|Bitwise ORORs each bit
^Bitwise XORExclusive OR
==, !=EqualityCompares values
<<, >>ShiftLogical shift
?:Ternary (if-else)Compact conditional

๐Ÿงฉ Module Instantiation

Named

my_mod U1 (.a(A), .b(B), .y(Y));

Ordered

my_mod U1 (A, B, Y);
  • Purpose: Reuses a module in another design.
  • Difference: Named instantiation avoids port-order errors and improves readability.

๐Ÿงช Simulation Constructs

initial begin
    $display("Start");
    #10 a = 1;
end
  • Purpose: Used in testbenches to simulate behavior.
  • Difference: Not synthesizableโ€”only for simulation and debugging.

๐Ÿงฌ Concatenation, Replication & Width Behavior

๐Ÿ”— Concatenation

assign out = {a, b}; // Combines a and b into a wider vector
  • {} joins multiple signals into a single vector.
  • Order matters: MSB on the left.

๐Ÿ” Replication

assign out = {4{a}}; // Replicates 'a' 4 times
  • {N{signal}} repeats the signal N times.
  • Useful for padding or pattern generation.

โš ๏ธ Truncation

wire [3:0] a;
assign a = 8'b10101010; // Only lower 4 bits assigned โ†’ a = 4'b1010
  • Higher bits are silently discarded.

๐ŸงŠ Zero-Padding

wire [7:0] a;
assign a = 4'b1101; // a = 8'b00001101
  • Left side is padded with zeros.

๐Ÿงฎ Parameters

Declaring Parameters

module adder #(parameter WIDTH = 8) (
    input wire [WIDTH-1:0] a, b,
    output wire [WIDTH-1:0] sum
);
  • Parameters allow scalable, reusable modules.
  • Can be overridden during instantiation.

Overriding Parameters

adder #(.WIDTH(16)) U1 (
    .a(a),
    .b(b),
    .sum(sum)
);
  • Use #(.NAME(VALUE)) syntax for named parameter override.

Local Parameters

localparam DEPTH = 32;
  • Internal constants that can’t be overridden.

๐Ÿ”€ Multiple always Blocks and Concurrency

  • All always blocks run concurrently, regardless of their order in the file.
  • Order of appearance does not affect executionโ€”Verilog models parallel hardware.
always @* begin
  a = b;
  c = m;
end

always @* begin
  y = ...;
  z = ...;
end
  • Best Practice: Assign each signal from only one block.

  • Difference: Unlike software, Verilog logic is synthesized as parallel hardware.

  • Exception: Inside a single always block, statement order mattersโ€”last assignment wins.

always @* begin
  y = a & b;
  y = x | c;  // Overrides previous y
end

Last updated on