• Skip to main content
  • Skip to search
  • Skip to footer
Cadence Home
  • This search text may be transcribed, used, stored, or accessed by our third-party service providers per our Cookie Policy and Privacy Policy.

  1. Blogs
  2. Verification
  3. PSS Randomization Semantics and Numeric Expressions
OK202502201742
OK202502201742

Community Member

Blog Activity
Options
  • Subscribe by email
  • More
  • Cancel
pss 3.0
Perspec
perspec system verifier
pss

PSS Randomization Semantics and Numeric Expressions

15 Jan 2026 • 5 minute read

Understanding how PSS defines numeric expressions—and how Perspec supports these rules is important when writing constraints that involve mixed types, limited bit widths, or signedness to make sure you get exactly what you meant and might save you debugging time.

The definition of numeric expression semantics is in the PSS 3.0 LRM, sections 8.7 (Expression Evaluation) and 8.8 (Type Conversion Rules). These rules precisely define how operand bit widths are determined, how signedness is propagated, and how overflows are handled.

Perspec’s support for the PSS randomize (procedural randomization) adheres to these standard rules. In other cases, support does not yet fully conform to the PSS LRM, but future updates will bring it into alignment.

The following examples illustrate how PSS randomization semantics work, how Perspec applies them today in PSS randomize, and how users can make their intent explicit when needed.

All the examples in this blog can be just copied into a PSS file and solved by Perspec.

Example 1: Operands with a Specific Bit Width

This example demonstrates how PSS evaluates expressions involving operands of the same type when that type has a specific bit width.

import std_pkg::*;  
component pss_top{  
  
struct S {  
rand bit[2] a, b, c;  
} 
      
action test {          
exec post_solve {  
               
         S my_struct;  
   
// Call randomize explicitly on the struct instance  
randomize my_struct with {  
my_struct.a + my_struct.b == my_struct.c;  
my_struct.a != 0;  
my_struct.b != 0; 
} 
  
                 // Print the randomized values  
                 print ("Randomized values: a=%d, b=%d, c=%d\n",my_struct.a, my_struct.b, my_struct.c);  
  
        }  
          }  
 }  
 

According to the PSS standard rules: 

  • The expression a + b is evaluated using the maximum bit width of its operands. 
  • Since both a and b are bit[2], the result is also bit[2]. 
  • Arithmetic overflow is therefore possible and well-defined. 

For example: 

  • a = 3, b = 3 → a + b = 6, truncated to 2 in 2 bits. 

When this struct is randomized with PSS randomize, Perspec applies exactly these standard semantics. As a result, valid solutions include combinations such as: 

  • a=3 b=3 c=2 
  • a=2 b=3 c=1 
  • a=3 b=1 c=0 

If your intent is instead to treat the computation as a wider (for example, 32-bit) operation, this can be made explicit using a cast: 

randomize my_struct with {  
            my_struct.a + my_struct.b == (bit[32])my_struct.c;  
            my_struct.a != 0;  
            my_struct.b != 0;  
}//randomize  

Or, more explicitly: 

randomize my_struct with {  
           (bit[32]) my_struct.a + (bit[32])my_struct.b == (bit[32])my_struct.c;  
            my_struct.a != 0;  
            my_struct.b != 0;  
}//randomize 

By making the bit width explicit, the constraint behavior becomes unambiguous and independent of automatic type propagation rules. 

Example 2: Mixed Bit Widths in an Expression 

Consider a constraint that mixes operands of different bit widths: 

import std_pkg::*; 
component pss_top{ 
struct S { 
rand bit[32] a, b; 
rand bit c; 
} 
     
action test {         
exec post_solve { 
 
S my_struct; 
 
 // Call randomize explicitly on the struct instance 
randomize my_struct with { 
 my_struct.a + my_struct.b= my_struct.c; 
} 
             
// Print the randomized values 
print ("Randomized values: a=%d, b=%d, c=%d\n",my_struct.a, my_struct.b,    my_struct.c); 
 
} 
}
} 

 

