A complete quick-reference for Verilog HDL. Covers every language construct you need to recall — module structure, data types, operators, procedural blocks, tasks, functions, system calls, compiler directives, and synthesis rules. Designed for engineers who learned Verilog and need to refresh it in a day.


Module Declaration & Ports

ANSI-Style (Preferred)


module my_module (
  input  wire        clk,
  input  wire        rst_n,
  input  wire [7:0]  data_in,
  output reg  [7:0]  data_out,
  output wire        valid,
  inout  wire [7:0]  bidir       // bidirectional
);
  // ...
endmodule

Parameterized Module


module fifo #(
  parameter WIDTH = 8,
  parameter DEPTH = 16
)(
  input  wire             clk,
  input  wire [WIDTH-1:0] wr_data,
  output wire             full
);
  localparam ADDR_W = $clog2(DEPTH);  // cannot be overridden
  // ...
endmodule

Instantiation


// Named port connection (always prefer)
fifo #(.WIDTH(32), .DEPTH(64)) u_fifo (
  .clk     (sys_clk),
  .wr_data (din),
  .full    (fifo_full)
);

// Positional (avoid — fragile)
fifo u_fifo2 (sys_clk, din, fifo_full);

Always use named port connections. Positional connections break silently when the port list changes.


Data Types

Nets and Variables

