Skip to content

Commit 837e8c7

Browse files
committed
[dv,cip] Rewrite `_DV_MUBI_DIST to avoid warnings
It turns out that randomising with a distribution like this if (0) { XYZ dist { [1:0] := 1; }; } generates a runtime warning from Xcelium (even though the distribution expression isn't actually used). Fortunately, range endpoints can be general expressions, so we can do everything with ternary operators instead. We can also avoid repeating stuff if we define `MIN / `MAX macros. This commit also fixes the weighting for true/false. Suppose we want to distribute with weights ZeroW, OneW, OtherW for 0, 1, other in a way that e.g. the fraction of ones is OneW / (ZeroW + OneW + OtherW). The following would definitely be wrong: value dist { 0 := ZeroW, 1 := OneW, [2:9] := OtherW }; Because there are eight "other" values, the fractions end up looking like OneW / (ZeroW + OneW + 8 * OtherW). Oops! To make everything line up properly, we multiply by 8: value dist { 0 := 8 * ZeroW, 1 := 8 * OneW, [2:9] := OtherW }; and will now have fractions like 8 * OneW / (8 * ZeroW + 8 * OneW + 8 * OtherW = OneW / (ZeroW + OneW + OtherW) Generalising to the macro, there are (MAX_ - 1) possible values (instead of 10), so we need to scale up by (MAX_ - 3). Signed-off-by: Rupert Swarbrick <rswarbrick@lowrisc.org>
1 parent 97b690f commit 837e8c7

File tree

1 file changed

+40
-21
lines changed

1 file changed

+40
-21
lines changed

hw/dv/sv/cip_lib/cip_macros.svh

Lines changed: 40 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -49,28 +49,47 @@
4949
end
5050
`endif
5151

52-
// A macro to simplify the distribution constraint of mubi type variable
53-
// Don't use this macro directly, use DV_MUBI4|8|16_DIST.
54-
// The weights of both TRUE and FALSE are scaled by the number of other
55-
// values, and this uses ":=" for the distribution of other values, so they
56-
// are truly uniform.
57-
// The MAX_ argument is the maximum value that VAR_ can take, which means
58-
// (MAX_ - 1) is the scaling factor.
52+
// Macros that expand to a ternary expression giving the smaller / larger of the two values.
53+
//
54+
// These make no guarantee to only evaluate arguments once.
55+
`ifndef _DV_TERNARY_MIN
56+
`define _DV_TERNARY_MIN(a_, b_) (((a_) < (b_)) ? (a_) : (b_))
57+
`endif
58+
`ifndef _DV_TERNARY_MAX
59+
`define _DV_TERNARY_MAX(a_, b_) (((a_) < (b_)) ? (b_) : (a_))
60+
`endif
61+
62+
// A macro that expands to a constraint giving distribution for a mubi-type variable
63+
// Don't use this macro directly: use DV_MUBI4|8|16_DIST instead.
64+
//
65+
// Arguments:
66+
//
67+
// VAR_ The variable whose distribution is being constrained
68+
// TRUE_ MuBi true value
69+
// FALSE_ MuBi false value
70+
// MAX_ The maximum value in the bit-vector range for the value
71+
// T_WEIGHT_ A weight to give the "true" case
72+
// F_WEIGHT_ A weight to give the "false" case
73+
// OTHER_WEIGHT_ A weight to give all other cases
74+
//
75+
// This macro uses ":=" to give weights for the other cases in order that the individual values
76+
// won't have a weight that depends on the length of the range containing them. There are (MAX_ - 3)
77+
// items in these other ranges, so we scale T_WEIGHT and F_WEIGHT by that value to ensure that
78+
// T_WEIGHT/F_WEIGHT/OTHER_WEIGHT give the relative probabilities of true/false/something-else.
79+
//
80+
// Some tools generate a warning if there is a backwards range ([big:little]) in the distribution,
81+
// even if an if/else check ensures that it isn't used. To avoid this warning, we use a ternary
82+
// operator to extract the larger/smaller value.
5983
`ifndef _DV_MUBI_DIST
60-
`define _DV_MUBI_DIST(VAR_, TRUE_, FALSE_, MAX_, T_WEIGHT_, F_WEIGHT_, OTHER_WEIGHT_) \
61-
if (TRUE_ > FALSE_) { \
62-
VAR_ dist {TRUE_ := (T_WEIGHT_) * ((MAX_) - 1), \
63-
FALSE_ := (F_WEIGHT_) * ((MAX_) - 1), \
64-
[0 : FALSE_ - 1] := (OTHER_WEIGHT_), \
65-
[FALSE_ + 1 : TRUE_ - 1] := (OTHER_WEIGHT_), \
66-
[TRUE_ + 1 : (MAX_)] := (OTHER_WEIGHT_)}; \
67-
} else { \
68-
VAR_ dist {TRUE_ := (T_WEIGHT_) * ((MAX_) - 1), \
69-
FALSE_ := (F_WEIGHT_) * ((MAX_) - 1), \
70-
[0 : TRUE_ - 1] := (OTHER_WEIGHT_), \
71-
[TRUE_ + 1 : FALSE_ - 1] := (OTHER_WEIGHT_), \
72-
[FALSE_+ 1 : (MAX_)] := (OTHER_WEIGHT_)}; \
73-
}
84+
`define _DV_MUBI_DIST(VAR_, TRUE_, FALSE_, MAX_, T_WEIGHT_, F_WEIGHT_, OTHER_WEIGHT_) \
85+
VAR_ dist { \
86+
TRUE_ := (T_WEIGHT_) * ((MAX_) - 3), \
87+
FALSE_ := (F_WEIGHT_) * ((MAX_) - 3), \
88+
[0 : `_DV_TERNARY_MIN(TRUE_, FALSE_)-1] := (OTHER_WEIGHT_), \
89+
[(`_DV_TERNARY_MIN(TRUE_, FALSE_)+1) : \
90+
(`_DV_TERNARY_MAX(TRUE_, FALSE_)-1)] := (OTHER_WEIGHT_), \
91+
[(`_DV_TERNARY_MAX(TRUE_, FALSE_)+1):(MAX_)] := (OTHER_WEIGHT_) \
92+
};
7493
`endif
7594

7695
// inputs of these macros

0 commit comments

Comments
 (0)