Functions in Constraints

class packet;
  rand bit [3:0] start_addr;
  rand bit [3:0] end_addr;
 
  constraint end_addr_c { end_addr == e_addr(start_addr); }
 
  function bit [3:0] e_addr(bit [3:0] s_addr);
    if(s_addr<0)
      e_addr = 0;
    else
        e_addr = s_addr * 2;
  endfunction
endclass
 
module func_constr;
  initial begin
    packet pkt;
    pkt = new();
 
    repeat(3) begin
      pkt.randomize();
      $display("\tstart_addr = %0d end_addr =",pkt.start_addr,pkt.end_addr);
    end
  end
endmodule

output :

start_addr = 9 end_addr = 2
start_addr = 14 end_addr =12
start_addr = 12 end_addr = 8

I am not getting hoe end_addr value is getting calculated

In reply to adityatumsare:

A couple of problems with your code:

s_addr is unsigned—it can never be less than 0.

e_addr is the same bit width as
s_addr
. When you multiply it by 2 (same as shift left by 1), you lose the MSB. Make e_addr one bit wider for this function.

  • You don’t test the return value of randomize() for success. It’s very easy to get a randomization failure when using functions in constraints. If you were to add another constraint on
    end_addr
    , the solver does not backtrack through a user defined function to find the proper inputs.

In reply to adityatumsare:

A function call inside the constraint breaks it into half. What seems to be happening is the inputs to the function call are solved before actually calling the function,then the result of the function is used to solve the rest of the constraint.

Instead of using function , The following constraint code should work :-

constraint end_addr_c {
(start_addr<0) → (e_addr==0);
(start_addr>=0) → (e_addr!=0 && (e_addr==start_addr));
};

In reply to prashantk:


constraint end_addr_c {
  (start_addr<0) -> (end_addr==0); // dummy rule, bit type is unsigned
  // (start_addr>=0) -> (end_addr!=0 && (end_addr==start_addr)); // wrong
  end_addr == (start_addr << 1);
};

In reply to javatea:

Hi javatea,

Can you please explain what is wrong with the second part of the code ?
// (start_addr>=0) → (end_addr!=0 && (end_addr==start_addr));

In reply to prashantk:

this is his requirement:

function bit [3:0] e_addr(bit [3:0] s_addr);
    ...
    e_addr = s_addr * 2; // end_addr == (start_addr << 1);
  endfunction

In reply to javatea:

In reply to prashantk:
this is his requirement:

function bit [3:0] e_addr(bit [3:0] s_addr);
...
e_addr = s_addr * 2; // end_addr == (start_addr << 1);
endfunction

Okay ,this should be like this (start_addr>=0) → (end_addr!=0 && (end_addr==2 * start_addr))
By the way your code will also work fine

In reply to prashantk:

No … that is still wrong.
you should read code more carefully.

  1. how about both 'h0? it’s a valid case. @ function bit [3:0] e_addr(bit [3:0] s_addr);
  2. if you want to use “2*start_addr”, you need to apply static casting (e.g. int’()) to avoid overflow.

end_addr == 2 * start_addr // can’t handle overflow