Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Constraining an entire object in SystemVerilog

I'm trying to constrain an entire object (not just the fields of an object) based on some other object. Here is a stripped down version of my production code:

I have the following class:

class some_class;
  bit[7:0] some_field;
  bit[3:0] some_other_field;


  // this function would do some complex procedural
  // operations on the fields of the object
  function void do_some_op();
    bit[3:0] tmp = some_field[3:0];
    some_field[3:0] = some_other_field;
    some_other_field = some_field[7:4];
    some_field[7:4] = tmp;
  endfunction

  function some_class some_function(bit some_param);
    some_function = new this;
    $display("foo"); // this print here to see that method is executed

    if (some_param)
      some_function.do_some_op();
  endfunction

  function void print();
    $display("some_field = %x", some_field);
    $display("some_other_field = %x", some_other_field);
  endfunction
endclass // some_class

This class contains some integral fields. It also has a method that does some complex procedural on the fields of that class. In the example I've simplified it. I also have another class that returns a new object on which the operation has been performed.

I have another class that operates with some_class instances. As per Dave's input I have made it create the objects first (as randomize() does not create objects).

class some_shuffler;
  rand bit        params[];
  rand some_class objects[];

  constraint size_c {
    params.size() == objects.size() - 1;
    params.size() <= 10;
  };

  constraint shuffle_c {
    // not allowed by standard
    // foreach (params[i])
    //   objects[i+1].some_field == objects[i].some_function(params[i]);

    foreach (params[i])
      objects[i+1].some_field == 
        objects[i].some_function(params[i]).some_field &&
      objects[i+1].some_other_field ==  
        objects[i].some_function(params[i]).some_other_field;
  };

  function new();
    objects = new[10];  // create more objects than needed
    foreach (objects[i])
      objects[i] = new();

    // initialize first object
    objects[0].some_field = 8'hA5;
  endfunction // new

  function void post_randomize();
    foreach (objects[i]) begin
      $display("objects[%0d]:", i);
      objects[i].print();
      $display("");
    end
  endfunction

endclass

This class has two arrays, one of operations performed and one of the intermediate states. There is an initial object. On this one, some_function is performed and it results in the next object.

This is how I wanted to test it:

module top;
  import some_pkg::*;

  initial begin
    static some_shuffler shuffler = new();
    bit rand_ok;
    rand_ok = shuffler.randomize() with {
     params.size() == 1;
    };
    assert (rand_ok);
  end

endmodule

When trying to constrain the objects directly I immediately get a constraint violation. The simulator seems to try to make the 2 handles equal. This is anyway forbidden by the standard and I'm not doing it anymore (though a compile failure would have been nice). I've unraveled the constraints as suggested by Dave and Greg (I think doing some_function().some_field is non-standard, but it compiles in Questa).

Even now, the foo print does not appear on the command line (some_function() is not getting executed). What I see is that objects[1] contains the initial value (all 0s for both fields).

I can't just generate the list of params and then procedurally randomize the objects for each iteration, because I want to be able to constrain the last object to have a certain value - basically giving the constraint solver the start and the end points and let it figure out the way to get there.

like image 704
Tudor Timi Avatar asked Jun 21 '14 09:06

Tudor Timi


Video Answer


1 Answers

Object vs. object constraints are not allowed in SystemVerilog because they are not integral types. See IEEE Std 1800-2012 § 18.3:

  • Constraints can be any SystemVerilog expression with variables and constants of integral type (e.g., bit, reg, logic, integer, enum, packed struct).

You can constrain the integral components of class object if the component is a rand (ex obj[1].value == obj[0].value+1;).

Functions are allowed in constraints, but there limitation. See IEEE Std 1800-2012 § 18.5.12 Functions in constraints for full details. Limitations include:

  • Functions cannot contain output or ref arguments
  • Functions should be automatic and leave no side effects
  • The functions arguments have an implicit priority (ex x<=F(y) infers solve y before x)
  • Circular dependencies will result in an error

Update:

Looks like the only thing truly being randomized is params. The values of some_field and some_other_fieldare calculations. So it makes more sense to move the loop for shuffling into thepost_randomize` function.

constraint size_c {
  params.size() == objects.size() - 1;
  params.size() <= 10;
};

function void postrand_shuffle();
  foreach (params[i])
    objects[i+1] = objects[i].some_function(params[i]);
endfunction

function void post_randomize();
  postrand_shuffle();
  // ... your other post_rand code...
endfunction

SystemVerilog's random constraint solver will work when there is at least one solution. However when the solution space is small and difficult to determine or a long chain, simulator performance drops. For these scenarios it is better move the one-to-one sequential calculations into post_randomize.

like image 67
Greg Avatar answered Oct 23 '22 15:10

Greg