VMM - (expanded) 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.

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