In reply to Jonathan_Alvarez:
In the paper’s example, the constraint about the length (i.e. length==6’h10) is just for demonstration, you can remove that to get the variable length you want. In reality length limitation constraints do exist. And yes you can add the following line in any procedural block after a successful randomization attempt (post_randomize is a good place).
start_end_addr_hash [start_addr] = start_addr + length - 1;
Back to the debate about performance, the introduced example (second one) shall generate all address ranges upfront. Although I am fan of late-randomization (randomize at the right time to take the DUT and testbench states into consideration), this is not just the problem I see with the second code. The second code has a nested foreach loops, this is a solver performance overkill, especially if size of the arrays are large enough. An interesting exercise is to measure the time the solver will solve the second example with array sizes of 100 and above.
The first code (code in the paper) kind of escape from this problem by only randomizing a single attempt at a time, then saving the start and end addresses in a hash table acting as a back-log/guiding reference for the next randomization attempt. Hence only one foreach is used in constraint, which still possess a performance bottleneck, however much faster than the second solution.
That said, if I were to write the code I would neither use the first nor the second solutions to solve the simple problem of non-overlapping address ranges. I would just remove the constraint completely and embrace the constraint with a checking loop like so.
class c;
rand bit [31:0] start_addr;
rand bit [5:0] length;
bit [31:0] start_end_addr_hash [bit[31:0]];
endclass
...
c c1 = new;
...
forever begin
duplicate = 0;
assert(c1.randomize());
foreach (c1.start_end_addr_hash [i])
if ((c1.start_addr <= c1.start_end_addr_hash [i]) && ((c1.start_addr + c1.length -1) >=i )) begin
duplicate = 1;
break;
end
if (!duplicate) break;
end
c1.start_end_addr_hash [c1.start_addr] = c1.start_addr + c1.length - 1;
The code above shall free the solver from complicated constraints allowing it to focus on the distribution. If we assumed an ideal solver distribution (e.g. BDD solver will be efficient to solve the simplified problem above), the third solution will be much faster than both solutions above (especially the second one).
Same stands true for the original question of this post; how to generate an array of random unique elements. Well you can also use procedural code and minimal solver work if possible, like so:
class dummy_c;
randc bit [31:0] val;
endclass
class trans;
rand bit [31:0] addrs [];
function void post_randomize();
dummy_c dc = new;
foreach (addrs[i]) begin
assert (dc.randomize);
addrs[i] = dc.val;
end
endfunction
endclass
Thanks,
Ahmed Yehia