VMM OpenSource - (expanded) sv/std_lib/vmm_scheduler.sv

Expanded versions of source files are the output of the preprocessor. Lines subject to conditional compilation are not shown and all compiler pragmas have been stripped. Macros have been completely expanded.

sv/std_lib/vmm_scheduler.sv unexpanded 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: 
00023: function vmm_scheduler::new(string       name,
00024:                             string       inst,
00025:                             vmm_channel  destination,
00026:                             int          instance_id = -1
00027:                             );
00028:    super.new(name, inst, instance_id );
00029:    
00030:    if (destination == null) begin
00031:       if (this.log.start_msg(vmm_log::FAILURE_TYP, vmm_log::FATAL_SEV)) begin
00032:          void'(this.log.text("Cannot create vmm_scheduler instance with a NULL destination channel reference"));
00033:          this.log.end_msg();
00034:       end
00035:       return;
00036:    end
00037:    this.out_chan = destination;
00038:    this.log.is_above(this.out_chan.log);
00039: 
00040:    this.randomized_sched = new;
00041: 
00042:    this.instance_id = instance_id;
00043:    this.election_count = 0;
00044: endfunction : new
00045: 
00046: 
00047: function string vmm_scheduler::psdisplay(string prefix = "");
00048:    psdisplay = super.psdisplay(prefix);
00049:    $sformat(psdisplay, "%s\n%sOutChan: %s(%s) [level=%0d of %0d]",
00050:             psdisplay, prefix, this.out_chan.log.get_name(),
00051:             this.out_chan.log.get_instance(), this.out_chan.level(),
00052:             this.out_chan.full_level());
00053:    foreach (this.sources[i]) begin
00054:       $sformat(psdisplay, "%s\n%sInChan[%0d/%s]: %s(%s) [level=%0d of %0d]",
00055:                psdisplay, prefix, i, (this.is_on[i]) ? "ON " : "OFF",
00056:                this.sources[i].log.get_name(),
00057:                this.sources[i].log.get_instance(), this.sources[i].level(),
00058:                this.sources[i].full_level());
00059:    end
00060:    return psdisplay;
00061: endfunction
00062: 
00063: 
00064: function int vmm_scheduler::new_source(vmm_channel channel);
00065:    if (channel == null) begin
00066:       if (this.log.start_msg(vmm_log::FAILURE_TYP, vmm_log::WARNING_SEV)) begin
00067:          void'(this.log.text("Attempting to add a NULL source channel"));
00068:          this.log.end_msg();
00069:       end
00070:       return -1;
00071:    end
00072:    
00073:    new_source = this.sources.size();
00074:    
00075:    this.sources.push_back(channel);
00076:    this.is_on.push_back(1);
00077:    if (channel.level() > 0) begin
00078:       -> this.next_cycle;
00079:    end
00080: 
00081:    // Watch for new additions to the newly added source
00082:    // to potentially trigger new scheduling cycles
00083:    fork 
00084:       while (1) begin
00085:          // The input channel may have been filled
00086:          // before the forked thread has had a chance
00087:          // to wait on the PUT indication
00088:          if (channel.level() > 0) begin
00089:             -> this.next_cycle;
00090:          end
00091:          channel.notify.wait_for(vmm_channel::PUT);
00092:          -> this.next_cycle;
00093:       end
00094:    join_none 
00095:   
00096: endfunction : new_source
00097: 
00098: 
00099: task vmm_scheduler::sched_from_input(int channel_id,
00100:                                      int on_off);
00101:    if (channel_id < 0 || channel_id >= this.sources.size()) begin
00102:       if (this.log.start_msg(vmm_log::FAILURE_TYP, vmm_log::WARNING_SEV)) begin
00103:          string msg;
00104:          $sformat(msg, "Invalid source channel ID specified in vmm_scheduler::sched_from_input(): %0d", channel_id);
00105:          void'(this.log.text(msg));
00106:          this.log.end_msg();
00107:       end
00108:       return;
00109:    end
00110: 
00111:    this.is_on[channel_id] = on_off;
00112: 
00113:    if (this.log.start_msg(vmm_log::INTERNAL_TYP, vmm_log::TRACE_SEV)) begin
00114:       string msg;
00115:       $sformat(msg, "Scheduling from channel #%0d turned %s", channel_id,
00116:               (on_off) ? "ON" : "OFF");
00117:       void'(this.log.text(msg));
00118:       this.log.end_msg();
00119:    end
00120: 
00121:    if (on_off && this.sources[channel_id].level() > 0) begin
00122:       -> this.next_cycle;
00123:    end
00124: endtask : sched_from_input
00125: 
00126: 
00127: task vmm_scheduler::schedule(output vmm_data     obj,
00128:                              input  vmm_channel  sources[$],
00129:                              input  int unsigned input_ids[$]);
00130:    int     id;
00131:    
00132:    this.randomized_sched.instance_id = this.instance_id;
00133:    this.randomized_sched.election_id = this.election_count++;
00134:    this.randomized_sched.n_sources   = sources.size();
00135:    this.randomized_sched.sources     = sources;
00136:    this.randomized_sched.ids         = input_ids;
00137: 
00138:    // Round-robin scheduler  
00139:    this.randomized_sched.next_idx = 0;
00140:    if (this.randomized_sched.id_history.size() > 0) begin
00141:       int last_id;
00142:       // Find the next ID that follows (numerically) the last one
00143:       // that was picked or use the first ID in the list of IDs.
00144:       // Note: IDs will be stored in increasing numerical values.
00145:       last_id = this.randomized_sched.id_history[$];
00146:       foreach (input_ids[i]) begin
00147:          if (input_ids[i] > last_id) begin
00148:             this.randomized_sched.next_idx = i;
00149:             break;
00150:          end
00151:       end
00152:    end
00153: 
00154:    obj = null;
00155:    if (!this.randomized_sched.randomize()) begin
00156:       if (this.log.start_msg(vmm_log::FAILURE_TYP, vmm_log::FATAL_SEV)) begin
00157:          void'(this.log.text("Unable to randomize vmm_scheduler::randomized_sched"));
00158:          this.log.end_msg();
00159:       end
00160:       return;
00161:    end
00162:    if (this.randomized_sched.source_idx < 0) return;
00163: 
00164:    if (this.randomized_sched.source_idx >= input_ids.size()) begin
00165:       if (this.log.start_msg(vmm_log::FAILURE_TYP, vmm_log::FATAL_SEV)) begin
00166:          void'(this.log.text("vmm_scheduler::randomized_sched randomized to an invalid choice"));
00167:          this.log.end_msg();
00168:       end
00169:       return;
00170:    end
00171:    
00172:    id = input_ids[this.randomized_sched.source_idx];
00173: 
00174:    if (this.log.start_msg(vmm_log::INTERNAL_TYP, vmm_log::TRACE_SEV)) begin
00175:       string msg;
00176:       $sformat(msg, "Scheduled data from source #%0d, offset %0d",
00177:               id, this.randomized_sched.obj_offset);
00178:       void'(this.log.text(msg));
00179:       this.log.end_msg();
00180:    end
00181: 
00182:    begin
00183:       vmm_channel src = this.sources[id]; 
00184:       if (src == null || src.level() == 0 ||
00185:           src.level() <= this.randomized_sched.obj_offset) begin
00186:          if (this.log.start_msg(vmm_log::FAILURE_TYP, vmm_log::FATAL_SEV)) begin
00187:             void'(this.log.text("vmm_scheduler::randomized_sched randomized to an invalid source"));
00188:             this.log.end_msg();
00189:          end
00190:          return;
00191:       end
00192:       this.get_object(obj, src, id, this.randomized_sched.obj_offset);
00193:    end
00194: 
00195:    this.randomized_sched.id_history.push_back(id);
00196:    this.randomized_sched.obj_history.push_back(obj);
00197:    if (this.randomized_sched.id_history.size() > 10) begin
00198:       void'(this.randomized_sched.id_history.pop_front());
00199:       void'(this.randomized_sched.obj_history.pop_front());
00200:    end
00201: endtask : schedule
00202: 
00203: 
00204: task vmm_scheduler::get_object(output vmm_data     obj,
00205:                                input  vmm_channel  source,
00206:                                input  int unsigned input_id,
00207:                                input  int          offset);
00208:    obj = null;
00209: 
00210:    if (source == null) begin
00211:       if (this.log.start_msg(vmm_log::FAILURE_TYP, vmm_log::FATAL_SEV)) begin
00212:          void'(this.log.text("vmm_scheduler::get_object called with invalid source"));
00213:          this.log.end_msg();
00214:       end
00215:       return;
00216:    end
00217:    
00218:    if (offset >= source.level()) begin
00219:       if (this.log.start_msg(vmm_log::FAILURE_TYP, vmm_log::FATAL_SEV)) begin
00220:          void'(this.log.text("vmm_scheduler::get_object called with invalid offset"));
00221:          this.log.end_msg();
00222:       end
00223:       return;
00224:    end
00225:    
00226:    source.get( obj, offset);
00227: endtask : get_object
00228: 
00229: 
00230: function void vmm_scheduler::start_xactor();
00231:    super.start_xactor();
00232:    // This MAY cause a new scheduling cycle
00233:    -> this.next_cycle;
00234: endfunction : start_xactor
00235: 
00236: 
00237: function void vmm_scheduler::stop_xactor();
00238:    super.stop_xactor();
00239: endfunction : stop_xactor
00240: 
00241: 
00242: function void vmm_scheduler::reset_xactor(vmm_xactor::reset_e rst_typ = SOFT_RST);
00243:    super.reset_xactor(rst_typ);
00244:    
00245:    this.out_chan.flush();
00246:    foreach (sources[i]) begin
00247:       this.sources[i].flush();
00248:    end
00249: 
00250:    this.instance_id = instance_id;
00251:    this.election_count = 0;
00252: 
00253:    if (rst_typ == HARD_RST ) begin
00254:       this.randomized_sched = new;
00255:    end
00256: endfunction
00257: 
00258: 
00259: task vmm_scheduler::main();
00260:    fork
00261:       super.main();
00262:       this.schedule_cycle();
00263:    join_none
00264: endtask
00265: 
00266: 
00267: task vmm_scheduler::schedule_cycle();
00268:    vmm_data          data;
00269:    vmm_channel       srcs[$];
00270:    int unsigned      ids[$];
00271:    
00272:    while (1) begin
00279:       // Works in VCS2008.03 or later
00280:       // IEEE 1800-2005 compliant
00281:       srcs = '{};
00282:       ids = '{};
00284: 
00285:       super.wait_if_stopped();
00286: 
00287:       // Identify all non-empty, active sources
00288:       foreach (this.sources[i]) begin
00289:          if (this.is_on[i] && this.sources[i] != null &&
00290:              this.sources[i].level() > 0) begin
00291:             srcs.push_back(this.sources[i]);
00292:             ids.push_back(i);
00293:          end
00294:       end
00295:       if (srcs.size() == 0) data = null;
00296:       else this.schedule(data, srcs, ids);
00297: 
00298:       if (data == null) begin
00299:          // Delay the next scheduling cycle until
00300:          // A new channel is added, new data is put into
00301:          // a channel, a channel is turned on or the scheduler
00302:          // is restarted
00303:          
     : do 
     :    /* synopsys translate_off */ 
     :    if (this.log.start_msg(vmm_log::DEBUG_TYP, vmm_log::TRACE_SEV, "", -1)) begin 
     :       void'(this.log.text("Waiting for next scheduling cycle...")); 
     :       this.log.end_msg(); 
     :    end 
     :    /* synopsys translate_on */ 
     : while (0);
00304:          @ ( this.next_cycle);
00305:          continue;
00306:       end
00307:       this.out_chan.put(data);
00308:    end
00309: endtask
00310: