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: