Why is the constraint solver failing in the below code?

Can anyone help me why the constraint solver fails? I am assuming it is legal to constraint only certain members of the class and keep rest of them untouched.

module rev_packet;

  
  typedef bit [7:0] ubyte;
  typedef enum {BROADCAST, LOCAL, WAN} addr_kind_e;
  
  class Packet;
    // HEADER
    rand ubyte control; // payload byte count 0:127, or
    // control msg type 128:255 (no payload)
    rand ubyte addr[4]; // destination IPv4 address
    // PAYLOAD
    rand ubyte payload[];  // contains 'length' bytes
    // CONTROL INFORMATION FOR TESTBENCH USE - not part of the packet
    rand addr_kind_e addr_kind;
    rand bit         is_ctrl_msg;
    constraint c_spread {
      addr_kind dist {BROADCAST:=1, LOCAL:=1, WAN:=1};
      is_ctrl_msg dist {0:=1, 1:=1};
    }
    constraint c_payload_length {
      if (is_ctrl_msg) {
        payload.size() == 0; control >= 128;
      } else {
        payload.size() == control; control <= 127;
      }
    }
    constraint c_address_kind {
      (addr_kind==BROADCAST) == (addr[0] == 255);
      (addr_kind==LOCAL) == 
        (   addr[0]==192 && addr[1]==168
         || addr[0]==10  && addr[1]==0  );
    }
  endclass
        
        initial begin
          bit ok;
          Packet P;
          P = new();
          repeat (10) begin
            P.randomize(payload);
            $display ("The value of address is %p",P.addr);
            $display ("The value of control is %p",P.control);
            $display ("The value of addr_kind is %s",P.addr_kind);
            $display ("The value of controlmsg is %p",P.is_ctrl_msg);
            $display ("The value of address is %p",P.payload);
          end
        end
      
      endmodule

In reply to rag123:

P.randomize(payload);

This only randomizes payload, but all other class variables are still tested against their constraints. What is it you are trying to accomplish?

As @warnerrs mentioned, you are randomizing only payload variable but the constranit solver will check the validity of all the constraint variables. We can think of it as if the Solver is generating current values for all random variables not passed to randomize(). So, before initially randomizing a single variable, it tries to randomize the entire cluster first.

During randomization, the validity of c_address_kind fails. This is because constraint solver is not allowed to change values of addr_kind (BROADCAST) and addr (0).

We have a couple of workarounds here.

  1. Make constraint_mode off for all violating constraints. In this case it is c_address_kind.
P.c_address_kind.constraint_mode(0);
P.randomize(payload);
  1. Randomize entire Packet class.
P.randomize();
  1. Use a local payload variable and use std::randomize to generate random values.
// In top module
bit [7:0] payload[];
std::randomize(payload) with {payload.size() == P.control;};

There can be other options also such as applying glue logic around randomization and in constraints. This DVCON paper explains the problem that you are facing.

In reply to sharvil111:

Thanks got it !

In reply to sharvil111:

As @warnerrs mentioned, you are randomizing only payload variable but the constranit solver will check the validity of all the constraint variables. We can think of it as if the Solver is generating current values for all random variables not passed to randomize(). So, before initially randomizing a single variable, it tries to randomize the entire cluster first.
During randomization, the validity of c_address_kind fails. This is because constraint solver is not allowed to change values of addr_kind (BROADCAST) and addr (0).
We have a couple of workarounds here.

  1. Make constraint_mode off for all violating constraints. In this case it is c_address_kind.
P.c_address_kind.constraint_mode(0);
P.randomize(payload);
  1. Randomize entire Packet class.
P.randomize();
  1. Use a local payload variable and use std::randomize to generate random values.
// In top module
bit [7:0] payload[];
std::randomize(payload) with {payload.size() == P.control;};

There can be other options also such as applying glue logic around randomization and in constraints. This DVCON paper explains the problem that you are facing.

Hi Shravil111,
Could you explain why the constraint solver is not allowed to change values of addr_kind (BROADCAST) and addr (0).?
In general what is the real use case of randomizing only single variable knowing that the other variables also get randomized? I mean how is P.randomize is different from P.randomize(payload)?

Thanks,
Manju

In reply to mbhat:

The solver can only change the value of active random variables. Non-active random variables are same as state variables.

We have shown you two different ways of selecting which variables you want to randomize. Sometimes it’s easier to de-activate a random variable and assign it to a constant
myvar = constant;
instead of adding a constraint
{myvar == constant;}
that fixes the value.