Facebook/LinkedIn login is now deprecated, please disconnect our access to your social profile.
Let us contribute to a cleaner Earth, Go Green Updated: May 31, 2020
3 minutes reading time (604 words)

Power of SystemVerilog Constraints

sv_power_of_constraints Use constraints to generate two queues with unique numbers and random size

SystemVerilog constraints are pretty amazing ! Lets see one use case where constraints are used to generate two queues of random sizes with unique values. Let us assume total number of elements in each queue should be less than or equal to 10.

Using a loooong way

Consider that both queues are part of a class called ABC. The first logical thing would be to decide the size of each queue which can be maintained in two separate variables that can be randomized. The constraints on these variables ensure that the total number of elements in each queue meets the requirement.

class ABC;
  int l_q[$];
  int l_q2[$]; 
 
  rand int l_q_size;
  rand int l_q2_size;
 
  constraint c_size { l_q_size inside {[1:9]};
                     l_q2_size inside {[1:10]};
                     (l_q_size + l_q2_size) <= 10;
                      l_q2_size >= 1;
                      solve l_q_size before l_q2_size;
                    }
endclass
 
module tb;
  initial begin
    ABC abc = new;
    abc.randomize();
    $display ("l_q_size=%0d l_q2_size=%0d", abc.l_q_size, abc.l_q2_size);
 
    for (int i = 0; i < abc.l_q_size; i++) begin
      int l_num;
      std::randomize(l_num) with { l_num inside {[1:10]};
                                  !(l_num inside {abc.l_q});
                                  };
      abc.l_q.push_back(l_num);
    end
 
    for (int i = 0; i < abc.l_q2_size; i++) begin
      int l_num;
      std::randomize(l_num) with { l_num inside {[1:10]};
                                  !(l_num inside {abc.l_q2, abc.l_q});
                                  };
      abc.l_q2.push_back(l_num);
    end
 
    $display("l_q=%p", abc.l_q);
    $display("l_q2=%p", abc.l_q2);
  end
endmodule
 

The class instance abc is randomized to decide on the size for each queue. That many number of elements can be randomized and pushed into the queue using a simple for loop. For each iteration, a local variable is randomized using the scope randomizer with inline constraints. These constraints ensure that unique elements are pushed into the queue and each element falls within the valid range.

In a similar way, the second for loop pushes a new set of elements into the second queue. Note that the inline constraint has also considered l_q or the first queue to keep elements unique between the two queues.

Using only constraint solver

This is the fastest way to generate two queues with unique data.

class ABC;
  rand int l_q[$];
  rand int l_q2[$];
 
  constraint c_q {   
            l_q.size() + l_q2.size() inside {[1:10]};
            l_q2.size() > 0;
            l_q.size() > 0;
 
          foreach (l_q[i]) {
            l_q[i] inside {[1:10]};
          }
 
          foreach (l_q2[i]) {
            l_q2[i] inside {[1:10]};
          }
 
          unique {l_q, l_q2};
        }
endclass
 
module tb;
  initial begin
    ABC abc = new;
    abc.randomize();
    $display("l_q=%p", abc.l_q);
    $display("l_q2=%p", abc.l_q2);
  end
endmodule
 

This could be your next interview question !

SystemVerilog Loops - when and where to use
The Art of Logging

Related Posts

 

Comments 2

Guest - DVJose on Monday, 01 June 2020 21:37

I think a few of the constraints are redundant here. The code could be much shorter. With regards to the unique constraint -

(1) the unique constraint can be taken out of the foreach
(2) One unique constraint that bundles both the queues is sufficient.

Similiary, the size can be bundled into one sum.

class ABC;
rand int l_q[$];
rand int l_q2[$];

constraint c_q2 {
l_q.size() + l_q2.size() inside {[1:10]};
foreach (l_q[i]) {
l_q[i] inside {[1:10]};
}
foreach (l_q2[i]) {
l_q2[i] inside {[1:10]};
}
unique {l_q, l_q2};
}
endclass

module tb;
initial begin
ABC abc = new;
abc.randomize();
$display("l_q=%p", abc.l_q);
$display("l_q2=%p", abc.l_q2);
end
endmodule

I think a few of the constraints are redundant here. The code could be much shorter. With regards to the unique constraint - (1) the unique constraint can be taken out of the foreach (2) One unique constraint that bundles both the queues is sufficient. Similiary, the size can be bundled into one sum. class ABC; rand int l_q[$]; rand int l_q2[$]; constraint c_q2 { l_q.size() + l_q2.size() inside {[1:10]}; foreach (l_q[i]) { l_q[i] inside {[1:10]}; } foreach (l_q2[i]) { l_q2[i] inside {[1:10]}; } unique {l_q, l_q2}; } endclass module tb; initial begin ABC abc = new; abc.randomize(); $display("l_q=%p", abc.l_q); $display("l_q2=%p", abc.l_q2); end endmodule
Admin on Monday, 01 June 2020 22:05

Thanks for your comments ! Yes, I agree that unique can be brought out of the loop. However, with only l_q.size() + l_q2.size() inside {[1:10]} gives the possibility that either l_q or l_q2 be empty. So in addition to that, l_q.size() and l_q2.size() > 0 would be required. I have condensed the code into a single constraint instead of two with unique outside the loop.

Thanks for your comments ! Yes, I agree that [i]unique[/i] can be brought out of the loop. However, with only l_q.size() + l_q2.size() inside {[1:10]} gives the possibility that either l_q or l_q2 be empty. So in addition to that, l_q.size() and l_q2.size() > 0 would be required. I have condensed the code into a single constraint instead of two with [i]unique[/i] outside the loop.
Already Registered? Login Here
Guest
Friday, 03 July 2020

By accepting you will be accessing a service provided by a third-party external to https://www.chipverify.com/

You consent to our cookies if you continue to use our website. To know more about cookies, see our privacy policy. I accept cookies from this site.

Agree