Object handles and randomization

In reply to Bahaa Osman:

Another approach which works in one step could be the following:


class txn;
  rand car cars[];

  local rand toyotas[];
  local rand hondas[];
  local rand fords[];

  local const int unsigned MAX_NUM_CARS = 10;


  constraint legal_num_cars {
    cars.size() <= MAX_NUM_CARS;
  }

  function void pre_randomize();
    // randomization doesn't create objects, but it can throw them away
    // create more cars than you need so randomization can throw away excess
    cars = new[MAX_NUM_CARS];
    foreach (cars[i])
      cars[i] = new();

    toyotas = new[MAX_NUM_CARS];
    foreach (toyotas[i])
      toyotas[i] = new();

    // same for hondas and fords
  endfunction

  function void post_randomize();
    foreach (cars[i])
      case (cars[i].brand)
        TOYOTA: cars[i] = toyotas[i];
        // same for hondas and fords
      endcase
  endfunction
endclass


class test;
  function void run();
    txn t = new();
    t.randomize() with {
      cars.size() == 5;
      cars[1].brand == TOYOTA;
      cars[2].brand == HONDA;
    };
  endfunction
endclass

While this might be more natural to constrain, it’s a lot more code. You create more objects than you need, just so you can have enough for randomize to work with.

Both approaches (the two step and this one) suffer from the problem that you need to make modifications to the ‘txn’ class code when you declare a new brand. The two step is clunkier to randomize, but more efficient memory-wise. The second one (gotta find a catchy name for it) is more natural, but requires much more code and will for sure be slower. It’s also going to require a lot more boilerplate code to keep objects in sync if you have any common properties defined in the ‘car’ class. For example, if you decide to add a ‘year_of_manufacture’ field to ‘car’ and want to be able to constrain that irrespective of the car brand, you’d need constraints to keep the ‘cars’ array in sync with the ‘toyotas’, ‘hondas’ and ‘fords’:


class txn;

  constraint keep_common_vars_in_sync {
    foreach cars[i] {
      toyotas[i].year_of_manufacture == cars[i].year_of_manufacture;
      hondas[i].year_of_manufacture == cars[i].year_of_manufacture;
      // ...
    }
  }

endclass


class test;
  function void run();
    txn t = new();
    t.randomize() with {
      cars.size() == 5;
      cars[0].brand == TOYOTA;
      cars[0].year_of_manufacture == 2017;
    };
  endfunction
endclass

Things are even more complicated if you want more funky constraints like “if the car at index i was built in 2017 then it has to be a Toyota and the model should be a Prius” (here, I’m assuming the model is a variable that’s defined in the ‘toyota’ class).

Note: I haven’t tested the code, but I think it should work.