Part 1 · Language Foundations · Intermediate

SystemVerilog Language Foundations

The language core every verification engineer must own: types, arrays, procedural code, operators, compilation units, and interfaces — the substrate everything else in SystemVerilog stands on.

What this section covers

Every constraint, covergroup, and class library sits on top of the language core : how values are represented, how data is organized, how procedural code executes, and how source files become an elaborated simulation. Weakness here shows up later as mysterious X bugs, race conditions, and compile-order failures that look unrelated to their root cause.

Each major topic below is a hub page with focused sub-topics. Drill into 4-state vs 2-state semantics , array machinery, always_comb/always_ff procedural rules, operator gotchas, package-based compilation, and the interface/clocking-block layer that connects a class-based testbench to RTL pins.

Topic map

diagram
Legend: [TYPE] [DATA] [PROC] [COMP] [IFACE]

┌─────────────────────────────────────────────────────────────────────────┐
│  LANGUAGE FOUNDATIONS — topic map                                         │
├─────────────────────────────────────────────────────────────────────────┤
│                                                                           │
│  1. DATA TYPES [TYPE]                                                     │
│     4-state vs 2-state │ nets vs vars │ casting │ X/Z │ enums │ strings  │
│                                                                           │
│  2. ARRAYS [DATA]                                                         │
│     packed/unpacked │ dynamic │ queues │ assoc │ methods │ foreach       │
│                                                                           │
│  3. PROCEDURAL CODE [PROC]                                                │
│     always_comb/ff │ blocking vs NBA │ tasks/functions │ fork-join       │
│                                                                           │
│  4. OPERATORS & EXPRESSIONS [TYPE]                                        │
│     reduction │ streaming │ wildcard equality │ precedence │ sizing      │
│                                                                           │
│  5. PACKAGES & COMPILATION [COMP]                                         │
│     import │ compilation units │ `include vs import │ elaboration order  │
│                                                                           │
│  6. INTERFACES & CLOCKING [IFACE]                                         │
│     modports │ virtual interfaces │ clocking blocks │ TB-DUT timing      │
│                                                                           │
└─────────────────────────────────────────────────────────────────────────┘

Topics and sub-topics

  1. Data Types — 4-state vs 2-state, nets vs variables, integer casting, X/Z propagation, enums/structs/unions, strings and special types.

  2. Arrays — packed vs unpacked layout, dynamic arrays, queues, associative arrays, array methods, and iteration idioms.

  3. Procedural Code — always_comb/always_ff semantics, blocking vs non-blocking assignment, tasks vs functions, fork-join process control.

  4. Operators & Expressions — reduction and streaming operators, ==?/inside, expression sizing rules, and sign-extension traps.

  5. Packages & Compilation — package import vs `include, compilation units, elaboration order, and how simulators build a design.

  6. Interfaces & Clocking — interface bundles, modports, virtual interfaces, and clocking blocks for race-free TB sampling and driving.


How RTL and testbench views differ

SystemVerilog serves two worlds with one language. The RTL world is structural and 4-state: every signal models real hardware, X means unknown silicon state, and Z means an undriven net. The testbench world is software-like and mostly 2-state: classes, queues, int loop counters, and string formatting — performance and convenience matter more than X modeling. Most foundation-level bugs live at the boundary where the two worlds exchange values.

diagram
Legend: [TYPE] [IFACE]

  4-STATE RTL WORLD                      2-STATE CLASS WORLD
  ─────────────────────                  ─────────────────────
  modules, wires, logic [TYPE]           classes, queues, int/bit [TYPE]
  values: 0 1 X Z                        values: 0 1 only
  init: X (uninitialized)                init: 0 (silently "valid")
  X = real unknown silicon state         X impossible — converted to 0
  static, elaborated structure           dynamic, new()-ed at runtime

            │                                      │
            └────────────┐            ┌────────────┘
                         ▼            ▼
              ┌────────────────────────────────┐
              │  BOUNDARY [IFACE]              │
              │  virtual interface + clocking  │
              │  4-state ◄──► 2-state copies   │
              │  X/Z silently become 0 going   │
              │  into bit/int — check first!   │
              └────────────────────────────────┘

Why the boundary matters

  • [TYPE] Copying a logic bus carrying X into an int produces 0 — the unknown disappears and the scoreboard happily compares garbage.

  • [TYPE] 2-state class fields initialize to 0, so a never-assigned field looks like a legal value instead of an obvious X.

  • [IFACE] Clocking blocks define when the TB samples and drives — without them, TB code races against RTL non-blocking updates.

  • [TYPE] RTL must stay 4-state so X propagation exposes reset and don't-care bugs that 2-state simulation hides.

Key takeaways

  • Foundations bugs surface later as X mysteries, races, and compile-order failures — learn the semantics, not just the syntax.

  • Keep RTL 4-state and testbench transaction fields 2-state; guard the boundary with explicit X/Z checks.

  • Six topics: data types, arrays, procedural code, operators, packages, interfaces — each is a hub with deep sub-lessons.

Common pitfalls

  • Treating logic and bit as interchangeable — X-hiding at the TB boundary silently corrupts checks.

  • Learning class-based SystemVerilog without procedural semantics — race conditions in monitors and drivers follow.

  • Skipping packages/compilation — works in one-file examples, breaks the moment a real multi-file project is built.