In short
SystemVerilog (IEEE 1800, current edition IEEE 1800-2023) is a single language that extends Verilog-2001 with strong design constructs (new data types, always_ff/always_comb, interfaces, packages) and a full object-oriented verification layer (classes, constrained randomisation, assertions, functional coverage). It is the industry language for RTL design and for testbenches built on UVM, so every VLSI company recruiting in India — Intel, Qualcomm, Nvidia, AMD, Synopsys, Cadence, Siemens EDA, Texas Instruments, Microchip, NXP, Bosch, Einfochips, Sasken, Tessolve, Wipro/HCL/L&T Technology Services — tests it in the written round and the technical interview. In universities it appears in Digital Design, HDL/VLSI Design and Verification labs; GATE EC/EE itself asks Verilog-level HDL only, so the SystemVerilog-specific material is mainly placement and lab material. Interviews split almost exactly into two halves: "design" questions (which always block, two-state vs four-state, race in non-blocking assignment) and "verification" questions (class vs module, randomize with constraints, assertion syntax, coverage closure). Treat it as one language with two disciplines inside it.
Explained
Data types and literals
- Four-state types carry 0, 1, X, Z:
logic,reg,wire,integer,time. Two-state types carry only 0/1 and simulate faster but hide X:bit,byte(8),shortint(16),int(32),longint(64). logicreplaces bothregandwirefor single-driver signals; it can be assigned from a procedural block or from a single continuousassign. Usewireonly where a net truly needs multiple drivers or a resolution function.- Signedness:
byte,shortint,int,longint,integerare signed by default;bit,logic,regvectors are unsigned.logic signed [7:0]makes an 8-bit signed value. stringis a dynamic built-in type with methods (len(),substr(),itoa());$sformatfreturns a formatted string.- User-defined:
typedef logic [31:0] word_t;enum,struct,union. An enum may be typed and based:typedef enum logic [1:0] {IDLE=2'b00, RUN=2'b01, DONE=2'b10} state_t;— enums give readable FSM states and enum methodsfirst(),next(),name(). - struct:
packedstructs map to a contiguous bit vector (synthesisable, can be driven as one bus); unpacked structs are a convenient grouping, mainly for testbenches. - Arrays: *packed* dimensions are written left of the name (
logic [3:0][7:0] a;= 32 bits, bit-sliceable), *unpacked* right of it (logic [7:0] mem [0:1023];= 1024 bytes of memory). Unpacked only is synthesisable as memory. - Dynamic structures (testbench only): dynamic array
int d[];withnew[n], queueint q[$]withpush_back/pop_front/size, associative arrayint aa[string]withexists,first,delete. Array methods: reductionsum,product,and,or,xor; locatormin,max,unique,find,find_index; orderingsort,rsort,reverse,shuffle. $bits(expr)gives width;'0,'1,'x,'zare width-less fill literals;4'b1x0zis a sized four-state literal.
Design constructs that replace plain Verilog
- **
always_comb** — infers combinational logic, has an implicit sensitivity list including functions it calls, and runs once at time 0 (plainalways @(*)need not). Variables it writes may not be written anywhere else. - **
always_ff @(posedge clk or negedge rst_n)— declares intent to infer a flop; the tool errors if the code is not flop-like or if another process writes the same variable.always_latch** similarly for latches. - **
logic+ non-blocking<=in sequential blocks, blocking=in combinational blocks** — the single most important coding rule; mixing them in one block creates simulation-synthesis mismatch. - **
unique/unique0/priority** oncaseandifreplace the oldfull_case/parallel_casepragmas and additionally give a runtime violation report in simulation.priority case= full but ordered;unique case= full and mutually exclusive.casez/casexare discouraged (casextreats X in the stimulus as a match and hides bugs); usecase insidewith wildcards where needed. - Enhanced operators:
++,--,+=,-=,<<=,insideset membership,==?/!=?wildcard compare,'{...}assignment patterns, labelledbegin : name ... end : name. - Loops:
forwith an inline declaration,do...while,foreach (arr[i,j]),break,continue,return. - **
package** holds shared typedefs, parameters, functions; imported withimport pkg::*;— the standard way to share a bus definition between design and testbench.$unit(compilation-unit scope) exists but is poor practice. - Module ports:
module m (input logic a, output logic y);— ANSI headers,.nameand.*implicit port connections,parameter typefor type parameters. - **
interface** bundles related signals:interface axi_lite_if (input bit clk); logic [31:0] addr; logic valid, ready; modport master (output addr, valid, input ready); modport slave (input addr, valid, output ready); endinterface. A modport fixes the direction per user, so one interface serves master, slave and testbench. It reduces port-list churn and is widely synthesisable today (check tool support). - **
function** (no time, returns a value, must beautomaticfor re-entrancy — in SystemVerilog items in modules are static by default, so writefunction automatic) vs **task** (may consume time, hasref/outputargs).void functionfor a side-effecting call. Arguments defaultinput;refpasses by reference,const reffor read-only large objects.
Verification layer: classes, randomisation, threads
- Class = data + methods, dynamically allocated:
class Packet; rand bit [7:0] data; randc bit [1:0] id; function new(); ... endfunction endclasswithPacket p = new();. A handle is a reference, not a copy —p2 = p1aliases the same object; a deep copy needs an explicitcopy()method. - OOP features: inheritance (
extends),super, polymorphism viavirtualmethods,pure virtualin avirtual class(abstract),protected/localvisibility,staticmembers and methods, parameterised classes (class fifo #(type T = int);),$castfor safe downcasting. - Randomisation:
rand(may repeat),randc(cyclic — all values before any repeat),p.randomize()returns 1 on success,randomize() with { ... }adds inline constraints,p.randomize(data)randomises only listed members.pre_randomize()/post_randomize()hooks.rand_mode(0)disables a variable,constraint_mode(0)a constraint. - Constraints:
constraint c_addr { addr inside {[0:1023]}; addr % 4 == 0; }; implicationlen > 64 -> burst == 1;,if/else,solve a before b(ordering of the solver, not a hard constraint),distweightingdata dist {0 := 10, [1:255] :/ 90};,unique {a, b, c};,foreachconstraints on arrays, soft constraints (soft len == 8;) that a later constraint can override. Constraints are declarative and solved simultaneously, not line by line. - Processes:
fork ... join(wait for all),join_any(wait for first),join_none(spawn and continue);disable fork,wait fork. Use **automatic** variables inside afor+fork join_noneloop or every thread sees the last index. - Inter-process communication:
semaphore(new(keys),get,put) for mutual exclusion;mailbox(new(bound),put,get,peek,try_get,num) as a typed FIFO between generator and driver;eventwith->trigger,@edge-sensitive wait and.triggeredpersistent flag. - **
clocking block** samples inputs and drives outputs relative to a clock with explicit skews, removing races:clocking cb @(posedge clk); default input #1step output #1; input ready; output addr, valid; endclocking— then@(vif.cb); vif.cb.valid <= 1;. The program block gives reactive-region scheduling for testbenches; modern UVM uses modules plus clocking blocks instead. - Virtual interface: a class cannot instantiate an interface, so the testbench stores
virtual axi_lite_if vif— the standard bridge between the static DUT hierarchy and the dynamic class world (passed down in UVM viauvm_config_db). - UVM (IEEE 1800.2) is a class library *written in* SystemVerilog, not part of the language:
uvm_sequence_item,sequence,sequencer,driver,monitor,agent,scoreboard,env,test, with phases (build_phase,connect_phase,run_phase), factory overrides, TLM ports anduvm_config_db. Interviewers expect the block diagram and the phase order.
Assertions, coverage and the scheduler
- Immediate assertion — procedural, zero-time:
assert (a == b) else $error("mismatch %0d", a);plusassume,cover. Deferred immediateassert #0avoids glitch firing. - Concurrent assertion — clocked, temporal, declared outside or inside a block:
property p_req_ack; @(posedge clk) disable iff (!rst_n) req |-> ##[1:3] ack; endproperty assert property (p_req_ack); - Operators:
|->overlapped implication (consequent starts the same cycle),|=>non-overlapped (next cycle),##ndelay,##[m:n]range,[*n]consecutive repetition,[->n]goto,and/or/throughout/within,$rose,$fell,$stable,$past(expr, n),$onehot,$onehot0,$isunknown,$countones. Sequences (sequence ... endsequence) are reusable building blocks;disable iffkills the check during reset. - Assertions serve three purposes: simulation checks, formal property verification targets, and documentation of the interface contract.
- Functional coverage answers "did I test it", unlike code coverage (line/branch/toggle/FSM) which answers "did I execute it":
covergroup cg @(posedge clk); cp_len: coverpoint len { bins small = {[0:63]}; bins large = {[64:255]}; illegal_bins bad = {0}; } cross cp_len, cp_burst; endgroup cg c = new();withc.sample()and$get_coverage(). Options:option.at_least,option.weight,option.per_instance,ignore_bins, transition bins(0 => 1 => 2). - Scheduler regions per time step: *Preponed* (
$past/sampling) → *Active* (blocking assignments, RTL) → *Inactive* (#0) → *NBA* (non-blocking updates) → *Observed* (concurrent assertion evaluation) → *Reactive* (program block) → *Postponed* ($strobe,$monitor). This is why a clocking block input sampled#1stepbefore the clock edge sees the old flop value and avoids the race. - DPI-C calls C from SystemVerilog (
import "DPI-C" function int crc32(input int d);) and SystemVerilog from C (export) — used for reference models.$assertoff/$asserton,$coverage_control,$random/$urandom/$urandom_range(max,min)($urandomis per-thread stable and preferred over$random).
Synthesisable vs testbench-only, and language guidance
- Synthesisable:
logic,bit, packed arrays/structs/enums,always_comb/always_ff/always_latch,unique/priority,interfacewith modports (tool-dependent), packages, parameters, generate (for/ifwithgenvar), functions,case inside. - Not synthesisable: classes, dynamic/associative arrays and queues, mailbox/semaphore,
fork join_any/join_none, constraints, covergroups, clocking blocks, program blocks,$display/file I/O, delays,string. - Hierarchy of standards: Verilog IEEE 1364-2001/2005 → merged into IEEE 1800-2005; later editions 1800-2009, 2012, 2017, 2023 (current). UVM is IEEE 1800.2. VHDL (IEEE 1076) is the alternative HDL; SystemC (IEEE 1666) is used at the transaction level. Indian service companies also ask about lint and CDC checks (Spyglass, Questa Lint) over the same code.
- Coding-style discipline expected in Indian design teams: one clock per module where possible, synchronous or properly synchronised reset, no latches by accident, no combinational loops, no mixing of blocking/non-blocking, and lint-clean RTL before synthesis.
Key points
- IEEE 1800 - the SystemVerilog standard; current edition 1800-2023; UVM is IEEE 1800.2.
- logic - replaces
regandwirefor any single-driver signal; four-state (0,1,X,Z). - bit vs logic -
bitis two-state (faster, hides X),logicfour-state (shows uninitialised and contention). - always_ff / always_comb / always_latch - declare intent; tools flag code that does not match, catching accidental latches.
- Blocking vs non-blocking -
=in combinational blocks,<=in sequential blocks; never mix them in one block. - Packed vs unpacked array - packed is one contiguous bit vector and synthesisable as a bus; unpacked models memory and supports array methods.
- Queue / dynamic / associative array - testbench-only containers (
[$],[],[string]); no hardware meaning. - interface + modport - bundles a protocol and fixes directions per role; a virtual interface is how classes reach the DUT.
- Clocking block - samples with input skew and drives with output skew, removing driver-DUT races.
- Class vs module - class objects are created and destroyed at run time by
new(); modules are static hierarchy fixed at elaboration. - rand vs randc -
randmay repeat;randcexhausts all values of its range before repeating. - Constraints are declarative - solved simultaneously;
solve...beforebiases the solver only, it does not add a condition. - randomize() returns a status - always check it (
if (!p.randomize()) $fatal), a failing solver otherwise passes silently. - Immediate vs concurrent assertion - procedural and zero-time vs clocked and temporal (
|->,|=>,##,$rose,disable iff). - Functional vs code coverage - functional coverage measures intent (covergroups, crosses); code coverage measures execution (line, branch, toggle, FSM).
- fork...join / join_any / join_none - wait for all / first / none;
automaticloop variables are mandatory withjoin_none. - Mailbox and semaphore - typed FIFO for generator-to-driver traffic; key-based mutual exclusion for a shared resource.
- Scheduler order - Preponed → Active → Inactive → NBA → Observed → Reactive → Postponed; assertions evaluate in Observed.
Formulas and examples
$bits(T) ; for logic [m:0][n:0] → (m+1)×(n+1) bitsMemory size = depth × width bits ;
logic [W-1:0] mem [0:D-1] → D×W bitsAddress bits for D locations: A = ⌈log₂ D⌉
Number of bins in a cross = (bins of cp1) × (bins of cp2) × …
Coverage % = (bins hit with ≥ option.at_least samples) / (total non-ignored, non-illegal bins) × 100
Constrained value space = ∏(legal values of each rand variable) after all constraints are applied
Example 1 — widths of packed and unpacked declarations.
logic [3:0][7:0] a; // packed: 4 x 8 = 32 bits, a[2] is a byte
logic [7:0] mem [0:1023]; // unpacked: 1024 bytes
typedef struct packed { logic [15:0] addr; logic [7:0] data; logic wr; } cmd_t;
$bits(a)= 4 × 8 = 32.memholds 1024 × 8 = 8192 bits = 1 KiB; address bits = ⌈log₂1024⌉ = 10.$bits(cmd_t)= 16 + 8 + 1 = 25 bits; as a packed struct it can be driven on a single 25-bit bus, andc[0]is thewrbit.
Example 2 — blocking vs non-blocking, counted cycle by cycle. Two shift attempts with a initially 1, b and c 0:
always_ff @(posedge clk) begin // non-blocking: correct 2-stage shift
b <= a; c <= b;
end
always_ff @(posedge clk) begin // blocking: collapses to one stage
b = a; c = b;
end
| After clock edge | Non-blocking b, c | Blocking b, c |
|---|---|---|
| 1st | 1, 0 | 1, 1 |
| 2nd | 1, 1 | 1, 1 |
- Non-blocking uses the old value of
b(NBA region), giving two flops in series. Blocking uses the newbimmediately, socgetsaafter one edge — one flop lost and a simulation-synthesis mismatch risk.
Example 3 — constrained random, counting the legal space.
class Pkt;
rand bit [9:0] addr; // 0..1023
rand bit [1:0] burst; // 0..3
constraint c1 { addr inside {[0:255]}; addr % 4 == 0; }
constraint c2 { burst != 2'b11; }
endclass
- Legal
addr: multiples of 4 in 0…255 → 256/4 = 64 values. - Legal
burst: 4 − 1 = 3 values. - Total combinations = 64 × 3 = 192. With
randc addr, 64 randomisations exhaust every address before any repeats. - Probability a single
randomize()returnsaddr == 0 && burst == 0= 1/192 ≈ 0.52%. - If
distis added —burst dist {0 := 1, 1 := 3, 2 := 6}— weights 1:3:6 sum to 10, so P(burst = 2) = 6/10 = 60%.
Example 4 — cross coverage arithmetic and closure.
covergroup cg @(posedge clk);
cp_len : coverpoint len { bins b[] = {[1:4]}; } // 4 bins
cp_kind : coverpoint kind { bins rd = {0}; bins wr = {1}; } // 2 bins
cross cp_len, cp_kind; // 8 bins
endgroup
- Total bins = 4 + 2 + 8 = 14. If a run hits all 4 lengths, both kinds, but only 6 of the 8 crosses: coverage = (4 + 2 + 6)/14 = 12/14 = 85.7%.
- Reaching 100% needs the two missing (len, kind) pairs — the standard "coverage hole → write a directed sequence" loop. With
option.at_least = 10, a bin sampled 7 times counts as not hit.
Example 5 — a concurrent assertion read in cycles.
property p_ack; @(posedge clk) disable iff (!rst_n)
$rose(req) |=> ##[0:2] ack; endproperty
assert property (p_ack) else $error("no ack within 3 cycles of req");
$rose(req)is true at the edge where req goes 0→1 (say cycle 5).|=>starts the consequent at cycle 6;##[0:2]allows ack at cycle 6, 7 or 8 → ack must assert within 3 clocks of the request.- ack at cycle 9 → assertion fails; reset low anywhere in the window → the attempt is killed, not failed, by
disable iff.
| Feature | Verilog-2001 | SystemVerilog |
|---|---|---|
| Signal type | reg, wire | logic, bit, enum, struct, union, typedef |
| Combinational block | always @(*) | always_comb (intent checked, runs at time 0) |
| Sequential block | always @(posedge clk) | always_ff (intent checked) |
| Case completeness | full_case/parallel_case pragmas | unique / unique0 / priority with runtime checks |
| Signal grouping | long port lists | interface with modport |
| Testbench stimulus | directed, $random | classes, constrained random, $urandom |
| Checking | if + $display | immediate and concurrent assertions (SVA) |
| Progress metric | eyeballing waveforms | functional coverage + code coverage |
| Reuse | copy-paste tasks | OOP inheritance, factory, UVM (IEEE 1800.2) |
Where it is used
- Semiconductor design houses in India — Intel (Bengaluru/Hyderabad), Qualcomm, Nvidia, AMD, Micron, Samsung SRI-B, TI, NXP, Microchip, Renesas, MediaTek: RTL in synthesisable SystemVerilog, UVM environments for block and subsystem verification.
- EDA vendors — Synopsys (VCS, VC Formal), Cadence (Xcelium, Jasper), Siemens EDA/Questa: the people who build and support the simulators, assertion and coverage engines.
- Design-services and VLSI training companies — Einfochips, Tessolve, Sasken, Mirafra, Wipro, HCLTech, LTTS, Cyient, Mistral, SmartSoC: large fresher intake specifically for UVM testbench and lint/CDC work.
- Indian product and space/defence electronics — ISRO/SCL Mohali, DRDO labs, BEL, C-DAC and Semi-Conductor Laboratory ASIC flows; the India Semiconductor Mission and Chips-to-Startup (C2S) programme fund SystemVerilog-based tape-out projects in colleges.
- FPGA prototyping and system teams — AMD Vivado and Intel Quartus accept SystemVerilog RTL; interfaces and packages are used to wire AXI/AHB/APB (Arm AMBA) subsystems in automotive and telecom products.
- Job roles — RTL design engineer, design verification (DV) engineer, formal verification engineer, AMS/analog-mixed-signal verification, post-silicon validation, FPGA engineer; DV is the largest single fresher opening in Indian VLSI.
Interview questions
- Q: Why is
logicpreferred overregandwire? A:logicis one four-state type usable in procedural blocks and single continuous assignments, so the designer need not decide betweenregandwire;wireis then kept only for genuinely multi-driven nets. - Q: What does
always_combgive you thatalways @(*)does not? A: An automatic sensitivity list that includes signals read inside called functions, a guaranteed execution at time 0, and a tool-enforced rule that no other process writes the same variables. - Q: Difference between a packed and an unpacked array? A: A packed array is a single contiguous bit vector that can be sliced and driven as a bus and is synthesisable; an unpacked array is a collection of separate elements, used for memories and for array methods.
- Q:
randversusrandc? A:randpicks uniformly and may repeat immediately;randccycles through every value in the declared range before any value repeats. - Q: Does
solve a before bconstrain the values? A: No — it only orders the solver soais chosen first, changing the probability distribution; the legal value set is unchanged. - Q: Why does a class need a *virtual* interface? A: A class is dynamic and cannot instantiate a static interface, so it holds a handle to an interface instance in the DUT hierarchy; this is the only link between the class-based testbench and the RTL.
- Q: Immediate versus concurrent assertion? A: Immediate assertions are procedural statements evaluated in zero time at that point in the code; concurrent assertions are clocked, evaluate a temporal property over many cycles in the Observed region, and can also be proved formally.
- Q: Difference between
|->and|=>? A:|->is overlapped — the consequent is checked in the same clock tick the antecedent matches;|=>is non-overlapped and starts the consequent on the next tick (it equals|-> ##1). - Q: Code coverage is 100% but you are not done. Why? A: Code coverage shows only that lines and branches executed; functional coverage shows whether the intended scenarios, corner values and crosses were actually hit, and only that can be signed off against the test plan.
- Q: What is the use of a clocking block? A: It defines input sampling and output driving skews relative to a clock so the testbench samples stable pre-edge values and drives after the edge, eliminating races with the DUT.
- Q:
fork...join_noneinside a loop produces identical threads. Why? A: The loop variable is shared; all threads see its final value. Declaring anautomaticcopy inside the loop gives each thread its own value. - Q:
mailboxversussemaphoreversusevent? A: A mailbox is a (optionally bounded) FIFO that passes objects between threads; a semaphore hands out keys for exclusive access to a shared resource; an event is a synchronisation flag triggered with->and waited on with@or.triggered. - Q: Is
casexsafe in RTL? A: No —casextreats X or Z in the *selector* as a match, which can mask real X propagation; usecase,case inside, orunique casewith explicit wildcards instead.
Common mistakes
- Mixing blocking and non-blocking assignments in one
alwaysblock, or using<=inalways_comb— a classic cause of simulation-synthesis mismatch. - Writing the same variable from two processes, or forgetting a branch in
always_comb, which infers an unintended latch (always_latch/lint would have caught it). - Calling
p.randomize()without checking its return value, so a solver failure leaves stale values and the test silently passes. - Writing constraints as if they executed sequentially, or using
solve...beforeexpecting it to exclude values. - Assigning one class handle to another and believing a copy was made — both handles point to the same object; a deep copy must be written.
- Using testbench-only constructs (queues, dynamic arrays, classes,
string, delays) in RTL and then failing synthesis. - Declaring two-state
bitin RTL and losing X-propagation, so an uninitialised flop reads as 0 in simulation but is unknown in silicon. - Treating 100% code coverage, or a passing assertion that never had its antecedent triggered, as proof of verification — check the assertion's cover count too.
Related topics
Verilog and HDL basics · Finite state machine design · Sequential circuits: flip-flops, counters and registers · Combinational circuits · Static timing analysis and synthesis · UVM and functional verification methodology