Skip to main content

Command Palette

Search for a command to run...

SV Part -5 fork-join and constraints

Updated
8 min read
SV Part -5 fork-join and constraints

fork-join

need for fork join :

Test bench components (BFM,Generator,Monitor) can have multiple concurrent running process.

in verilog module, concurrent process can be implemented using multiple always blocks.

3 concurrent process -->use 3 always blocks.

class does not have always block, how to achive concurrent nature?

fork join is used to achive concurrent running behaviour in class.

fork join triggers all the processes defined inside the block at same time.

fork join family

We need the fork-join family because different situations require different synchronization: sometimes you want to wait for all tasks, sometimes just one, and sometimes none. The single fork...join cannot cover all these use cases.

  1. fork join : if all the process is done then only start executing outside statements.

    application for fork join

  2. fork join_any : if any one of the process is done then start executing outside statements.

    application for fork join_any

  3. fork join_none : if none of the process is done then start executing outside the statements.

    application for fork join

Labelling

  • Labeling in SystemVerilog assigns identifiers to code blocks (e.g., begin...end, fork...join) to enhance readability, target specific sections for revisions, control execution (e.g., via disable), and improve debugging by tracing block-specific outputs in logs.

Constrained Random Verification (CRV)

  • Putting together constraints and randomization is called as CRV.

  • While verifying a complex design, we can’t use a single test case to do the whole verification.

    • if test case fails, we are not sure what feature is causing the failure.

    • By dividing the design feature in to different testcases, when a test fails, we know what feature is not working.

    • By using constraints, we create a scenario that targets a specific feature.

  • seed:

    • input to the tool used as a starting point for randomization.

    • vsim top -sv_seed 1000

    • seed helps generate different random patterns for the same testcase by using different seed values.

importance of seed in projects :

  • A complex design has multiple test cases.

  • When a test case fails.

  • possible reasons for failure:

    • some test bench or test case issue.

      • Verification engineer will review and fix it.

      • Should not email or contact RTL team for this.

    • some bug in the design

      • Design engineer will review and fix it.

      • Design team releases a new version of RTL code.

      • Verification engineer should take same TB where testcase failed, only change the RTL code.

        • Return the same test case with same seed.

          • if test passes, then RTL fix is working.

          • if test fails, then RTL fix is not working.

Directed Verification

  • User manually decides the scenario to apply, this limits the scope of verification since every time same scenario is targeted when test is run(even with different Seeds).

    • Directed verification

      • addr = 110; // Fixed value => this indicates directed
    • Constrained random verification

      • addr inside {[110:150]};
  • In directed verification, since user doesn’t generate different scenarios, possibility of finding bugs is less.

  • Whereas with constrained random verification, different scenarios gets created for the same test case(using different seed), hence it improves the chances of finding bugs in the design.

when we use directed verification:

  • initial stages of project use constrained random verification.

  • Final stages of verification we do directed verification

    • targeted for closing functional and code coverage

    • till we get 95% functional and code coverage, use CRV

    • to close the remaining 5% coverage, use directed scenario.

Constraints importance

  • In any project, verification engineer spends lot of time in developing testcases

    • Test cases are developed as per the test plan

    • Adding new testcase for functional and code coverage closure.

  • New Test cases coding is about writing inline constraints to create a different scenario.

  • if transaction or packet class is coded with right set of constraints, overall testcases coding effort reduces significantly.

  • Test case development majorly involves using constraints to generate stimulus specific to the test.

constraints

constraints are limitations of signals

  • Before constraints: In Verilog, if you wanted random values, you had to write your own code using $random and then manually check ranges, relationships, and conditions. This was tedious and error‑prone because you had to enforce rules yourself.

  • Problem: No built‑in way to express rules like “address must be aligned,” “packet length must be > 0,” or “two fields must be consistent.” You ended up writing a lot of procedural code to filter or regenerate values until they matched your requirements.

  • Constraints (SystemVerilog): Introduced to overcome this. You can directly declare rules inside a class (constraint blocks), and the solver automatically generates random values that satisfy them.

Why we need constraints:

They replace manual $random filtering with a powerful, declarative way to specify rules. This makes testbench stimulus generation faster, cleaner, and less error‑prone.

  • constraints can be applicable for two major things.

    • it tells about that valid input will be applied to the design or not.

    • in every test, it will focus on the specific feature of the design.

Types of constraints :

  • we have 2 types of constraints

      1. in-line constraints

        1. in-class constraints
  • in-line constraints

    • the constraints which is mentioned in the same line of the randomization.

    • we will use “with” clause for in-line constraints.

      syntax: object.randomize() with {constraint};

  • in-class constraints

    • the constraints which are mentioned inside the class are known as in-class constraints.

      1. simple constraints

        1. distributive constraints

        2. if-else constraints

        3. implicit constraint

        4. iterative constraints

        5. unique constraints

        6. soft constraints

        7. variable order constraints

simple constraints

the constraint which is mentioned with simple mathematical expression.ta

distributive constraints

  • it will generate the random values basing on the weightages

in distributive constraint we need to consider “dist

providing weightages for values

  • syntax: <variable> dist {<value>:=<weightage1>,<value2>:=weitage2};

providing weightages for ranges

syntax: <variable> dist {<range1>:/<weightage1>,<range2>:/weitage2};

simple example for distributive constraint

if-else constraints

  • basing on the conditions, it will generate the random values

in constraint we can’t able to consider the begin and end, so representing the multiple lines in the blocks we can be use “{}

implicit constraints

  • it is same as if-else constraints, but here we need to consider implication operator

  • implication operator can be represented as ()

    syntax: constraint constraint_name{

    (condition1) → (logic1);

    (condition2) → (logic2);

    (condition3) → (logic3);

    ,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,

    }

Q. consider two variables a and b, if a is +ve then b is also +ve, if a is -ve then b is also -ve.

iterative constraints

  • where we have multiple variables or multibit variables we need to consider this iterative constraints.

  • for accessing the arrays, queues,vectors, assosiative arrays we need to consider this means we need to consider loops.

    • for loop, while loop, forever loop, repeat loop, foreach loop.

    • in constraints only foreach loop is applicable, Remaining loops are not applicable because, in the foreach loop, we do not need to increment the iterative variable.

      syntax: constraint constraint_name{

      foreach(arr[i]){

      // iterative logic;

      }

      }

Same thing for Dynamic arrays

Note: 4 ways of size allocation

  1. function new()

  2. pre_randomize()

  3. inside the constraint.(arry.size()==len)

  4. inside the module obj.arr_name = new[size];

soft constraints

  • if any constraint conflict will be happened, randomization will be failed.

  • to avoid that constraint conflict we need to mention one of the constraint as soft.

    constraint c{

    a<50;

    a>100; // randomization will be failed due to constraint conflict.

    }

priorities

in-lineIn-classpriority
normalnormalconflict
normalsoftIn-line
softnormalin-class
softsoftin-line

Unique constraints

we can use randc(cyclic) for unique values but for multiple variables, single randc it is not possible, so we with this unique constraint

  • it is used to generate the unique values b/w two or more variables

    syntax: constraint constraint_name{

    unique {variable1,variable2,variable3………};

    }

variable order constraints

randomization function will be happened at ones. so any variable dependency are presented, if the solvation will not happened properly than it will go to unknown states. to avoid those things we need to consider this variable order constraint. we need to use keywords “solve“ and “before

syntax: constraint constraint_name{

(condition) - > (logic)

solve <condition> before <logic>;

}

simple example for understanding the variable order constraint