VMM - std_lib/vmm_broadcast.sv

std_lib/vmm_broadcast.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 
00023 function vmm_broadcast::new(string      name,
00024                             string      inst,
00025                             vmm_channel source,
00026                             bit         use_references,
00027                             int         mode
00028                             `VMM_XACTOR_NEW_EXTERN_ARGS);
00029    super.new(name, inst, -1 `VMM_XACTOR_NEW_CALL);
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(`vmm_sformatf("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             `vmm_error(this.log, `vmm_sformatf("Internal Error: Invalid broadcasting mode %0d!", this.mode));
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        
00236 `ifdef VMM_DETAILED_MSGS
00237       if (this.log.start_msg(vmm_log::INTERNAL_TYP, vmm_log::TRACE_SEV)) begin
00238          this.log.text("New broadcasting cycle...");
00239          this.log.end_msg();
00240       end
00241       if (this.log.start_msg(vmm_log::INTERNAL_TYP, vmm_log::VERBOSE_SEV)) begin
00242          this.log.text(data.psdisplay("Broadcasting:"));
00243          this.log.end_msg();
00244       end
00245 `endif
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);
00262 `ifdef VMM_DETAILED_MSGS
00263                if (this.log.start_msg(vmm_log::INTERNAL_TYP,
00264                                       vmm_log::DEBUG_SEV)) begin
00265                   string msg;
00266                   $sformat(msg, "Broadcasted to output #%0d", i);
00267                   this.log.text(msg);
00268                   this.log.end_msg();
00269                end
00270                if (this.log.start_msg(vmm_log::INTERNAL_TYP, vmm_log::VERBOSE_SEV)) begin
00271                   this.log.text(obj.psdisplay("Broadcasted:"));
00272                   this.log.end_msg();
00273                end
00274 `endif
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