How to write efficient DV constraints?

Split Bigger Problem into Smaller Ones

Instead of mixing everything together, splitting bigger problems into smaller steps offers better performance. One may consider using “Solve-Before” for user defined solving order.

In addition, it is also recommended to sequence constraint solving in “pre_randomize()” and “post_randomize()” whenever possible.

Use “Solve-Before” with Caution

Although user-defined “solve-before” constructs are a powerful tool to control solver order, improper usage can lead to multiple retries and simulation performance degradation.

In the example below, “x” and “y” may be resolved early to certain illegal values that cannot satisfy the constraint. Constraining “x” and “y” properly avoids constraint solver retries.

        class myClass {
            rand bit [7:0] x, y, z;

            constraint legal_range {
                (x * y) + z == 10;
                solve x, y before z;

                // constraining x & y properly to avoid retries
                (x * y) < 10;
            }
        }
        endclass

Use SystemVerilog Build-in Functions

Using SystemVerilog built-in functions improves readability and avoids errors. For example, to randomize and uniquify an array “arr”, use “arr.unique()”; to sort an array “arr”, use “arr.sort()”.

Prefer Integer Randomization Functions Whenever Possible

There are multiple ways to randomize variables, for example:

  1. Standard randomization function “std::randomize()
  2. Object built-in randomization function “obj.randomize()
  3. Unsigned integer randomization functions “$urandom()” and “$urandom_range()
  4. Signed integer randomization function “$random()

Use integer randomization functions whenever possible, since they offer tens or even hundreds of times performance gains over standard and object built-in randomization functions. For example:

        // Randomize a 64-bit unsigned variable “var”
        // Instead of using
        std::randomize(var);
        // Using two concatenated $urandom()
        var = {$urandom(), $urandom()};

        // Randomize an unsigned integer “var”
        // Instead of using
        std::randomize (var) with {
            var >= MIN;
            var <= MAX;
        };
        // Use $urandom_range() instead
        var = $urandom_range(MIN, MAX);

        // Randomize a bit with unified distribution
        rand bit rand_bit;
        // Instead of using
        std::randomize (rand_bit) with {
            rand_bit dist {0:=50, 1:=50};
        };
        // Use $urandom_range() instead
        rand_bit = $urandom_range(1);

Avoid Using Real Datatypes

SystemVerilog LRM defines that constraint solvers only need to handle integer types. Real datatypes in constraints may result in poor randomization performance. For example:

        class myClass {
            rand int unsigned x, y;

            constraint xy_range {
                x inside {[100 : 1000]};
                // Do not write this way
                // y inside {[0.5*x : x]};
                // Use integer based workaround
                y inside {[x/2 : x]};
            }
        }
        endclass

Subscribe

Enter your email to get updates from us. You might need to check the spam folder for the confirmation email.

Leave a comment