Skip to content

[dv,cip] Rewrite `_DV_MUBI_DIST to avoid warnings#29330

Open
rswarbrick wants to merge 1 commit intolowRISC:masterfrom
rswarbrick:dv-mubi-dist
Open

[dv,cip] Rewrite `_DV_MUBI_DIST to avoid warnings#29330
rswarbrick wants to merge 1 commit intolowRISC:masterfrom
rswarbrick:dv-mubi-dist

Conversation

@rswarbrick
Copy link
Contributor

@rswarbrick rswarbrick commented Feb 17, 2026

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).

@rswarbrick rswarbrick requested a review from a team as a code owner February 17, 2026 11:40
@rswarbrick rswarbrick removed the request for review from a team February 17, 2026 11:40
@rswarbrick rswarbrick added the Component:DV DV issue: testbench, test case, etc. label Feb 17, 2026
@rswarbrick
Copy link
Contributor Author

rswarbrick commented Feb 17, 2026

Dammit! Just realised that I had an off-by-one error in the commit message. Take 2 3...

Copy link
Contributor

@marnovandermaas marnovandermaas left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it's not quite right, so I've made a suggestion.

Copy link
Contributor

@elliotb-lowrisc elliotb-lowrisc left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm confused. Why not use the :/ operator for the other values?

@rswarbrick
Copy link
Contributor Author

The problem is just that you might have the "other" category broken into multiple ranges and you don't want the probability of a given "other" value to depend on the length of the range that it happens to be in.

Copy link
Contributor

@elliotb-lowrisc elliotb-lowrisc left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah OK, I think some tweaks to the code comments could avoid some future confusion

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>
Copy link
Contributor

@elliotb-lowrisc elliotb-lowrisc left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems clearer to me, thanks

@elliotb-lowrisc
Copy link
Contributor

Whoops, wrong button

@rswarbrick
Copy link
Contributor Author

@vogelpi: This is the nicer version of the commit that was previously the last item in #28695. Would you mind taking a quick look at it?

Copy link
Contributor

@marnovandermaas marnovandermaas left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks good to me thanks for the clarifying comments.

Copy link
Contributor

@vogelpi vogelpi left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @rswarbrick for cleaning this up. The comments and motivation are very clear. But I have some questions regarding the correctness.

Comment on lines +88 to +89
TRUE_ := (T_WEIGHT_) * ((MAX_) - 3), \
FALSE_ := (F_WEIGHT_) * ((MAX_) - 3), \
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am not sure the -3 is correct. In the example you max in the commit message, MAX_ is 9, but you scale by 8 (== MAX_ - 1) and not by 6 (== MAX_ - 3).

Comment on lines +90 to +93
[0 : `_DV_TERNARY_MIN(TRUE_, FALSE_)-1] := (OTHER_WEIGHT_), \
[(`_DV_TERNARY_MIN(TRUE_, FALSE_)+1) : \
(`_DV_TERNARY_MAX(TRUE_, FALSE_)-1)] := (OTHER_WEIGHT_), \
[(`_DV_TERNARY_MAX(TRUE_, FALSE_)+1):(MAX_)] := (OTHER_WEIGHT_) \
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think this is correct based on an example I just did on paper based on the Mubi4 type with equal weights for true, false and invalid. Unless I made a mistake, inserting the numbers gives me the following weights:

  • 6 (true) := 4
  • 9 (false) := 4
  • 0:5 := 1/3 - meaning the total weight for this group is 6 * 1/3 = 2
  • 7:8 := 1/3 - total weight 2 * 1/3 = 2/3
  • 10:15 := 1/3 - total weight 6 * 1/3 = 2
    So the total weight of the invalid group is 4 + 2/3 and not 4. Does this make sense?

I think you need to take the set size into account as well and then use :/ instead of :=.

@vogelpi
Copy link
Contributor

vogelpi commented Mar 10, 2026

One more point that came to my mind: this change is going to affect potentially all regressions. So we must keep an eye on the coverage metrics and make sure results won't degrade @rswarbrick .

Maybe to reduce the risk, can we infer which blocks are expected to be affected? I.e., where is macro used / not used?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Component:DV DV issue: testbench, test case, etc.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants