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