TypeUsageDefault
wireContinuous assignments, port connectionsz
regProcedural blocks (always, initial)x
integer32-bit signed variable for loops, calculationsx
real64-bit floating point (not synthesizable)0.0
time64-bit unsigned for simulation timex
realtimeFloating-point simulation time0.0
Constant TypeCan Override?Use Case
parameterYes (at instantiation)Configurable module width, depth, etc.
localparamNoDerived constants ($clog2, state encodings)
`defineGlobal scopeProject-wide constants, conditional compilation
genvarN/AGenerate loop index only

reg does NOT mean "register" in hardware. It simply means "can be assigned in a procedural block." A reg inside always @(*) synthesizes to combinational logic, not a flip-flop.

Vectors


wire [7:0]   byte_val;           // 8-bit vector, bit 7 is MSB
wire [31:0]  word;               // 32-bit
reg  [15:0]  counter;

// Signed
wire signed [15:0] signed_val;
reg  signed [7:0]  signed_reg;

Arrays and Memories


reg  [7:0]  mem [0:255];         // 1D array: 256 entries of 8 bits
reg  [7:0]  matrix [0:3][0:3];   // 2D array
integer     int_array [0:9];     // array of integers

// Initialization
initial $readmemh("data.hex", mem);        // hex file
initial $readmemb("data.bin", mem, 0, 15); // binary, partial range

Part Selects


wire [31:0] word;
wire [7:0]  byte0 = word[7:0];      // fixed part-select
wire [7:0]  byte1 = word[15:8];

// Indexed part-select (variable position, fixed width)
wire [7:0]  byte_n = word[n*8 +: 8];   // 8 bits starting at n*8, going up
wire [7:0]  byte_m = word[m*8+7 -: 8]; // 8 bits ending at m*8+7, going down

Number Formats

Syntax: <size>'<signed><base><digits>

ExampleDescription
8'b1010_00118-bit binary (underscores optional for readability)
8'o2438-bit octal
8'd1638-bit decimal
8'hA38-bit hexadecimal
8'sb1010_00118-bit signed binary
'hDEAD_BEEFUnsized (at least 32 bits)
-8'd5Negative: two's complement of 5
4'bx / 4'bzAll bits unknown / high-impedance
'0 / '1 / 'x / 'zFill all bits (context width); SystemVerilog only, not valid Verilog

Four-Value Logic

ValueMeaning
0Logic low, false
1Logic high, true
x / XUnknown (conflict, uninitialized)
z / Z / ?High-impedance (undriven, tri-state)

Operators

Arithmetic


a + b        // addition
a - b        // subtraction
a * b        // multiplication
a / b        // division (power-of-2 only for synthesis)
a % b        // modulus (power-of-2 only for synthesis)

Relational & Equality


a == b       // equality (x/z → unknown result)
a != b       // inequality
a === b      // case equality (x/z match exactly) — not synthesizable
a !== b      // case inequality — not synthesizable
a < b   a <= b   a > b   a >= b    // comparisons

Logical


a && b       // logical AND  (result is 1-bit)
a || b       // logical OR   (result is 1-bit)
!a           // logical NOT  (result is 1-bit)

Bitwise


~a           // NOT (invert)
a & b        // AND
a | b        // OR
a ^ b        // XOR
a ~^ b       // XNOR (equivalence)

Reduction (Unary — result is 1-bit)


&a           // AND reduce: a[n-1] & ... & a[0]
|a           // OR reduce
^a           // XOR reduce (parity)
~&a          // NAND reduce
~|a          // NOR reduce
~^a          // XNOR reduce

Shift


a << n       // logical shift left  (fill with 0)
a >> n       // logical shift right (fill with 0)
a <<< n      // arithmetic shift left  (same as logical)
a >>> n      // arithmetic shift right (fill with sign bit — requires signed type)

Concatenation, Replication, Conditional


{a, b, c}    // concatenation
{4{a}}       // replication: {a, a, a, a}
{{4{1'b0}}, a} // zero-extend: 4 zero-bits prepended to a

sel ? a : b  // conditional (ternary mux)

Operator Precedence (High to Low)

PriorityOperators
Highest! ~ & | ^ (unary)
* / %
+ -
<< >> <<< >>>
< <= > >=
== != === !==
& → ^ ~^ → | (bitwise)
&&
||
Lowest?:

When mixing bitwise and logical operators, always use parentheses. a & b == c is parsed as a & (b == c), not (a & b) == c.


Continuous Assignments


// Drive wires with combinational logic
assign y = a & b;
assign z = sel ? a : b;                  // 2:1 mux
assign {cout, sum} = a + b + cin;        // multi-bit result
assign data_bus = oe ? data_out : 8'bz;  // tri-state buffer

Procedural Blocks

always Blocks


// Combinational logic
always @(*) begin              // @* = automatic sensitivity list
  y = a & b;                   // use blocking (=)
end

// Sequential logic — synchronous reset
always @(posedge clk) begin
  if (!rst_n) q <= 0;         // use non-blocking (<=)
  else        q <= d;
end

// Sequential logic — asynchronous reset
always @(posedge clk or negedge rst_n) begin
  if (!rst_n) q <= 0;
  else        q <= d;
end

initial Block (Testbench / Simulation Only)


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

Blocking vs Non-Blocking

AssignmentSymbolUse InBehavior
Blocking=Combinational always @(*)Executes immediately, sequentially
Non-blocking<=Sequential always @(posedge clk)Scheduled, all update simultaneously at end of time step

Never mix = and <= in the same always block. Blocking in sequential blocks or non-blocking in combinational blocks causes simulation/synthesis mismatches.


Conditional Statements

if-else


always @(*) begin
  if (cond_a)
    out = val_a;
  else if (cond_b)
    out = val_b;
  else
    out = val_default;     // always include else → prevents latches
end

case / casez / casex


always @(*) begin
  case (sel)
    2'b00:   y = a;
    2'b01:   y = b;
    2'b10:   y = c;
    2'b11:   y = d;
    default: y = 0;       // always include default
  endcase
end

// casez: z/? bits are don't-care (useful for priority logic)
casez (req)
  4'b1???: grant = 4'b1000;
  4'b01??: grant = 4'b0100;
  4'b001?: grant = 4'b0010;
  4'b0001: grant = 4'b0001;
  default: grant = 4'b0000;
endcase

// casex: both x and z are don't-care (avoid in RTL — use casez instead)

Use casez for priority encoders and interrupt logic. Avoid casex in synthesizable code — it can mask real x-propagation bugs in simulation.


Loops


// for — synthesizable if bounds are compile-time constant
integer i;
always @(*) begin
  parity = 0;
  for (i = 0; i < 8; i = i + 1)
    parity = parity ^ data[i];
end

// while — synthesizable only if deterministic iteration count
while (count > 0) begin
  // ...
  count = count - 1;
end

// repeat — fixed number of iterations (testbench)
repeat (10) @(posedge clk);

// forever — infinite loop (testbench clocks)
initial forever #5 clk = ~clk;

Generate Blocks


// generate for — replicate hardware instances
genvar g;
generate
  for (g = 0; g < N; g = g + 1) begin : stage
    assign pipe[g+1] = pipe[g] & enable[g];
  end
endgenerate

// generate if — conditional hardware
generate
  if (USE_BRAM) begin : gen_bram
    bram_wrapper u_mem (.clk(clk), .addr(addr), .data(data));
  end else begin : gen_dist
    dist_ram u_mem (.clk(clk), .addr(addr), .data(data));
  end
endgenerate

// generate case
generate
  case (IMPL)
    "FAST":   fast_adder  u_add (...);
    "SMALL":  small_adder u_add (...);
    default:  basic_adder u_add (...);
  endcase
endgenerate

Every generate for loop and if/else branch needs a unique label (e.g., begin : stage). The label creates a named scope for hierarchical references.


Tasks & Functions

Function

Purely combinational, executes in zero simulation time, returns a single value. Can be used in continuous assignments and expressions.


function [7:0] add_sat;        // returns 8-bit value
  input [7:0] a, b;
  reg [8:0] sum;
  begin
    sum = a + b;
    add_sat = sum[8] ? 8'hFF : sum[7:0];  // saturate on overflow
  end
endfunction

// ANSI-style (cleaner)
function automatic [7:0] max(input [7:0] a, input [7:0] b);
  max = (a > b) ? a : b;
endfunction

// Usage
assign result = add_sat(x, y);
wire [7:0] bigger = max(val_a, val_b);

Task

Can contain timing controls (#, @, wait), can have multiple outputs. Cannot be used in expressions.


task automatic drive_data;
  input [7:0] data;
  input [3:0] addr;
  output       done;
  begin
    @(posedge clk);
    bus_addr <= addr;
    bus_data <= data;
    bus_wr   <= 1'b1;
    @(posedge clk);
    bus_wr   <= 1'b0;
    done = 1'b1;
  end
endtask

// Usage (in initial or always block)
drive_data(8'hAB, 4'h3, ack);

Function vs Task

FeatureFunctionTask
Timing controls (#, @)NoYes
Can call tasksNoYes
Return valueSingle valueVia output ports
Use in expressionsYesNo
SynthesizableYes (combinational)Only if no timing

Use the automatic keyword for recursive functions or tasks called from multiple threads. Without it, all local variables are static and shared — which causes bugs in concurrent usage.


Timing Controls

Used in simulation (testbench) and sequential always blocks.


#10          // delay 10 time units
// (a literal such as #10ns is SystemVerilog; in Verilog the unit comes from `timescale)

