class
vmm_scenario_(
class_name) extends
VMM_SCENARIO;
static
VMM_LOG log;
rand
class_name items[];
class_name using;
virtual function string psdisplay(string prefix = "");
psdisplay = super.psdisplay(prefix);
foreach (this.items[i]) begin
string pfx;
if (this.items[i] == null) continue;
$sformat(pfx, "%s Item[%0d]: ", prefix, i);
psdisplay = {psdisplay, "\n", this.items[i].psdisplay(pfx)};
end
if (this.using != null) begin
psdisplay = {psdisplay, "\n", this.using.psdisplay({prefix, " Using: "})};
end
return psdisplay;
endfunction
constraint
vmm_scenario_valid_(
class_name) {
items.size() == length;
solve length before items.size()
VMM_SOLVE_BEFORE_OPT;
}
function new(
VMM_SCENARIO_NEW_ARGS);
super.new(this.log
VMM_SCENARIO_NEW_CALL);
if (this.log == null) begin
this.log = new({
text, " Scenario"}, "Class");
this.notify.log = this.log;
end
using = null;
endfunction: new
function void allocate_scenario(
class_name using = null);
this.items = new [this.get_max_length()];
foreach (this.items[i]) begin
if (using == null) this.items[i] = new;
else $cast(this.items[i], using.copy());
VMM_OBJECT_SET_PARENT(this.items[i], this)
this.items[i].stream_id = this.stream_id;
this.items[i].scenario_id = this.scenario_id;
this.items[i].data_id = i;
end
endfunction: allocate_scenario
function void fill_scenario(
class_name using = null);
int i;
if (this.items.size() < this.get_max_length()) begin
this.items = new [this.get_max_length()] (this.items);
end
foreach (this.items[i]) begin
if (this.items[i] != null) continue;
if (using == null) this.items[i] = new;
else $cast(this.items[i], using.copy());
VMM_OBJECT_SET_PARENT(this.items[i], this)
this.items[i].stream_id = this.stream_id;
this.items[i].scenario_id = this.scenario_id;
this.items[i].data_id = i;
end
endfunction: fill_scenario
function void pre_randomize();
this.fill_scenario(this.using);
endfunction: pre_randomize
virtual task apply(
channel_name channel,
ref int unsigned n_insts);
int i;
for (i = 0; i < this.length; i++) begin
class_name item;
$cast(item, this.items[i].copy());
`ifndef VMM_GRAB_DISABLED
channel.put(item,,this);
`else
channel.put(item);
`endif
end
n_insts = this.length;
endtask: apply
endclass
class
vmm_inject_item_scenario_(
class_name) extends
vmm_scenario_(
class_name);
function new(
class_name obj
VMM_DATA_NEW_ARGS);
super.new(
VMM_DATA_NEW_CALL);
this.items = new [1];
this.items[0] = obj;
this.length = 1;
this.repeated = 0;
endfunction: new
virtual task apply(
channel_name channel,
ref int unsigned n_insts);
`ifndef VMM_GRAB_DISABLED
channel.put(this.items[0],,this);
`else
channel.put(this.items[0]);
`endif
n_insts = 1;
endtask: apply
endclass
class
vmm_atomic_scenario_(
class_name) extends
vmm_scenario_(
class_name);
int unsigned ATOMIC;
constraint atomic_scenario {
if (scenario_kind == ATOMIC) {
length == 1;
repeated == 0;
}
}
function new(
VMM_DATA_NEW_ARGS);
super.new(
VMM_DATA_NEW_CALL);
this.ATOMIC = this.define_scenario("Atomic", 1);
this.scenario_kind = this.ATOMIC;
this.length = 1;
endfunction: new
virtual function string psdisplay(string prefix = "");
psdisplay = super.psdisplay(prefix);
endfunction:psdisplay
function void pre_randomize();
super.pre_randomize();
endfunction
virtual task apply(
channel_name channel,
ref int unsigned n_insts);
super.apply(channel, n_insts);
endtask: apply
endclass
class
vmm_scenario_election_(
class_name);
int stream_id;
int scenario_id;
int unsigned n_scenarios;
int unsigned last_selected[$];
int unsigned next_in_set;
vmm_scenario_(
class_name) scenario_set[$];
rand int select;
constraint
vmm_scenario_election_valid_(
class_name) {
select >= 0;
select < n_scenarios;
}
constraint round_robin {
select == next_in_set;
}
endclass
typedef class
vmm_scenario_gen_(
class_name);
class
vmm_scenario_gen_callbacks_(
class_name) extends vmm_xactor_callbacks;
virtual task pre_scenario_randomize(
vmm_scenario_gen_(
class_name) gen,
ref
vmm_scenario_(
class_name) scenario);
endtask
virtual task post_scenario_gen(
vmm_scenario_gen_(
class_name) gen,
vmm_scenario_(
class_name) scenario,
ref bit dropped);
endtask
endclass
class
vmm_scenario_gen_(
class_name) extends
VMM_XACTOR;
int unsigned stop_after_n_insts;
int unsigned stop_after_n_scenarios;
typedef enum int {GENERATED,
DONE} symbols_e;
vmm_scenario_election_(
class_name) select_scenario;
vmm_scenario_(
class_name) scenario_set[$];
protected
vmm_scenario_(
class_name) scenario_registry[string];
channel_name out_chan;
protected int scenario_count;
protected int inst_count;
virtual function string psdisplay(string prefix = "");
psdisplay = super.psdisplay(prefix);
$sformat(psdisplay, "%s [stops after #insts %0d>%0d or #scenarios %0d>%0d]",
psdisplay, this.inst_count, this.stop_after_n_insts,
this.scenario_count, this.stop_after_n_scenarios);
$sformat(psdisplay, "%s\n%sOutChan: %s(%s) [level=%0d of %0d]",
psdisplay, prefix, this.out_chan.log.get_name(),
this.out_chan.log.get_instance(), this.out_chan.level(),
this.out_chan.full_level());
foreach (this.scenario_registry[name]) begin
psdisplay = {psdisplay, "\n",
this.scenario_registry[name].psdisplay(prefix)};
end
return psdisplay;
endfunction: psdisplay
function new(string inst,
int stream_id = -1,
channel_name out_chan = null
VMM_XACTOR_NEW_ARGS);
super.new({
text, " Scenario Generator"}, inst, stream_id
VMM_XACTOR_NEW_CALL);
if (out_chan == null) begin
out_chan = new({
text, " Scenario Generator output channel"},
inst);
VMM_OBJECT_SET_PARENT(out_chan, this)
end
this.out_chan = out_chan;
this.out_chan.set_producer(this);
this.log.is_above(this.out_chan.log);
this.scenario_count = 0;
this.inst_count = 0;
this.stop_after_n_insts = 0;
this.stop_after_n_scenarios = 0;
this.select_scenario = new;
begin
vmm_atomic_scenario_(
class_name) sc = new;
VMM_OBJECT_SET_PARENT(sc, this)
this.register_scenario("Atomic", sc);
end
void'(this.notify.configure(GENERATED));
void'(this.notify.configure(DONE, vmm_notify::ON_OFF));
endfunction: new
virtual function void register_scenario(string name,
vmm_scenario_(
class_name) scenario);
if(name == "") begin
vmm_error(this.log,
vmm_sformatf("Invalid '%s' string was passed", name));
return;
end
if(this.scenario_registry.exists(name)) begin
vmm_error(this.log,
vmm_sformatf("%s already has an entry in the scenario registry", name));
return;
end
if(scenario == null) begin
vmm_error(this.log,
vmm_sformatf("scenario passed for %s is a null value", name));
return;
end
this.scenario_registry[name] = scenario;
foreach(this.scenario_set[i]) begin
if(this.scenario_set[i] == scenario)
return;
end
this.scenario_set.push_back(scenario);
endfunction: register_scenario
virtual function bit scenario_exists(string name);
if(name == "") begin
vmm_error(this.log,
vmm_sformatf("Invalid '%s' string was passed", name));
return 0;
end
if(this.scenario_registry.exists(name))
scenario_exists = 1;
else
scenario_exists = 0;
endfunction: scenario_exists
virtual function void replace_scenario(string name,
vmm_scenario_(
class_name) scenario);
if(name == "") begin
vmm_error(this.log,
vmm_sformatf("Invalid '%s' string was passed", name));
return;
end
if(scenario == null) begin
vmm_error(this.log,
vmm_sformatf("scenario passed for %s is a null value", name));
return;
end
if(!this.scenario_registry.exists(name)) begin
vmm_error(this.log,
vmm_sformatf("cannot replace a unregistered %s entry [use register_scenario]", name));
return ;
end
foreach(this.scenario_set[i]) begin
if(this.scenario_set[i] == this.scenario_registry[name]) begin
this.scenario_set.delete(i);
break;
end
end
this.scenario_registry[name] = scenario;
foreach(this.scenario_set[i]) begin
if(this.scenario_set[i] == scenario)
return;
end
this.scenario_set.push_back(scenario);
endfunction: replace_scenario
virtual function void get_all_scenario_names(ref string name[$]);
string s;
if(this.scenario_registry.first(s)) begin
do begin
name.push_back(s);
end while(this.scenario_registry.next(s));
end
if(name.size() == 0) begin
vmm_warning(this.log, "There are no entries in the scenario generator registry");
end
endfunction: get_all_scenario_names
virtual function void get_names_by_scenario(
vmm_scenario_(
class_name) scenario,
ref string name[$]);
string s;
if(scenario == null) begin
vmm_error(this.log,
vmm_sformatf("scenario is a null value"));
return;
end
if(this.scenario_registry.first(s)) begin
do begin
if(this.scenario_registry[s] == scenario)
name.push_back(s);
end while(this.scenario_registry.next(s));
end
if(name.size() == 0) begin
vmm_warning(this.log, "There are no entries in the scenario registry");
end
endfunction: get_names_by_scenario
virtual function string get_scenario_name(
vmm_scenario_(
class_name) scenario);
string s[$];
if(scenario == null) begin
vmm_error(this.log,
vmm_sformatf("scenario is a null value"));
return "";
end
this.get_names_by_scenario(scenario, s);
if(s.size())
get_scenario_name = s[0];
else
get_scenario_name = "";
endfunction: get_scenario_name
virtual function int get_scenario_index(
vmm_scenario_(
class_name) scenario);
get_scenario_index = -1;
foreach(this.scenario_set[i]) begin
if(this.scenario_set[i] == scenario) begin
return (get_scenario_index = i);
end
end
if(get_scenario_index == -1) begin
vmm_warning(this.log,
vmm_sformatf("Cannot find the index for the scenario"));
end
endfunction: get_scenario_index
virtual function bit unregister_scenario(
vmm_scenario_(
class_name) scenario);
string s;
unregister_scenario=0;
if(scenario == null) begin
vmm_error(this.log,
vmm_sformatf("scenario is a null value"));
return 0;
end
if(this.scenario_registry.first(s)) begin
do begin
if(this.scenario_registry[s] == scenario) begin
this.scenario_registry.delete(s);
unregister_scenario=1;
end
end while(this.scenario_registry.next(s));
end
if(unregister_scenario==0) begin
vmm_warning(this.log, "There are no entries in the scenario registry");
end
if(unregister_scenario) begin
foreach(this.scenario_set[i]) begin
if(this.scenario_set[i] == scenario) begin
this.scenario_set.delete(i);
break;
end
end
end
endfunction: unregister_scenario
virtual function
vmm_scenario_(
class_name) unregister_scenario_by_name(string name);
if(name == "") begin
vmm_error(this.log,
vmm_sformatf("Invalid '%s' string was passed", name));
return null;
end
if(!this.scenario_registry.exists(name)) begin
vmm_warning(this.log,
vmm_sformatf("There is no entry for %s in the scenario registry", name));
return null;
end
else begin
unregister_scenario_by_name = this.scenario_registry[name];
foreach(this.scenario_set[i]) begin
if(this.scenario_set[i] == this.scenario_registry[name]) begin
this.scenario_set.delete(i);
break;
end
end
this.scenario_registry.delete(name);
end
endfunction: unregister_scenario_by_name
virtual function
vmm_scenario_(
class_name) get_scenario(string name);
if(name == "") begin
vmm_error(this.log,
vmm_sformatf("Invalid '%s' string was passed", name));
return null;
end
if(!this.scenario_registry.exists(name)) begin
vmm_error(this.log,
vmm_sformatf("%s does not have an entry in the scenario registry", name));
return null;
end
get_scenario = this.scenario_registry[name];
if(get_scenario == null)
vmm_warning(this.log,
vmm_sformatf("%s has a null scenario associated with it in the scenario registry", name));
endfunction: get_scenario
function int unsigned get_n_insts();
get_n_insts = this.inst_count;
endfunction: get_n_insts
function int unsigned get_n_scenarios();
get_n_scenarios = this.scenario_count;
endfunction: get_n_scenarios
virtual task inject_obj(
class_name obj);
vmm_inject_item_scenario_(
class_name) scenario = new(obj);
this.inject(scenario);
endtask: inject_obj
virtual task inject(
vmm_scenario_(
class_name) scenario);
bit drop = 0;
scenario.stream_id = this.stream_id;
scenario.scenario_id = this.scenario_count;
foreach (scenario.items[i]) begin
scenario.items[i].stream_id = scenario.stream_id;
scenario.items[i].scenario_id = scenario.scenario_id;
scenario.items[i].data_id = i;
end
vmm_callback(
vmm_scenario_gen_callbacks_(
class_name),
post_scenario_gen(this, scenario, drop));
if (!drop) begin
this.scenario_count++;
this.notify.indicate(GENERATED, scenario);
if (scenario.repeated > scenario.repeat_thresh) begin
vmm_warning(this.log,
vmm_sformatf("A scenario will be repeated %0d times...",
scenario.repeated));
end
repeat (scenario.repeated + 1) begin
int unsigned n_insts = 0;
scenario.apply(this.out_chan, n_insts);
this.inst_count += n_insts;
end
end
endtask: inject
virtual function void reset_xactor(vmm_xactor::reset_e rst_typ = SOFT_RST);
super.reset_xactor(rst_typ);
this.scenario_count = 0;
this.inst_count = 0;
this.out_chan.flush();
vmm_delQ(this.select_scenario.last_selected);
if (rst_typ >= FIRM_RST) begin
this.notify.reset( , vmm_notify::HARD);
end
if (rst_typ >= HARD_RST) begin
vmm_atomic_scenario_(
class_name) sc = new;
VMM_OBJECT_SET_PARENT(sc, this)
this.stop_after_n_insts = 0;
this.stop_after_n_scenarios = 0;
this.select_scenario = new;
this.scenario_set.push_back(sc);
end
endfunction: reset_xactor
virtual protected task main();
vmm_scenario_(
class_name) the_scenario;
fork
super.main();
join_none
if(this.scenario_set.size() == 0)
return;
while ((this.stop_after_n_insts <= 0
|| this.inst_count < this.stop_after_n_insts)
&& (this.stop_after_n_scenarios <= 0
|| this.scenario_count < this.stop_after_n_scenarios)) begin
this.wait_if_stopped();
this.select_scenario.stream_id = this.stream_id;
this.select_scenario.scenario_id = this.scenario_count;
this.select_scenario.n_scenarios = this.scenario_set.size();
this.select_scenario.scenario_set = this.scenario_set;
if (this.select_scenario.last_selected.size() == 0)
this.select_scenario.next_in_set = 0;
else
this.select_scenario.next_in_set = ((this.select_scenario.last_selected[$] + 1) % this.scenario_set.size());
if (!this.select_scenario.randomize()) begin
vmm_fatal(this.log, "Cannot select scenario descriptor");
continue;
end
if (this.select_scenario.select < 0 ||
this.select_scenario.select >= this.scenario_set.size()) begin
vmm_fatal(this.log,
vmm_sformatf("Select scenario #%0d is not within available set (0-%0d)",
this.select_scenario.select,
this.scenario_set.size()-1));
continue;
end
this.select_scenario.last_selected.push_back(this.select_scenario.select);
while (this.select_scenario.last_selected.size() > 10) begin
void'(this.select_scenario.last_selected.pop_front());
end
the_scenario = this.scenario_set[this.select_scenario.select];
if (the_scenario == null) begin
vmm_fatal(this.log,
vmm_sformatf("Selected scenario #%0d does not exist",
this.select_scenario.select));
continue;
end
the_scenario.stream_id = this.stream_id;
the_scenario.scenario_id = this.scenario_count;
foreach (the_scenario.items[i]) begin
if (the_scenario.items[i] == null) continue;
the_scenario.items[i].stream_id = the_scenario.stream_id;
the_scenario.items[i].scenario_id = the_scenario.scenario_id;
the_scenario.items[i].data_id = i;
end
vmm_callback(
vmm_scenario_gen_callbacks_(
class_name),
pre_scenario_randomize(this, the_scenario));
if (the_scenario == null) continue;
if (!the_scenario.randomize()) begin
vmm_fatal(this.log, $psprintf("Cannot randomize scenario descriptor #%0d",
this.select_scenario.select));
continue;
end
this.inject(the_scenario);
end
this.notify.indicate(DONE);
this.notify.indicate(XACTOR_STOPPED);
this.notify.indicate(XACTOR_IDLE);
this.notify.reset(XACTOR_BUSY);
this.scenario_count++;
endtask: main
endclass