2
votes

I want to constrain an address in System Verilog so that the address is equal to two the power of value. for example the generated address(16-bit) should be

addr = 0, 2, 4, 8, 16, 32 .... 32,768

The following works for me. However, I am looking for any other short and elegant way of doing it.

class two_power_addr;
  rand bit [15:0] addr;
  bit [15:0] temp;

  constraint c_addr {
    addr == temp;
  }

endclass

module tb();
  two_power_addr c;

  initial begin
    c=new();
    c.temp=0;
    c.randomize();
    $display("%0d \n", c.addr);
    c.temp=16'h2;
    for(int i=0; i<10; i++) begin      
      c.randomize();
      c.temp=c.temp<<1;
      $display("%0d \n", c.addr);
    end
  end
endmodule
4

4 Answers

2
votes

You can write your constraint as follow to check whether the randomized value is of 2's power or not.

constraint 2_power {
  (addr != 0) -> (addr & (addr - 1)) == 0;
}
1
votes
constraint c_addr { $onehot0(addr) == 1; }
0
votes

Her is a variant without constrains and classes which works perfectly well in your case.

 bit[3:0] rnd;
 logic address[15:0];

 rnd =  $urandom;
 address = 16'b1 << rnd;

I guess you can come up with a class randomization for rnd if you wish instead of $urandom.

0
votes

Here is one more alternative method to do same. Also I prefer Dave's method more as it is short, power of two can never be 0 so $onehot0 can be replaced by $onehot. But as the question included addr = 0, in that case $onehot0 can be used.

class gen#(parameter width = 8);

    rand bit [width-1:0] addr;
    rand int num;
  
    constraint num_c { num inside {[0:width-1]};}
    constraint solve_order { solve num before addr;}
    constraint pow_2 {  addr == 2**num;}

endclass: gen