VMM - std_lib/vmm_scenario_gen.sv

std_lib/vmm_scenario_gen.sv expanded source

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