00001 // 00002 // ------------------------------------------------------------- 00003 // Copyright 2004-2008 Synopsys, Inc. 00004 // All Rights Reserved Worldwide 00005 // 00006 // Licensed under the Apache License, Version 2.0 (the 00007 // "License"); you may not use this file except in 00008 // compliance with the License. You may obtain a copy of 00009 // the License at 00010 // 00011 // http://www.apache.org/licenses/LICENSE-2.0 00012 // 00013 // Unless required by applicable law or agreed to in 00014 // writing, software distributed under the License is 00015 // distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 00016 // CONDITIONS OF ANY KIND, either express or implied. See 00017 // the License for the specific language governing 00018 // permissions and limitations under the License. 00019 // ------------------------------------------------------------- 00020 // 00021 00022 `ifdef VCS 00023 `ifndef VMM_SOLVE_BEFORE_OPT 00024 `define VMM_SOLVE_BEFORE_OPT hard 00025 `endif 00026 `endif 00027 `ifndef VMM_SOLVE_BEFORE_OPT 00028 `define VMM_SOLVE_BEFORE_OPT 00029 `endif 00030 00031 `ifdef VCS2006_06 00032 // Work-around for NYI feature in VCS2006.06 00033 // *NOT* IEEE compliant :-( 00034 `define vmm_delQ(_q) _q.delete() 00035 `else 00036 // Works in VCS2008.03 00037 `define vmm_delQ(_q) _q = '{} 00038 `endif 00039 00040 `define vmm_scenario_(class) class``_scenario 00041 `define vmm_scenario_valid_(class) class``_scenario_valid 00042 `define vmm_inject_item_scenario_(class) class``_inject_item_scenario 00043 `define vmm_atomic_scenario_(class) class``_atomic_scenario 00044 `define vmm_scenario_election_(class) class``_scenario_election 00045 `define vmm_scenario_election_valid_(class) class``_scenario_election_valid 00046 `define vmm_scenario_gen_(class) class``_scenario_gen 00047 `define vmm_scenario_gen_callbacks_(class) class``_scenario_gen_callbacks 00048 00049 `define vmm_scenario_gen(class_name, text) \ 00050 `vmm_scenario_gen_using(class_name, class_name``_channel, text) 00051 00052 `define vmm_scenario_gen_using(class_name, channel_name, text) \ 00053 \ 00054 class `vmm_scenario_(class_name) extends `VMM_DATA; \ 00055 \ 00056 static vmm_log log; \ 00057 \ 00058 local int next_scenario_kind = 0; \ 00059 local int max_length = 0; \ 00060 local string scenario_names[*]; \ 00061 \ 00062 int stream_id; \ 00063 int scenario_id; \ 00064 \ 00065 rand int unsigned scenario_kind; \ 00066 rand int unsigned length; \ 00067 rand class_name items[]; \ 00068 class_name using; \ 00069 rand int unsigned repeated = 0; \ 00070 static int unsigned repeat_thresh = 100; \ 00071 \ 00072 constraint `vmm_scenario_valid_(class_name) { \ 00073 scenario_kind >= 0; \ 00074 scenario_kind < next_scenario_kind; \ 00075 \ 00076 length >= 0; \ 00077 length <= max_length; \ 00078 \ 00079 items.size() == length; \ 00080 \ 00081 repeated >= 0; \ 00082 \ 00083 solve scenario_kind before length `VMM_SOLVE_BEFORE_OPT; \ 00084 solve length before items.size() `VMM_SOLVE_BEFORE_OPT; \ 00085 } \ 00086 \ 00087 constraint repetition { \ 00088 repeated == 0; \ 00089 } \ 00090 \ 00091 function new(`VMM_DATA_NEW_ARGS); \ 00092 super.new(this.log `VMM_DATA_NEW_CALL); \ 00093 if (this.log == null) begin \ 00094 this.log = new({text, " Scenario"}, "Class"); \ 00095 this.notify.log = this.log; \ 00096 end \ 00097 \ 00098 using = null; \ 00099 endfunction: new \ 00100 \ 00101 virtual function void display(string prefix = ""); \ 00102 $display(this.psdisplay(prefix)); \ 00103 endfunction: display \ 00104 \ 00105 virtual function string psdisplay(string prefix = ""); \ 00106 int i; \ 00107 \ 00108 $sformat(psdisplay, "%sScenario \"%s\": kind=%0d, length=%0d (max=%0d), repeated=%0d\n", \ 00109 prefix, this.scenario_name(this.scenario_kind), this.scenario_kind, this.length, this.max_length, \ 00110 this.repeated); \ 00111 foreach (this.items[i]) begin \ 00112 psdisplay = {psdisplay, this.items[i].psdisplay(`vmm_sformatf("%s Item #%0d: ", prefix, i))}; \ 00113 end \ 00114 endfunction: psdisplay \ 00115 \ 00116 function int unsigned define_scenario(string name, \ 00117 int unsigned max_len); \ 00118 define_scenario = this.next_scenario_kind++; \ 00119 this.scenario_names[define_scenario] = name; \ 00120 \ 00121 if (max_len > this.max_length) this.max_length = max_len; \ 00122 endfunction: define_scenario \ 00123 \ 00124 function void redefine_scenario(int unsigned scenario_kind, \ 00125 string name, \ 00126 int unsigned max_len); \ 00127 this.scenario_names[scenario_kind] = name; \ 00128 \ 00129 if (max_len > this.max_length) this.max_length = max_len; \ 00130 endfunction: redefine_scenario \ 00131 \ 00132 function string scenario_name(int unsigned scenario_kind); \ 00133 if (!this.scenario_names.exists(scenario_kind)) begin \ 00134 `vmm_error(this.log, `vmm_sformatf("Cannot find scenario name: undefined scenario kind %0d", \ 00135 scenario_kind)); \ 00136 return "?"; \ 00137 end \ 00138 \ 00139 scenario_name = this.scenario_names[scenario_kind]; \ 00140 endfunction: scenario_name \ 00141 \ 00142 function void allocate_scenario(class_name using = null); \ 00143 this.items = new [this.max_length]; \ 00144 foreach (this.items[i]) begin \ 00145 if (using == null) this.items[i] = new; \ 00146 else $cast(this.items[i], using.copy()); \ 00147 \ 00148 this.items[i].stream_id = this.stream_id; \ 00149 this.items[i].scenario_id = this.scenario_id; \ 00150 this.items[i].data_id = i; \ 00151 end \ 00152 endfunction: allocate_scenario \ 00153 \ 00154 function void fill_scenario(class_name using = null); \ 00155 int i; \ 00156 \ 00157 if (this.items.size() < this.max_length) begin \ 00158 this.items = new [this.max_length] (this.items); \ 00159 end \ 00160 foreach (this.items[i]) begin \ 00161 if (this.items[i] != null) continue; \ 00162 \ 00163 if (using == null) this.items[i] = new; \ 00164 else $cast(this.items[i], using.copy()); \ 00165 \ 00166 this.items[i].stream_id = this.stream_id; \ 00167 this.items[i].scenario_id = this.scenario_id; \ 00168 this.items[i].data_id = i; \ 00169 end \ 00170 endfunction: fill_scenario \ 00171 \ 00172 function void pre_randomize(); \ 00173 this.fill_scenario(this.using); \ 00174 endfunction: pre_randomize \ 00175 \ 00176 virtual task apply(channel_name channel, \ 00177 ref int unsigned n_insts); \ 00178 int i; \ 00179 \ 00180 for (i = 0; i < this.length; i++) begin \ 00181 class_name item; \ 00182 $cast(item, this.items[i].copy()); \ 00183 channel.put(item); \ 00184 end \ 00185 \ 00186 n_insts = this.length; \ 00187 endtask: apply \ 00188 endclass \ 00189 \ 00190 \ 00191 class `vmm_inject_item_scenario_(class_name) extends `vmm_scenario_(class_name); \ 00192 \ 00193 function new(class_name obj `VMM_DATA_NEW_ARGS); \ 00194 super.new(`VMM_DATA_NEW_CALL); \ 00195 \ 00196 this.items = new [1]; \ 00197 this.items[0] = obj; \ 00198 this.length = 1; \ 00199 this.repeated = 0; \ 00200 endfunction: new \ 00201 \ 00202 virtual task apply(channel_name channel, \ 00203 ref int unsigned n_insts); \ 00204 channel.put(this.items[0]); \ 00205 n_insts = 1; \ 00206 endtask: apply \ 00207 \ 00208 endclass \ 00209 \ 00210 \ 00211 class `vmm_atomic_scenario_(class_name) extends `vmm_scenario_(class_name); \ 00212 \ 00213 int unsigned ATOMIC; \ 00214 \ 00215 constraint atomic_scenario { \ 00216 if (scenario_kind == ATOMIC) { \ 00217 length == 1; \ 00218 repeated == 0; \ 00219 } \ 00220 } \ 00221 \ 00222 function new(`VMM_DATA_NEW_ARGS); \ 00223 super.new(`VMM_DATA_NEW_CALL); \ 00224 \ 00225 this.ATOMIC = this.define_scenario("Atomic", 1); \ 00226 \ 00227 this.scenario_kind = this.ATOMIC; \ 00228 this.length = 1; \ 00229 endfunction: new \ 00230 \ 00231 virtual function string psdisplay(string prefix = ""); \ 00232 psdisplay = super.psdisplay(prefix); \ 00233 endfunction:psdisplay \ 00234 \ 00235 function void pre_randomize(); \ 00236 super.pre_randomize(); \ 00237 endfunction \ 00238 \ 00239 virtual task apply(channel_name channel, \ 00240 ref int unsigned n_insts); \ 00241 super.apply(channel, n_insts); \ 00242 endtask: apply \ 00243 \ 00244 endclass \ 00245 \ 00246 \ 00247 class `vmm_scenario_election_(class_name); \ 00248 int stream_id; \ 00249 int scenario_id; \ 00250 int unsigned n_scenarios; \ 00251 int unsigned last_selected[$]; \ 00252 int unsigned next_in_set; \ 00253 \ 00254 `vmm_scenario_(class_name) scenario_set[$]; \ 00255 \ 00256 rand int select; \ 00257 \ 00258 constraint `vmm_scenario_election_valid_(class_name) { \ 00259 select >= 0; \ 00260 select < n_scenarios; \ 00261 } \ 00262 \ 00263 constraint round_robin { \ 00264 select == next_in_set; \ 00265 } \ 00266 \ 00267 endclass \ 00268 \ 00269 typedef class `vmm_scenario_gen_(class_name); \ 00270 \ 00271 class `vmm_scenario_gen_callbacks_(class_name) extends vmm_xactor_callbacks; \ 00272 virtual task pre_scenario_randomize(`vmm_scenario_gen_(class_name) gen, \ 00273 ref `vmm_scenario_(class_name) scenario); \ 00274 endtask \ 00275 \ 00276 virtual task post_scenario_gen(`vmm_scenario_gen_(class_name) gen, \ 00277 `vmm_scenario_(class_name) scenario, \ 00278 ref bit dropped); \ 00279 endtask \ 00280 endclass \ 00281 \ 00282 \ 00283 class `vmm_scenario_gen_(class_name) extends `VMM_XACTOR; \ 00284 \ 00285 int unsigned stop_after_n_insts; \ 00286 int unsigned stop_after_n_scenarios; \ 00287 \ 00288 typedef enum int {GENERATED, \ 00289 DONE} symbols_e; \ 00290 \ 00291 `vmm_scenario_election_(class_name) select_scenario; \ 00292 \ 00293 `vmm_scenario_(class_name) scenario_set[$]; \ 00294 \ 00295 channel_name out_chan; \ 00296 \ 00297 protected int scenario_count; \ 00298 protected int inst_count; \ 00299 \ 00300 function new(string inst, \ 00301 int stream_id = -1, \ 00302 channel_name out_chan = null \ 00303 `VMM_XACTOR_NEW_ARGS); \ 00304 super.new({text, " Scenario Generator"}, inst, stream_id \ 00305 `VMM_XACTOR_NEW_CALL); \ 00306 \ 00307 if (out_chan == null) begin \ 00308 out_chan = new({text, " Scenario Generator output channel"}, \ 00309 inst); \ 00310 end \ 00311 this.out_chan = out_chan; \ 00312 this.log.is_above(this.out_chan.log); \ 00313 \ 00314 this.scenario_count = 0; \ 00315 this.inst_count = 0; \ 00316 this.stop_after_n_insts = 0; \ 00317 this.stop_after_n_scenarios = 0; \ 00318 \ 00319 this.select_scenario = new; \ 00320 begin \ 00321 `vmm_atomic_scenario_(class_name) sc = new; \ 00322 this.scenario_set.push_back(sc); \ 00323 end \ 00324 \ 00325 this.notify.configure(GENERATED); \ 00326 this.notify.configure(DONE, vmm_notify::ON_OFF); \ 00327 endfunction: new \ 00328 \ 00329 function int unsigned get_n_insts(); \ 00330 get_n_insts = this.inst_count; \ 00331 endfunction: get_n_insts \ 00332 \ 00333 function int unsigned get_n_scenarios(); \ 00334 get_n_scenarios = this.scenario_count; \ 00335 endfunction: get_n_scenarios \ 00336 \ 00337 virtual task inject_obj(class_name obj); \ 00338 `vmm_inject_item_scenario_(class_name) scenario = new(obj); \ 00339 this.inject(scenario); \ 00340 endtask: inject_obj \ 00341 \ 00342 virtual task inject(`vmm_scenario_(class_name) scenario); \ 00343 bit drop = 0; \ 00344 \ 00345 scenario.stream_id = this.stream_id; \ 00346 scenario.scenario_id = this.scenario_count; \ 00347 foreach (scenario.items[i]) begin \ 00348 scenario.items[i].stream_id = scenario.stream_id; \ 00349 scenario.items[i].scenario_id = scenario.scenario_id; \ 00350 scenario.items[i].data_id = i; \ 00351 end \ 00352 \ 00353 `vmm_callback(`vmm_scenario_gen_callbacks_(class_name), \ 00354 post_scenario_gen(this, scenario, drop)); \ 00355 \ 00356 if (!drop) begin \ 00357 this.scenario_count++; \ 00358 this.notify.indicate(GENERATED, scenario); \ 00359 \ 00360 if (scenario.repeated > scenario.repeat_thresh) begin \ 00361 `vmm_warning(this.log, `vmm_sformatf("A scenario will be repeated %0d times...", \ 00362 scenario.repeated)); \ 00363 end \ 00364 repeat (scenario.repeated + 1) begin \ 00365 int unsigned n_insts = 0; \ 00366 scenario.apply(this.out_chan, n_insts); \ 00367 this.inst_count += n_insts; \ 00368 end \ 00369 end \ 00370 endtask: inject \ 00371 \ 00372 virtual function void reset_xactor(reset_e rst_typ = SOFT_RST); \ 00373 super.reset_xactor(rst_typ); \ 00374 this.scenario_count = 0; \ 00375 this.inst_count = 0; \ 00376 this.out_chan.flush(); \ 00377 `vmm_delQ(this.select_scenario.last_selected); \ 00378 \ 00379 if (rst_typ >= FIRM_RST) begin \ 00380 this.notify.reset( , vmm_notify::HARD); \ 00381 end \ 00382 \ 00383 if (rst_typ >= HARD_RST) begin \ 00384 `vmm_atomic_scenario_(class_name) sc = new; \ 00385 \ 00386 this.stop_after_n_insts = 0; \ 00387 this.stop_after_n_scenarios = 0; \ 00388 this.select_scenario = new; \ 00389 this.scenario_set.push_back(sc); \ 00390 end \ 00391 \ 00392 endfunction: reset_xactor \ 00393 \ 00394 virtual protected task main(); \ 00395 `vmm_scenario_(class_name) the_scenario; \ 00396 \ 00397 fork \ 00398 super.main(); \ 00399 join_none \ 00400 \ 00401 while ((this.stop_after_n_insts <= 0 \ 00402 || this.inst_count < this.stop_after_n_insts) \ 00403 && (this.stop_after_n_scenarios <= 0 \ 00404 || this.scenario_count < this.stop_after_n_scenarios)) begin \ 00405 \ 00406 this.wait_if_stopped(); \ 00407 \ 00408 this.select_scenario.stream_id = this.stream_id; \ 00409 this.select_scenario.scenario_id = this.scenario_count; \ 00410 this.select_scenario.n_scenarios = this.scenario_set.size(); \ 00411 this.select_scenario.scenario_set = this.scenario_set; \ 00412 if (this.select_scenario.last_selected.size() == 0) \ 00413 this.select_scenario.next_in_set = 0; \ 00414 else \ 00415 this.select_scenario.next_in_set = ((this.select_scenario.last_selected[$] + 1) % this.scenario_set.size()); \ 00416 \ 00417 if (!this.select_scenario.randomize()) begin \ 00418 `vmm_fatal(this.log, "Cannot select scenario descriptor"); \ 00419 continue; \ 00420 end \ 00421 \ 00422 if (this.select_scenario.select < 0 || \ 00423 this.select_scenario.select >= this.scenario_set.size()) begin \ 00424 `vmm_fatal(this.log, `vmm_sformatf("Select scenario #%0d is not within available set (0-%0d)", \ 00425 this.select_scenario.select, \ 00426 this.scenario_set.size()-1)); \ 00427 continue; \ 00428 end \ 00429 \ 00430 this.select_scenario.last_selected.push_back(this.select_scenario.select); \ 00431 while (this.select_scenario.last_selected.size() > 10) begin \ 00432 void'(this.select_scenario.last_selected.pop_front()); \ 00433 end \ 00434 \ 00435 the_scenario = this.scenario_set[this.select_scenario.select]; \ 00436 if (the_scenario == null) begin \ 00437 `vmm_fatal(this.log, `vmm_sformatf("Selected scenario #%0d does not exist", \ 00438 this.select_scenario.select)); \ 00439 continue; \ 00440 end \ 00441 \ 00442 the_scenario.stream_id = this.stream_id; \ 00443 the_scenario.scenario_id = this.scenario_count; \ 00444 foreach (the_scenario.items[i]) begin \ 00445 if (the_scenario.items[i] == null) continue; \ 00446 \ 00447 the_scenario.items[i].stream_id = the_scenario.stream_id; \ 00448 the_scenario.items[i].scenario_id = the_scenario.scenario_id; \ 00449 the_scenario.items[i].data_id = i; \ 00450 end \ 00451 \ 00452 `vmm_callback(`vmm_scenario_gen_callbacks_(class_name), \ 00453 pre_scenario_randomize(this, the_scenario)); \ 00454 if (the_scenario == null) continue; \ 00455 \ 00456 if (!the_scenario.randomize()) begin \ 00457 `vmm_fatal(this.log, $psprintf("Cannot randomize scenario descriptor #%0d", \ 00458 this.select_scenario.select)); \ 00459 continue; \ 00460 end \ 00461 \ 00462 this.inject(the_scenario); \ 00463 end \ 00464 \ 00465 this.notify.indicate(DONE); \ 00466 this.notify.indicate(XACTOR_STOPPED); \ 00467 this.notify.indicate(XACTOR_IDLE); \ 00468 this.notify.reset(XACTOR_BUSY); \ 00469 this.scenario_count++; \ 00470 endtask: main \ 00471 \ 00472 endclass