System Verilog – Failed to Randomize Dynamic Array Using Foreach in Constraint

integrated-circuitrandomsimulationsystem-verilogverification

In the following code, I force a random variable 'ResBlks' with a value (setting its rand_mode to 0), then attempt to randomize the transaction:

`include "uvm_macros.svh"

package mytest;
import uvm_pkg::*;

typedef enum logic {Type2=0, Sorted=1} PhyRBAlloc_t; // RBs allocation type

class Txn extends uvm_sequence_item;

  rand bit [6:0] ResBlks; // Number of resource blocks (NRB)
  rand PhyRBAlloc_t PhyRBAllocType; // Physical RB allocation type
  rand integer PhyRB[2][]; // Physical RB mapping

  // Array of unique values
  constraint ArrSize {
    PhyRB[0].size() > 0;
    PhyRB[0].size() <= ResBlks;
    PhyRB[1].size() == PhyRB[0].size();
  }
  constraint vals {
    foreach(PhyRB[0][i]) PhyRB[0][i] < ResBlks;
    if(PhyRBAllocType == Type2) {
      foreach(PhyRB[1][i]) PhyRB[1][i] < ResBlks;
    }
    unique { PhyRB[0] };
    unique { PhyRB[1] } ;
  }

  constraint ResBlksConstraint {
    ResBlks inside {6,15,25,50,75,100};
  }

  function void post_randomize;
    if(PhyRBAllocType == Sorted) begin
      PhyRB[0].sort();
      PhyRB[1] = PhyRB[0];
    end
  endfunction

  function new(string name="Txn");
    super.new(name);
  endfunction

  `uvm_object_utils_begin(Txn)
    `uvm_field_int(ResBlks, UVM_DEFAULT)
    `uvm_field_array_int(PhyRB[0], UVM_DEFAULT)
    `uvm_field_array_int(PhyRB[1], UVM_DEFAULT)
  `uvm_object_utils_end

endclass

class Seq extends uvm_sequence #(Txn);
  `uvm_object_utils(Seq)

  function new(string name="Seq");
    super.new(name);
  endfunction

  task body();

      req = Txn::type_id::create("req");
      start_item(req);

      req.ResBlks = 50;
      req.ResBlks.rand_mode(0);
      if(!req.randomize())
        `uvm_error("RAND", "txn rand failed")
      finish_item(req);
  endtask: body
endclass: Seq

typedef uvm_sequencer #(Txn) Sqr;

class Drv extends uvm_driver#(Txn);
  `uvm_component_utils(Drv)
  virtual MyIf vif;
  Txn txn;

  function new(string name="Drv", uvm_component parent=null);
    super.new(name, parent);
  endfunction

  function void build_phase(uvm_phase phase);
    if(!uvm_config_db #(virtual MyIf)::get(this, "", "vif", vif))
      `uvm_fatal("NO VIF", "No virtual interface");
  endfunction: build_phase

  task run_phase(uvm_phase phase);

    vif.nRst = 0;
    vif.Init = 0;
    #100 @(negedge vif.Clk);
    vif.nRst = 1;


    forever begin
      seq_item_port.get_next_item(txn);
      // drive txn

        @vif.cb
            vif.cb.ResBlks <= txn.ResBlks;
            vif.cb.Init <= 1;
        @vif.cb vif.cb.Init <= 0;

     @vif.cb GenRBAlloc;

      seq_item_port.item_done();
    end

  endtask: run_phase

  task GenRBAlloc;
    integer i;

    if(!txn.randomize(PhyRBAllocType))
      `uvm_error("RAND", "PhyRBAllocType rand failed")
    if(!txn.randomize(PhyRB))
      `uvm_error("RAND", "PhyRB rand failed")

    `uvm_info("SFRM", $sformatf("UsedRBNum: %0d", txn.PhyRB[0].size()), UVM_MEDIUM)
    `uvm_info("SFRM", $sformatf("RB allocation: %s", txn.PhyRBAllocType.name()), UVM_MEDIUM)
    `uvm_info("SFRM", $sformatf("PhyRB[0]: %0p", txn.PhyRB[0]), UVM_MEDIUM)
    `uvm_info("SFRM", $sformatf("PhyRB[1]: %0p", txn.PhyRB[1]), UVM_MEDIUM)

  endtask: GenRBAlloc

endclass: Drv