@(posedge clk)       // wait for rising edge
@(negedge rst_n)     // wait for falling edge
@(a or b or c)       // wait for any change (sensitivity list)
@(*)                 // wait for any input change (combinational)

wait (ready == 1)    // wait until condition is true (level-sensitive)

// Intra-assignment delay
q <= #1 d;           // assign d to q, but delay the update by 1 time unit

Named Blocks & Disable


// Named block — can be disabled (like break/return)
always @(posedge clk) begin : search_block
  integer i;
  found = 0;
  for (i = 0; i < 16; i = i + 1) begin
    if (mem[i] == target) begin
      found = 1;
      index = i;
      disable search_block;   // exit the named block (like break)
    end
  end
end

// Named blocks create scope — local variables visible via hierarchy
// search_block.i is accessible from outside

Gate-Level Primitives


// Built-in gate instantiation
and  u1 (out, in1, in2);          // 2-input AND
or   u2 (out, in1, in2, in3);     // 3-input OR
nand u3 (out, in1, in2);          // NAND
nor  u4 (out, in1, in2);          // NOR
xor  u5 (out, in1, in2);          // XOR
xnor u6 (out, in1, in2);          // XNOR
not  u7 (out, in);                // inverter
buf  u8 (out, in);                // buffer

// Tri-state
bufif1 u9  (out, in, enable);     // buffer if enable=1
bufif0 u10 (out, in, enable);     // buffer if enable=0
notif1 u11 (out, in, enable);     // inverter if enable=1

