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