VMM - (expanded) std_lib/vmm_broadcast.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_broadcast.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_broadcast::new(string      name,
00024:                             string      inst,
00025:                             vmm_channel source,
00026:                             bit         use_references,
00027:                             int         mode
00028:                             );
00029:    super.new(name, inst, -1 );
00030:    
00031:    if (source == null) begin
00032:       if (this.log.start_msg(vmm_log::FAILURE_TYP, vmm_log::FATAL_SEV)) begin
00033:          this.log.text("Cannot create vmm_broadcast instance with a NULL source channel reference");
00034:          this.log.end_msg();
00035:       end
00036:    end
00037: 
00038:    this.in_chan       = source;
00039:    this.log.is_above(this.in_chan.log);
00040:    this.dflt_use_refs = use_references;
00041:    this.mode          = mode;
00042: 
00043:    this.n_out_chans = 0;
00044: endfunction : new
00045: 
00046: 
00047: task vmm_broadcast::broadcast_mode(bcast_mode_e mode);
00048:    if (mode != AFAP && mode != ALAP) begin
00049:       if (this.log.start_msg(vmm_log::FAILURE_TYP, vmm_log::FATAL_SEV)) begin
00050:          this.log.text($psprintf("Invalid broadcast mode %0d", mode));
00051:          this.log.end_msg();
00052:       end
00053:       return;
00054:    end
00055:    
00056:    this.mode = mode;
00057:    // This MAY create the opportunity for a new broadcast cycle...
00058:    -> this.new_cycle;
00059: endtask : broadcast_mode
00060: 
00061: 
00062: function int vmm_broadcast::new_output(vmm_channel channel,
00063:                                        logic use_references);
00064:    int     chan_id = this.n_out_chans++;
00065:    
00066: 
00067:    this.out_chans.push_back(channel);
00068:    this.is_on.push_back(1);
00069:    this.use_refs.push_back((use_references === 1'bx) ?
00070:                            this.dflt_use_refs : use_references);
00071: 
00072: 
00073:    // Trigger a new broadcasting cycle whenever the channel becomes
00074:    // empty while it is ON
00075:    fork
00076:       while (1) begin
00077:          // A new (presumably empty) channel is added creates
00078:          // a broadcast opportunity
00079:          if (this.is_on[chan_id]) -> this.new_cycle;
00080:          channel.notify.wait_for(vmm_channel::GOT);
00081:       end
00082:    join_none
00083: 
00084:    new_output = chan_id;
00085: endfunction : new_output
00086: 
00087: 
00088: function void vmm_broadcast::bcast_on(int unsigned output_id);
00089:    this.bcast_on_off(output_id, 1);
00090: endfunction: bcast_on   
00091: 
00092: 
00093: function void vmm_broadcast::bcast_off(int unsigned output_id);
00094:    this.bcast_on_off(output_id, 0);
00095: endfunction: bcast_off
00096: 
00097: 
00098: function void vmm_broadcast::bcast_on_off(int     channel_id,
00099:                                           int     on_off);
00100:    if (channel_id < 0 || channel_id >= this.n_out_chans) begin
00101:       if (this.log.start_msg(vmm_log::FAILURE_TYP)) begin
00102:          string txt;
00103:          $sformat(txt, "Invalid output channel ID %0d", channel_id);
00104:          this.log.text(txt);
00105:          this.log.end_msg();
00106:       end
00107:       return;
00108:    end
00109: 
00110:    this.is_on[channel_id] = on_off;
00111: 
00112:    // If a non-full channel is turned back on, this triggers a
00113:    // new broadcasting cycle
00114:    if (on_off && !this.out_chans[channel_id].is_full()) begin
00115:       -> this.new_cycle;
00116:    end
00117: 
00118:    // If a full channel is turned off, this triggers a
00119:    // new broadcasting cycle
00120:    if (!on_off && this.out_chans[channel_id].is_full()) begin
00121:       -> this.new_cycle;
00122:    end
00123: 
00124:    // Flush a channel that has been turned off
00125:    if (!on_off) begin
00126:       this.out_chans[channel_id].flush();
00127:    end
00128: endfunction: bcast_on_off
00129: 
00130: 
00131: task vmm_broadcast::bcast_to_output(int     channel_id,
00132:                                     int     on_off);
00133:    this.bcast_on_off(channel_id, on_off);
00134: endtask : bcast_to_output
00135: 
00136: 
00137: function bit vmm_broadcast::add_to_output(int unsigned decision_id,
00138:                                           int unsigned output_id,
00139:                                           vmm_channel  channel,
00140:                                           vmm_data     obj);
00141:    add_to_output = 1;
00142: endfunction : add_to_output
00143: 
00144: 
00145: function void vmm_broadcast::start_xactor();
00146:    super.start_xactor();
00147: endfunction : start_xactor
00148: 
00149: 
00150: function void vmm_broadcast::stop_xactor();
00151:    super.stop_xactor();
00152: endfunction : stop_xactor
00153: 
00154: 
00155: function void vmm_broadcast::reset_xactor(vmm_xactor::reset_e rst_typ);
00156:    super.reset_xactor(rst_typ);
00157:    
00158:    this.in_chan.flush();
00159:    foreach (out_chans[i]) begin
00160:       this.out_chans[i].flush();
00161:    end
00162: endfunction : reset_xactor
00163: 
00164: 
00165: task vmm_broadcast::main();
00166:    fork
00167:       super.main();
00168:       this.broadcast();
00169:       this.sink_if_outs();
00170:    join_none
00171: endtask : main
00172: 
00173: 
00174: task vmm_broadcast::broadcast();
00175:    bit run_once = 1;
00176:    
00177:    while (1) begin
00178:       int     decision_id = 0;
00179:       int     i;
00180:       int     go;
00181:       
00182:       vmm_data data, cpy;
00183:       vmm_data obj;
00184:       
00185:       if (this.log.start_msg(vmm_log::INTERNAL_TYP, vmm_log::TRACE_SEV)) begin
00186:          this.log.text("Waiting for next broadcasting cycle...");
00187:          this.log.end_msg();
00188:       end
00189:       if (!run_once)  @ this.new_cycle;
00190:       run_once = 0;
00191:       this.wait_if_stopped();
00192: 
00193:       // OK to broadcast?
00194:       case (this.mode) 
00195: 
00196:          AFAP: begin
00197:             // OK to broadcast if just one active output channel
00198:             // is not full
00199:             int     i;
00200: 
00201:             go = 0;
00202:             for (i = 0; i < this.n_out_chans; i++) begin
00203:                if (this.is_on[i] && !this.out_chans[i].is_full()) begin
00204:                   go = 1;
00205:                   break;
00206:                end
00207:             end
00208:          end
00209:          
00210:          ALAP: begin
00211:             // OK to broadcast only if ALL active output channel
00212:             // are not full
00213:             int     i;
00214:             
00215:             go = 1;
00216:             for (i = 0; i < this.n_out_chans; i++) begin
00217:                if (this.is_on[i] && this.out_chans[i].is_full()) begin
00218:                   go = 0;
00219:                   break;
00220:                end
00221:             end
00222:          end
00223: 
00224:          default: begin
00225:             
     : do 
     :    if (this.log.start_msg(vmm_log::FAILURE_TYP, vmm_log::ERROR_SEV)) begin 
     :       void'(this.log.text($psprintf("Internal Error: Invalid broadcasting mode %0d!", this.mode))); 
     :       this.log.end_msg(); 
     :    end 
     : while (0);
00226:             continue;
00227:          end
00228:       endcase
00229:       // No go!
00230:       if (!go) continue;
00231:       
00232:       this.wait_if_stopped();
00233:       this.in_chan.get(data);
00234:       this.wait_if_stopped();
00235:        
00246: 
00247:       for (i = 0; i < this.n_out_chans; i++) begin
00248:          if (this.is_on[i]) begin
00249: 
00250:             // Copy or reference?
00251:             if (this.use_refs[i]) begin
00252:                 obj = data;
00253:             end
00254:             else begin
00255:                // Minimize the number of copies made
00256:                if (cpy == null) cpy = data.copy();
00257:                obj = cpy;
00258:             end
00259:             
00260:             if (this.add_to_output(decision_id++, i, this.out_chans[i], obj)) begin
00261:                this.out_chans[i].sneak(obj);
00275:                // Mark the copy as having been used.
00276:                if (!this.use_refs[i]) cpy = null;
00277:             end
00278:          end
00279:       end
00280:    end
00281: endtask : broadcast 
00282: 
00283: 
00284: task vmm_broadcast::sink_if_outs();
00285:    bit sink;
00286:    vmm_data unused_data;
00287:    
00288:    vmm_data temp_obj;
00289:    // Sink the data from the source channel
00290:    // if there are no active output channels
00291:    while (1) begin
00292:       int     i;
00293: 
00294:       // Wait for something to be in the source channel
00295:       vmm_data peeked;
00296:       this.in_chan.peek(peeked);
00297: 
00298:       // Can it go anywhere??
00299:       sink = 1;
00300:       for (i = 0; i < this.n_out_chans; i++) begin
00301:          if (this.is_on[i]) begin
00302:             sink = 0;
00303:             break;
00304:          end
00305:       end
00306: 
00307:       // Sink it if there is nowhere to go and it has not
00308:       // been removed by some other thread.
00309:       this.in_chan.peek( temp_obj);
00310:       if (sink && this.in_chan.level() > 0 &&
00311:           temp_obj == peeked ) begin
00312:          this.in_chan.get( unused_data);
00313:       end
00314: 
00315:       if (in_chan.level() > 0) begin
00316:          in_chan.notify.wait_for(vmm_channel::GOT);
00317:       end
00318:    end
00319: endtask : sink_if_outs