Close Menu
VLSI Web
  • Home
    • About Us
    • Contact Us
    • Privacy Policy
  • Digital Design
    • Digital Circuits
    • Verilog
    • VHDL
    • System Verilog
    • UVM
  • VLSI Roles
    • RTL Design
    • Design Verification
    • Physical Design
    • DFT
    • STA
  • Interviews
  • Informative
  • VLSI Forge
Instagram LinkedIn WhatsApp Telegram
Instagram LinkedIn WhatsApp Telegram
VLSI Web
  • Home
    • About Us
    • Contact Us
    • Privacy Policy
  • Digital Design
    • Digital Circuits
    • Verilog
    • VHDL
    • System Verilog
    • UVM
  • VLSI Roles
    • RTL Design
    • Design Verification
    • Physical Design
    • DFT
    • STA
  • Interviews
  • Informative
  • VLSI Forge
VLSI Web
System Verilog

SystemVerilog for RTL Design: always_ff, always_comb, Packages and More

Raju GorlaBy Raju Gorla6 July 2026Updated:11 October 2026No Comments4 Mins Read
SystemVerilog for RTL design
Share
Facebook Twitter LinkedIn Email Telegram WhatsApp

The short answer: For RTL design, SystemVerilog gives you logic instead of wire and reg, always_ff, always_comb and always_latch to state intent, enums and packed structs for readable state and bus fields, unique and priority for safer case statements, packages for shared types and functions, and interfaces for buses. All of these are synthesisable and supported by mainstream tools. Classes, randomisation and dynamic types are testbench-only.

I write all new RTL in SystemVerilog. The language doesn’t change what hardware you can build, but it catches mistakes earlier and makes code shorter and easier to review. This post covers the synthesisable subset and what synthesis does with it, combining my older posts on SystemVerilog for design, synthesis and timing considerations, and packages.

  1. The features worth using
  2. always_ff, always_comb and always_latch
  3. unique and priority
  4. Packages
  5. Other small wins
  6. Synthesis and timing considerations
  7. Not synthesisable

Table of Contents

  • Part 1: The features worth using
  • Part 2: always_ff, always_comb and always_latch
  • Part 3: unique and priority
  • Part 4: Packages
  • Part 5: Other small wins
  • Part 6: Synthesis and timing considerations
  • Part 7: Not synthesisable
  • FAQ
    • Is SystemVerilog synthesisable?
    • What is the difference between always_comb and always @(*)?
    • Should I use unique case?
    • What is a package in SystemVerilog?

Part 1: The features worth using

SystemVerilog features for RTL: always_ff and always_comb, logic and fill literals, enums and packed structs, unique and priority, packages and interfaces
My standard SystemVerilog RTL toolkit.

Part 2: always_ff, always_comb and always_latch

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

always_comb begin
  next = state;
  case (state)
    IDLE: if (start) next = RUN;
    RUN:  if (done)  next = IDLE;
    default:         next = IDLE;
  endcase
end
  • always_comb has an automatic, complete sensitivity list (including signals read inside functions) and runs once at time zero.
  • Tools warn if always_comb infers a latch or always_ff doesn’t infer flops.
  • A variable written in an always_comb or always_ff block can’t be written anywhere else.

Part 3: unique and priority

always_comb begin
  unique case (sel)          // exactly one item should match
    2'b00: y = a;
    2'b01: y = b;
    2'b10: y = c;
    2'b11: y = d;
  endcase
end

always_comb begin
  priority if (irq[2]) id = 2;   // first match wins; one must match
  else if    (irq[1]) id = 1;
  else if    (irq[0]) id = 0;
end

They replace the old full_case and parallel_case synthesis pragmas, which changed synthesis without telling the simulator. With unique and priority, the simulator reports violations, so a wrong assumption shows up as a warning instead of a silent mismatch. Still add a default unless you’re sure.

Part 4: Packages

package cpu_pkg;
  typedef enum logic [3:0] {ADD, SUB, AND_, OR_} alu_op_t;
  typedef struct packed {
    alu_op_t    op;
    logic [4:0] rd, rs1, rs2;
  } uop_t;
  function automatic logic parity(input logic [31:0] d);
    return ^d;
  endfunction
endpackage

module alu import cpu_pkg::*; (input uop_t uop, ...);

Packages replace `include files for shared types, parameters and functions. Compile them before the modules that import them.

Part 5: Other small wins

  • '0, '1, 'x fill any width: count <= '0;.
  • $bits(x) returns the width of a signal or type.
  • ++, += and friends work in procedural code (use them carefully in RTL for readability).
  • Port connections with .* connect every port to a same-named signal; handy at the top level, but explicit names are clearer elsewhere.
  • Assertions can live right next to the RTL they check. See SystemVerilog assertions.

Part 6: Synthesis and timing considerations

Construct Synthesis result Watch out for
enum Encoding chosen by you or the tool Name-based debug only works in simulation
packed struct / union Plain vectors Field order sets bit order
unique case Parallel mux, no priority logic A violation in silicon is undefined behaviour
interface Flattened into individual ports Some tools limit modport and generic interface use at the top level
functions in always_comb Inlined combinational logic Deep functions become long timing paths
for loops Unrolled Large loops create large, slow logic

The usual timing rules still apply: register outputs between blocks, keep combinational depth reasonable, and pipeline long arithmetic.

Part 7: Not synthesisable

Classes, randomisation, dynamic arrays, queues, associative arrays, strings, mailboxes, fork-join and delays are all testbench features. Keep them out of RTL files.

Practise this on VLSI Forge

I built VLSI Forge so you can write RTL in your browser, run it on a real simulator and check every signal in the waveform. Free, nothing to install.

RTL Design problems · Daily challenge

Previous in my SystemVerilog series: SystemVerilog data types. Next: Tasks and functions.

FAQ

Is SystemVerilog synthesisable?

The design subset is: logic, always_ff, always_comb, enums, packed structs, interfaces, packages, unique and priority. Classes and dynamic types aren’t.

What is the difference between always_comb and always @(*)?

always_comb runs at time zero, includes signals read inside called functions, forbids other drivers of its outputs, and lets tools check for unintended latches.

Should I use unique case?

Use it when items really are mutually exclusive and you want the simulator to check that. Add a default for robustness.

What is a package in SystemVerilog?

A named scope for shared types, parameters, functions and tasks, imported into modules with import pkg::*;

ASIC and FPGA design Digital design essentials HDL programming techniques RTL coding in Verilog SystemVerilog basics Verification and validation in SystemVerilog
Share. Facebook Twitter LinkedIn Email Telegram WhatsApp
Previous ArticleSystemVerilog Data Types: logic, enums, structs, queues and Associative Arrays
Next Article Tasks and Functions in SystemVerilog: ref, void, Defaults and More
Raju Gorla
  • Website

Related Posts

System Verilog

Design Patterns in SystemVerilog Testbenches: Factory, Callbacks and More

16 July 2026
System Verilog

DPI in SystemVerilog: Calling C from Your Testbench (and Back)

15 July 2026
System Verilog

SystemVerilog Testbench Architecture: A Self-Checking Testbench Without UVM

14 July 2026
Add A Comment
Leave A Reply Cancel Reply

Topics
  • Digital Circuits
  • Informative
  • Interview Questions
  • Physical Design
  • RTL Design
  • STA
  • System Verilog
  • UVM
  • Verilog
Instagram LinkedIn WhatsApp Telegram
  • About
  • Contact
  • Privacy Policy
  • VLSI Forge
  • Courses
  • Feedback
© 2026 VLSI Web

Type above and press Enter to search. Press Esc to cancel.