'Way to pick random addresses from dynamic ranges in SV constraints

I have a requirement to pick random addresses from a set of predefined ranges in Systemverilog

program test;

int unsigned q[$], rSz;
typedef struct {
  int unsigned from, till;
} range_t;

initial begin
    range_t ranges[$];

    ranges.push_back('{from: 'h10, till: 'h1F});
    ranges.push_back('{from: 'h30, till: 'h3F});
    ranges.push_back('{from: 'h50, till: 'h5F});

    rSz = ranges.size();
    $displayh(rSz, ranges);

    repeat (10) begin
        std::randomize(q) with {
            q.size() inside {[4:8]};
            foreach (q[i]) {
                q[i] inside {[ranges[0].from: ranges[0].till]} ||
                q[i] inside {[ranges[1].from: ranges[1].till]} ||
                q[i] inside {[ranges[2].from: ranges[2].till]} ;
            }
        };
        $displayh(q);
    end
end

endprogram : test

It works fine if I have a fixed number of ranges that I can hard-code. But the number of ranges itself is dynamic, I can not hard-code the ranges as in the foreach loop.

I can't use a nested foreach as the statements in the inner loop will be treated as individual constraints and fail with each other as the ranges are non-overlapping.

All I could come up with is something like below where I use the ranges in order and then shuffle at the end.

program test;

int unsigned q[$], rSz;
typedef struct {
  int unsigned from, till;
} range_t;

initial begin
    range_t ranges[$];
    ranges.push_back('{from: 'h10, till: 'h1F});
    ranges.push_back('{from: 'h30, till: 'h3F});
    ranges.push_back('{from: 'h50, till: 'h5F});

    rSz = ranges.size();
    $displayh(rSz, ranges);

    repeat (10) begin
        std::randomize(q) with {
            q.size() inside {[4:8]};
            foreach (q[i]) {
                q[i] inside {[ranges[i % rSz].from: ranges[i % rSz].till]};
            }
        };
        q.shuffle();
        $displayh(q);
    end
end

endprogram : test

Is there a better way of doing this in general?

I am looking for something like foreach-or where all lines in loop are or-ed instead of and-ed - if that explains the requirement.



Solution 1:[1]

Most people are familiar with the sum() array reduction method, but there are also or(), and(), and xor() reduction methods as well.

module test;
  int unsigned q[$], rSz;
  typedef struct {
    int unsigned from, till;
  } range_t;
  
  initial begin
    range_t ranges[$];

    ranges.push_back('{from: 'h10, till: 'h1F});
    ranges.push_back('{from: 'h30, till: 'h3F});
    ranges.push_back('{from: 'h50, till: 'h5F});

    rSz = ranges.size();
    $displayh(rSz,, ranges);

    repeat (10) begin
      assert(std::randomize(q) with {
        q.size() inside {[4:8]};
        foreach (q[i]) 
          ranges.or(range) with (q[i] inside {[range.from: range.till]});
      });
      $displayh(q);
    end
  end
endmodule: test

See section 7.12.3 Array reduction methods in the IEEE 1800-2017 SystemVerilog LRM.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 dave_59