// With drive strength and delay
nand #(2, 3) u12 (out, a, b);    // rise=2, fall=3 delay
and (strong0, weak1) u13 (o, a, b);

System Tasks & Functions

Display & Monitoring


$display("msg");                   // print + newline (one-shot)
$write("msg");                     // print without newline
$strobe("msg");                    // print at end of time step
$monitor("a=%b b=%b", a, b);      // print on ANY change (auto-trigger)
$monitoron;  $monitoroff;          // enable/disable $monitor

// Format specifiers
$display("dec=%0d hex=%h bin=%b oct=%o", val, val, val, val);
$display("str=%s time=%0t", name, $time);
$display("real=%f sci=%e", rval, rval);

Format Specifiers

SpecifierMeaning
%d / %0dDecimal (padded / no padding)
%h / %HHexadecimal
%b / %BBinary
%oOctal
%sString
%tTime (formatted per $timeformat)
%f / %eReal (fixed / scientific)
%mModule hierarchical name (no argument)

File I/O


integer fd;
fd = $fopen("output.log", "w");    // "w"=write, "r"=read, "a"=append
$fdisplay(fd, "data = %h", data);
$fwrite(fd, "no newline");
$fclose(fd);

// Read memory from file
$readmemh("data.hex", mem);           // hex format
$readmemb("data.bin", mem);           // binary format
$readmemh("data.hex", mem, 0, 255);   // specify address range

Simulation Control


$finish;             // end simulation
$finish(2);          // end with diagnostic level (0=nothing, 1=time, 2=time+stats)
$stop;               // pause simulation (drop to debugger)
$time;               // current time as 64-bit integer
$realtime;           // current time as real number
$stime;              // current time as 32-bit integer

$timeformat(-9, 2, " ns", 12);   // units, precision, suffix, min_width

Math & Utility


$clog2(n)            // ceiling of log2 — essential for address widths
$random;             // random 32-bit signed integer
$random(seed);       // seeded random
$urandom;            // unsigned random (SystemVerilog only)
$urandom_range(max, min);  // random in range (SystemVerilog only)

$bits(expr);         // number of bits in expression/type (SystemVerilog only)
$countones(val);     // number of 1-bits (SystemVerilog only)
$onehot(val);        // true if exactly one bit is set (SystemVerilog only)
$onehot0(val);       // true if zero or one bit is set (SystemVerilog only)
$isunknown(val);     // true if any bit is x or z (SystemVerilog only)

Value Change Dump (Waveform)


initial begin
  $dumpfile("waves.vcd");
  $dumpvars(0, top);        // 0 = all hierarchy levels below 'top'
  $dumpvars(1, top);        // 1 = only signals in 'top' (no children)
  $dumpvars(0, top.u_cpu);  // dump specific instance
end

$dumpon;  $dumpoff;          // start/stop dumping at runtime
$dumpall;                    // force dump of all current values

Compiler Directives


`timescale 1ns / 1ps           // time_unit / time_precision

`define WIDTH 32                // macro definition
`define MAX(a,b) ((a)>(b)?(a):(b))   // parameterized macro
wire [`WIDTH-1:0] bus;          // usage (note backtick)

`undef WIDTH                   // undefine macro

`ifdef SIMULATION              // conditional compilation
  // simulation-only code
`elsif SYNTHESIS
  // synthesis-only code
`else
  // default code
`endif

`ifndef GUARD_H                // include guard
`define GUARD_H
  // declarations
`endif

`include "defines.vh"          // file inclusion

`default_nettype none          // require explicit declarations (recommended)
`default_nettype wire          // restore default (at end of file)

`resetall                      // reset all directives to defaults

