Inside a constraint block, there is NO implied order of how the variable values will be solved. The SystemVerilog constraint solver is free to choose the variables to randomize first.
Let us look at an example below. The intention is to randomize “addrType” first, and then randomize “addr” value per “addrType”. However, the constraint solver can randomize “addr” first, followed by “addrType”. If “addrType” == LOW, then “addr” must be in the range of [0:63]; however, this does not imply that if “addr” is in the range of [0:63], then “addrType” == LOW.
typedef enum {LOW, MID, HIGH} addr_t;
class myAddrBus {
rand bit[7:0] addr;
rand addr_t addrType;
constraint addr_range {
if (addrType == LOW) addr inside {[0:63]};
else if (addrType == MID) addr inside {[64, 127]};
else if (addrType == HIGH) addr inside {[128:255]};
// equivalently, the use of implication operators is the same as using if-else
// (addrType == LOW) -> addr inside {[0:63]};
// (addrType == MID) -> addr inside {[64, 127]};
// (addrType == HIGH) -> addr inside {[128:255]};
}
}
We can replace the implication operators with equivalent operators. In this example, the constraint solver can still randomize “addr” first, followed by “addrType”. The difference is, if “addrType” == LOW, then “addr” must be in the range of [0:63]; conversely, if “addr” is in the range of [0:63], then “addrType” == LOW.
class myAddrBus {
rand bit[7:0] addr;
rand addr_t addrType;
constraint addr_range {
(addrType == LOW) <-> addr inside {[0:63]};
(addrType == MID) <-> addr inside {[64, 127]};
(addrType == HIGH) <-> addr inside {[128:255]};
}
}
To dictate the constraint solver order, one can declare a random property as “randc” instead of “rand”. The constraint solver randomizes “randc” before “rand” properties. For example, we can declare “addrType” as “randc” and “addr” as “rand”.
However, there are subtle differences between “randc” and “rand”: “randc” exhausts all values before repeating any value, while “rand” can repeat without exhausting all possible values. (Think of “randc” as picking a card from a deck of cards, while “rand” as rolling a dice).
An alternative approach is to use “solve-before” construct to set solving order for the same type of random properties. Using the same example above:
class myAddrBus {
rand bit[7:0] addr;
rand addr_t addrType;
constraint addr_range {
if (addrType == LOW) addr inside {[0:63]};
else if (addrType == MID) addr inside {[64, 127]};
else if (addrType == HIGH) addr inside {[128:255]};
solve addrType before addr;
}
}
Note, “solve-before” construct cannot force “rand” to be randomized before “randc” properties.

Leave a comment