Panel For Example Panel For Example Panel For Example
SystemVerilog Syntax: Processes & Operators

SystemVerilog Syntax: Processes & Operators

Author : Adrian September 04, 2025

1. Simulation Time Control

In SystemVerilog, simulation time can be advanced using one of three methods:

  • Delay control: #
  • Event control: @
  • The wait statement, which combines aspects of event control and a while loop.

Delay control can be applied in two ways: before the statement or within the statement (intra-assignment delay).

// Delay occurs before the assignment statement is executed #10 rega = regb; // Wait 10 time units, then execute rega = regb; #((d+e)/2) rega = regb; // Wait (d+e)/2 time units, then execute the assignment. // Intra-assignment delay a = #5 b; // Equivalent to: temp = b; #5; a = temp; a = @(posedge clk) b; // Equivalent to: temp = b; @(posedge clk); a = temp; a = repeat(3) @(posedge clk) b; // Equivalent to: temp = b; @(posedge clk); @(posedge clk); @(posedge clk); a = temp;

When the delay operator # precedes the statement, the simulator waits for the specified delay, then evaluates and executes the entire statement. For intra-assignment delays, the right-hand side expression is evaluated immediately, and the assignment to the left-hand variable is postponed by the specified delay or event.

 

2. Controlling `fork` Threads

After initiating parallel threads withfork...join,fork...join_any, or fork...join_none, you can control them using wait forkdisable, or disable fork.

wait fork: This statement blocks the parent process until all of its immediate child processes have completed. It does not wait for grandchildren or other descendant processes.

disable: This statement terminates all activity within a named block or task, regardless of the parent-child process hierarchy. A child process can use disable to terminate its parent, and any process can be terminated by an unrelated process.

disable fork: This statement also terminates processes, but it respects the parent-child hierarchy. It stops all active child processes spawned by the current process, including all of their descendants.

 

3. Fine-Grained Process Control

SystemVerilog includes a built-in process class that allows other processes to access and control a process after it has started. The definition of this class is as follows:

class process; typedef enum { FINISHED, RUNNING, WAITING, SUSPENDED, KILLED } state; static function process self(); function state status(); function void kill(); task await(); function void suspend(); function void resume(); function void srandom( int seed ); function string get_randstate(); function void set_randstate( string state ); endclass

When a process is spawned, an object of type process is created internally. Users cannot manually create a process object with the new() constructor, and attempting to do so will result in a compiler error. The process class cannot be extended through inheritance.

To manipulate a process, you can declare a variable of type process and assign it a handle to an existing process. The static method self() returns the handle of the current process.

process job; fork begin: new_blk job = process::self(); // ... end join_none

With the handle job, you can now control the process running in the

new_blk block.

The built-in methods of the process class include:

  • status(): Returns the current state of the process object. The possible states are:

  • FINISHED: The process terminated normally.
  • RUNNING: The process is currently executing and not blocked.
  • WAITING: The process is blocked, waiting for a condition to be met.
  • SUSPENDED: The process has been suspended and is waiting to be resumed.
  • KILLED: The process was forcibly terminated by kill() or disable.
  • kill(): Terminates the specified process and all its descendant processes created with fork.
  • await(): A task that allows one process to wait for another process to complete. A process cannot call its own await() method.
  • suspend(): Allows a process to suspend its own execution or that of another process.
  • resume(): Resumes a previously suspended process.

 

4. Equality Operators

SystemVerilog provides three types of equality operators:

  • Logical equality ( ==!=): If either operand contains an X or Z bit, the result of the comparison is X (unknown). The result is 1 (True) or 0 (False) only if both operands are free of X and Z bits.
  • Case equality (===!==): This operator performs a bit-for-bit comparison that includes X and Z values. The result is always 1 (True) or 0 (False).
  • Wildcard equality (==?!=?): For this operator, the right-hand side is treated as a wildcard pattern. Any X or Z bits in the right-hand operand act as wildcards, matching any value (0, 1, X, or Z) in the corresponding bit of the left-hand operand. However, X or Z bits in the left-hand operand are treated as literal values. The result can be 0, 1, or X. If an X or Z on the left is not matched by a wildcard on the right, the result is X.

 

5. Short-Circuit Evaluation

The logical operators &&||, `->`, and the conditional operator ?: support short-circuit evaluation.

The first operand is always evaluated. For &&, if the first operand is false, subsequent operands are not evaluated. For ||, if the first operand is true, subsequent operands are not evaluated.

For the conditional operator (cond_predicate ? expr1 : expr2), if cond_predicate is true, only expr1 is evaluated. If it is false, only expr2 is evaluated. If cond_predicate evaluates to X or Z, the result is determined by merging the results of both expressions, as shown in this example:

wire [15:0] busa = drive_busa ? data : 16'bz;

If drive_busa is 1, busa is assigned the value of data. If drive_busa is an unknown state (X or Z), the result for `busa` will also be unknown. Because expr2 is high-impedance (Z), the output for any bit will resolve to X when `drive_busa` is unknown, regardless of the corresponding bit value in `data`.

 

6. Set Membership Operator (`inside`)

The inside operator checks if an expression is a member of a set of values or ranges. Its syntax is:

inside_expression ::= expression inside { open_range_list }

The expression to the left of inside must be a singular expression. The set on the right is a comma-separated list of expressions or ranges. If the left-hand expression is an unpacked array, it is automatically expanded to its singular elements.

For non-integral expressions, inside uses logical equality (==) for comparison. For integral expressions, it uses wildcard equality (==?). This means that X or Z bits in the range list expressions are treated as wildcards, but X or Z bits in the left-hand expression are treated as literal values.

If no exact match is found, but some comparisons result in X, the entire operation returns 1'bx.

Ranges are specified as [low_bound : high_bound]. The $ symbol can be used to represent the minimum or maximum value of the left-hand expression's type. If the left value in a range is greater than the right value, the range is considered empty.

Examples:

// Array expansion int array[$] = '{3,4,5}; if ( ex inside {1, 2, array} ) ... // Same as { 1, 2, 3, 4, 5 } // Wildcard comparison and unknown result assign r = 3'bz11 inside {3'b1?1, 3'b011}; // r = 1'bx