Put `default_nettype none at the top of every file. It forces you to declare all signals explicitly, catching typos that would otherwise silently create 1-bit wires.


Synthesis Attributes & Pragmas


// Verilog-2001 attributes
(* full_case *)          case (sel) ... endcase    // all cases covered
(* parallel_case *)      case (sel) ... endcase    // cases are mutually exclusive
(* full_case, parallel_case *)                     // both

// Synthesis directives (tool-specific, in comments)
// synthesis translate_off
  $display("simulation only");
// synthesis translate_on

// Keep signals from being optimized away
(* keep = "true" *) wire debug_sig;
(* dont_touch = "true" *) reg [7:0] probe;

// RAM inference hint (Xilinx)
(* ram_style = "block" *)   reg [31:0] bram [0:1023];
(* ram_style = "distributed" *) reg [7:0] lutram [0:63];

full_case and parallel_case can create simulation/synthesis mismatches. Use them only when you truly know the case is full or parallel, and consider using default and proper coding style instead.


Common Patterns — Quick Reference

Edge Detector


reg sig_d;
always @(posedge clk) sig_d <= sig;
assign rising  = sig & ~sig_d;
assign falling = ~sig & sig_d;

Synchronizer (Clock Domain Crossing)


reg [1:0] sync;
always @(posedge clk_dst or negedge rst_n)
  if (!rst_n) sync <= 2'b0;
  else        sync <= {sync[0], async_sig};
assign synced = sync[1];

Counter with Terminal Count


reg [WIDTH-1:0] cnt;
always @(posedge clk or negedge rst_n)
  if (!rst_n)       cnt <= 0;
  else if (en)      cnt <= cnt + 1'b1;
assign terminal = (cnt == MAX_VAL);

Shift Register


reg [N-1:0] sreg;
always @(posedge clk)
  if (load)       sreg <= parallel_in;
  else if (shift) sreg <= {sreg[N-2:0], serial_in};
assign serial_out = sreg[N-1];

FSM Template


localparam IDLE=0, RUN=1, DONE=2;
reg [1:0] state, next;

always @(posedge clk or negedge rst_n)
  if (!rst_n) state <= IDLE;
  else        state <= next;

always @(*) begin
  next = state;  busy = 0;  valid = 0;
  case (state)
    IDLE: if (start) next = RUN;
    RUN:  begin busy = 1; if (done) next = DONE; end
    DONE: begin valid = 1; next = IDLE; end
  endcase
end

Synchronous RAM


reg [W-1:0] mem [0:D-1];
always @(posedge clk) begin
  if (we) mem[waddr] <= wdata;
  rdata <= mem[raddr];
end

Synthesis Golden Rules

  • Use = in combinational, <= in sequential — never mix
  • Every if needs an else, every case needs a default
  • Assign every output in every branch (or default at top)
  • Use @(*) for combinational sensitivity lists
  • Clock and reset appear only in sequential always sensitivity lists
  • No combinational loops — every feedback path through a flip-flop
  • Use parameter / localparam — no magic numbers
  • One module per file, filename matches module name
  • `default_nettype none at the top of every file
  • Use $clog2() for address widths: localparam ADDR_W = $clog2(DEPTH)

Common Pitfalls

MistakeResultFix
Missing else / defaultLatch inferredComplete all branches or default at top
Incomplete sensitivity listSim/synth mismatchUse @(*)
<= in comb blockRace conditionsUse =
= in seq blockRace conditions and simulation/synthesis mismatch (flip-flops are still inferred)Use <=
Multiple drivers on wireContention / XOne driver per signal
Async reset not synchronizedMetastabilityUse reset synchronizer
Combinational feedback loopOscillation / hangBreak with flip-flop
Using initial for resetNot synthesizable (ASIC)Use reset in always block
Divided clock as clockTiming closure issuesUse clock enable instead
Did you find what you were looking for?

Quiz

Test Your Knowledge

1 of 5 Score: 0 / 5
Cron Job Starts