class Agent  extends uvm_agent;
  `uvm_component_utils(Agent)
  Sqr sqr;
  Drv drv;

  function new(string name="Agent", uvm_component parent=null);
    super.new(name, parent);
  endfunction

  function void build_phase(uvm_phase phase);
    if(get_is_active() == UVM_ACTIVE) begin
      sqr = Sqr::type_id::create("sqr", this);
      drv = Drv::type_id::create("drv", this);
    end
  endfunction: build_phase

  function void connect_phase(uvm_phase phase);
    if(get_is_active() == UVM_ACTIVE)
      drv.seq_item_port.connect(sqr.seq_item_export);
  endfunction: connect_phase

endclass: Agent

class Env  extends uvm_env;
  `uvm_component_utils(Env)
  Agent agent;

  function new(string name="Env", uvm_component parent=null);
    super.new(name, parent);
  endfunction

  function void build_phase(uvm_phase phase);
    agent = Agent::type_id::create("agent", this);
  endfunction: build_phase

endclass: Env

class ParamTest extends uvm_test;
  `uvm_component_utils(ParamTest)
  Env env;

  function new(string name="ParamTest", uvm_component parent=null);
    super.new(name, parent);
  endfunction

  function void build_phase(uvm_phase phase);
    env = Env::type_id::create("env", this);
  endfunction: build_phase

  task run_phase(uvm_phase phase);
    Seq seq;
    phase.raise_objection(this);
    seq = Seq::type_id::create("seq");
    seq.start(env.agent.sqr);
    phase.drop_objection(this);
  endtask: run_phase

endclass: ParamTest

endpackage

interface MyIf (
  // Clock & reset:
  input Clk
);

parameter CQ = 0;
// Inputs
logic nRst;
logic Init; // Re-initialize the block
logic [6:0] ResBlks; // Number of resource blocks (NRB)
logic [6:0] UsedRBNum;// Length of type 2 distributed bitmap.
logic [6:0] PhyRB0;// Type 2-Distributed physical RB mapping for even slots.
logic [6:0] PhyRB1;// Type 2-Distributed physical RB mapping for odd slots.

clocking cb @(posedge Clk);
default input #1step output #CQ;
output negedge nRst;
// Inputs
output Init; // Re-initialize the block
output UsedRBNum;// Length of type 2 distributed bitmap.
output PhyRB0;// Type 2-Distributed physical RB mapping for even slots.
output PhyRB1;// Type 2-Distributed physical RB mapping for odd slots.
output ResBlks;

endclocking

endinterface

module tb;
  import mytest::*;
  import uvm_pkg::*;
  parameter CLKPRD = 8; // Clock period
  parameter CQ = 0;
  reg Clk;

MyIf  uMyIf (
  // Clock & reset:
  .Clk(Clk)
);

initial begin
  Clk <= 0;
  forever #(CLKPRD/2) Clk = ~Clk;
end

initial begin
  uvm_config_db #(virtual MyIf)::set(null, "", "vif", uMyIf);
  run_test("ParamTest");
end

endmodule

Yet the randomization fails with this error:

** Failure: (vsim-7067) t2.sv(23): Index out of bounds (PhyRB[1][9]) for unpacked array of packed elements in constraint.

I tried to run QuestaSim with -solvedebug option, so it reports the following:

# Begin RandSet 1
# Random Variables:
#   bit signed [31:0] PhyRB[1].size
#   bit signed [31:0] PhyRB[0].size
# Constraints:
#   t2.sv(16): ArrSize { (PhyRB[0].size > 0); }
#   t2.sv(17): ArrSize { (PhyRB[0].size <= ResBlks); }
#   t2.sv(18): ArrSize { (PhyRB[1].size == PhyRB[0].size); }
#   t2.sv(12): (PhyRB[1].size >= 0);
#   t2.sv(12): (PhyRB[0].size >= 0);
# * Solving RandSet 1 with ACT engine
# Solved: PhyRB[0].size = 9
# Solved: PhyRB[1].size = 9
# End RandSet 1

I don't understand, why is the foreach statement attempting to access PhyRB[1][9], although PhyRB[1].size = 9 ?!

I am running QuestaSim 10.4c simulation tool.

Best Answer

The problem is in the foreach syntax, it should be:

foreach PhyRB[,i] PhyRB[0][i] < ResBlks;