Per the PSS standard: 

  • The expression is evaluated using the largest bit width among the operands, which is 32 bits. 
  • The result of a + b is therefore a 32-bit value. 
  • The 1-bit variable c must match the truncated result (either 0 or 1). 

When this struct is randomized with PSS randomize, Perspec correctly produces values such as: 

  • large 32-bit values for a and b 
  • c equal to the least significant bit of their sum 

If your intent is to restrict a and b to small values (for example, to mimic a narrower arithmetic model), this intent should be expressed explicitly: 

 randomize my_struct with {  
           (bit[32]) my_struct.a + (bit[32])my_struct.b == (bit[32])my_struct.c;  
            my_struct.a  in [0..1]; 
            my_struct.b  in [0..1]; 
 } 

This makes the constraint semantics clear and avoids relying on implicit truncation effects. 

Example 3: Signed Variables and Unsigned Range Bounds 

This example illustrates how signedness is determined in set membership constraints. 

import std_pkg::*; 
component pss_top{ 
struct S { 
rand int a; 
} 
     
action test {         
exec post_solve { 
 
S my_struct; 
 
// Call randomize explicitly on the struct instance 
randomize my_struct with {  
my_struct.a in [0..0xffffffff]; 
 }//randomize 
 
// Print the randomized values 
print ("Randomized values: a=%d", my_struct.a); 
} 
} 
} 
 

According to the PSS rules: 

  • The presence of an unsigned operand (the literal 0xffffffff) causes the entire expression to be evaluated as unsigned. 
  • The signed variable a is therefore treated as an unsigned 32-bit value for the purpose of this constraint. 

As a result: 

  • Both positive and negative values of a may satisfy the constraint, because negative values become large unsigned numbers. 

If your intent is to restrict a to non-negative values, this must be stated explicitly: 

randomize my_struct with {  
           my_struct.a in [0..0xffffffff]; 
           my_struct.a>=0; 
}//randomize 

Example 4: Range Lists with Mixed Signed and Unsigned Bounds 

Consider a range with mixed signed and unsigned literals: 

import std_pkg::*; 
component pss_top{ 
struct S { 
rand int a; 
} 
     
action test {         
exec post_solve { 
 
S my_struct; 
 
// Call randomize explicitly on the struct instance 
randomize my_struct with {  
my_struct.a in [-256..0xff]; 
} 
 
         
// Print the randomized values 
print ("Randomized values: a=%d\n", my_struct.a); 
} 
} 
} 

According to the PSS rules: 

  • The presence of the unsigned literal 0xff causes all operands to be treated as unsigned. 
  • The lower bound -256 becomes 0xffffff00 when interpreted as unsigned. 
  • The resulting range is empty, since the lower bound is greater than the upper bound. 

An empty range produces a contradiction during procedural randomization. 

To express the intended signed range, the bounds should be made explicitly signed: 

randomize my_struct with {  
           my_struct.a in [-256..(int)0xff]; 
}//randomize 

This ensures that all operands are treated consistently as signed values. 

Summary and Best Practices 

PSS defines precise rules for numeric expression evaluation during randomization. Perspec’s support for PSS randomize (procedural randomize) follows these standard semantics, enabling predictable behavior that aligns with the LRM. 

However, when expressions involve mixed bit widths, mixed signedness, or implicit type promotion, the resulting behavior may not always be intuitive at first glance. Therefore, it is recommended to follow the following best practices: 

  • Make bit widths explicit when overflow or truncation matters. 
  • Use casts to control signedness deliberately. 
  • Add explicit constraints when you want to restrict value ranges. 

By expressing intent clearly in the code, you avoid relying on implicit rules and ensure that your constraints behave exactly as intended during PSS randomization.

Learn more about Cadence Perspec System Verifier and how it supports PSS.

© 2026 Cadence Design Systems, Inc. All Rights Reserved.

  • Terms of Use
  • Privacy
  • Cookie Policy
  • US Trademarks
  • Do Not Sell or Share My Personal Information