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: // ToDo: Fill level based on bytes
00024:
00025: function vmm_channel::new(string name,
00026: string inst,
00027: int unsigned full=1,
00028: int unsigned empty=0,
00029: bit fill_as_bytes=1'b0);
00033:
00034: if (this.shared_log == null) begin
00035: this.one_log = _vmm_opts.get_bit("channel_shared_log",
00036: "All VMM channels share the same vmm_log instance");
00037: this.shared_log = new("VMM Channel", "[shared]");
00038: end
00039:
00040: if (this.one_log) this.log = shared_log;
00041: else this.log = new(name, inst);
00042: this.shared_log = this.log;
00043:
00044: this.notify = new(this.log);
00045:
00046:
00047: void'(this.notify.configure(FULL, vmm_notify::ON_OFF));
00048: void'(this.notify.configure(EMPTY, vmm_notify::ON_OFF));
00049: void'(this.notify.configure(PUT));
00050: void'(this.notify.configure(GOT));
00051: void'(this.notify.configure(PEEKED));
00052: void'(this.notify.configure(ACTIVATED));
00053: void'(this.notify.configure(ACT_STARTED));
00054: void'(this.notify.configure(ACT_COMPLETED));
00055: void'(this.notify.configure(ACT_REMOVED));
00056: void'(this.notify.configure(LOCKED));
00057: void'(this.notify.configure(UNLOCKED));
00058: void'(this.notify.configure(GRABBED));
00059: void'(this.notify.configure(UNGRABBED));
00060: void'(this.notify.configure(RECORDING, vmm_notify::ON_OFF));
00061: void'(this.notify.configure(PLAYBACK, vmm_notify::ON_OFF));
00062: void'(this.notify.configure(PLAYBACK_DONE, vmm_notify::ON_OFF));
00063:
00064: if (full <= 0) full = 1;
00065: if (empty < 0 || empty > full) empty = full;
00066:
00067: this.full = full;
00068: this.empty = empty;
00069: this.is_sunk = 0;
00070:
00071: this.active = null;
00072: this.active_status = INACTIVE;
00073: this.tee_on = 0;
00074: this.downstream = null;
00075: this.locks = 2'b00;
00076:
00077: this.full_chan = 0;
00078: this.notify.indicate(EMPTY);
00079:
00080: this.iterator = 0;
00081: this.is_put = 0;
00082: this.is_playback = 0;
00083: this.record_fp = -1;
00084:
00085: //
00086: // Thread to manage connection requests
00087: //
00088: fork: connection_requests
00089: while (1)
00090: begin : new_while_loop
00091: vmm_data data = null;
00092:
00093: // Broken connection?
00094: if (this.downstream != null)
00095: begin
00096: if (this.log.start_msg(vmm_log::INTERNAL_TYP, vmm_log::TRACE_SEV))
00097: begin
00098: string txt;
00099: txt = {"Channel connection established: ",
00100: this.log.get_name(),
00101: "(", this.log.get_instance(), ") -> ",
00102: this.downstream.log.get_name(),
00103: "(", this.downstream.log.get_instance(), ")"};
00104:
00105: void'(this.log.text(txt));
00106: this.log.end_msg();
00107: end // if debug level
00108:
00109: // Fork the data mover thread
00110: fork
00111: while (1)
00112: begin : inner_while_loop
00113: // Simple blocking interface
00114: data = null;
00115: this.peek(data);
00116: this.downstream.put(data);
00117: this.get(data);
00118: end // inner_while_loop
00119: join_none
00120: end // if downstream != null
00121:
00122: // Wait for new connection requests
00123: @this.new_connection;
00124:
00125: // Stop the data mover thread
00126: disable fork;
00127:
00128: // Remove any datum that was forwarded
00129: // to the downstream channel but not removed
00130: // from this channel because of the blocking
00131: // model. Otherwise, the same datum will be
00132: // obtained from this channel twice.
00133: if (data != null) this.get(data);
00134: end // while (1)
00135: join_none // connection_requests
00136: endfunction : new
00137:
00138:
00139: function void vmm_channel::reconfigure(int full=-1,
00140: int empty=-1,
00141: logic fill_as_bytes=1'bx);
00142: if (full < 0) full = this.full;
00143: if (full == 0) full = 1;
00144: if (empty < 0) empty = this.empty;
00145:
00146: if (full < empty)
00147: begin
00148:
: do
: /* synopsys translate_off */
: if (this.log.start_msg(vmm_log::FAILURE_TYP, vmm_log::ERROR_SEV, "", -1)) begin
: void'(this.log.text("Cannot reconfigure channel with FULL < EMPTY"));
: this.log.end_msg();
: end
: /* synopsys translate_on */
: while (0);
00149: return;
00150: end
00151:
00152: this.full = full;
00153: this.empty = empty;
00154:
00155: if (this.level() >= this.full)
00156: begin
00157: this.full_chan = 1;
00158: this.notify.indicate(FULL);
00159: this.notify.reset(EMPTY);
00160: end
00161: else if (this.level() <= this.empty)
00162: begin
00163: this.full_chan = 0;
00164: -> this.item_taken;
00165: this.notify.indicate(EMPTY);
00166: this.notify.reset(FULL);
00167: end
00168: else
00169: begin
00170: this.full_chan = 0;
00171: -> this.item_taken;
00172: this.notify.reset(EMPTY);
00173: this.notify.reset(FULL);
00174: end
00175: endfunction: reconfigure
00176:
00177:
00178: function int unsigned vmm_channel::full_level();
00179: full_level = this.full;
00180: endfunction: full_level
00181:
00182:
00183: function int unsigned vmm_channel::empty_level();
00184: empty_level = this.empty;
00185: endfunction: empty_level
00186:
00187:
00188: function int unsigned vmm_channel::level();
00189: level = this.data.size() + ((this.active == null) ? 0 : 1);
00190: endfunction: level
00191:
00192:
00193: function int unsigned vmm_channel::size();
00194: size = this.data.size() + ((this.active == null) ? 0 : 1);
00195: endfunction : size
00196:
00197:
00198: function bit vmm_channel::is_full();
00199: is_full = full_chan;
00200: endfunction : is_full
00201:
00202:
00203: function void vmm_channel::flush();
00204: vmm_data obj;
00205: if (this.downstream != null)
00206: this.downstream.flush();
00207:
00214: // Works in VCS2008.03 or later
00215: // IEEE 1800-2005 compliant
00216: this.data = '{};
00217: this.tee_data = '{};
00219: full_chan = 0;
00220: this.active = null;
00221: this.active_status = INACTIVE ;
00222: -> this.item_taken;
00223: this.notify.reset(FULL);
00224: this.notify.indicate(EMPTY);
00225: endfunction: flush
00226:
00228: function void vmm_channel::reset_grabbers();
00234: // Works in VCS2008.03 or later
00235: // IEEE 1800-2005 compliant
00236: this.grab_owners = '{};
00238: endfunction: reset_grabbers
00240:
00241: function void vmm_channel::sink();
00242: this.flush();
00243: this.is_sunk = 1;
00244: endfunction: sink
00245:
00246:
00247: function void vmm_channel::flow();
00248: this.is_sunk = 0;
00249: endfunction: flow
00250:
00251:
00252: function void vmm_channel::reset();
00253: this.flush();
00255: this.reset_grabbers();
00257: endfunction: reset
00258:
00259:
00260: function void vmm_channel::lock(bit [1:0] who);
00261: this.locks |= who;
00262: this.notify.indicate(LOCKED);
00263: endfunction: lock
00264:
00265:
00266: function void vmm_channel::unlock(bit [1:0] who);
00267: this.locks &= ~who;
00268: this.notify.indicate(UNLOCKED);
00269: // May cause a consumer or producer to unblock
00270: -> this.item_taken;
00271: -> this.item_added;
00272: endfunction: unlock
00273:
00274:
00275: function bit vmm_channel::is_locked(bit [1:0] who);
00276: is_locked = (this.locks & who) ? 1 : 0;
00277: endfunction: is_locked
00278:
00279:
00281: function bit vmm_channel::check_grab_owners(vmm_scenario grabber);
00282: vmm_scenario current_parent;
00283:
00284: current_parent = grabber;
00285:
00286: while (current_parent != null) begin
00287: if (this.grab_owners[0] == current_parent) begin
00288: return 1;
00289: end
00290: current_parent = current_parent.get_parent_scenario();
00291: end
00292: return 0;
00293: endfunction: check_grab_owners
00294:
00295:
00296: function bit vmm_channel::check_all_grab_owners(vmm_scenario grabber);
00297: foreach (this.grab_owners[i]) begin
00298: if (grabber == this.grab_owners[i]) return 1;
00299: end
00300: return 0;
00301: endfunction: check_all_grab_owners
00303:
00304:
00305: function bit vmm_channel::try_grab(vmm_scenario grabber);
00307: if (this.notify.is_on(PLAYBACK)) begin
00308:
: do
: /* synopsys translate_off */
: if (this.log.start_msg(vmm_log::FAILURE_TYP, vmm_log::WARNING_SEV, "", -1)) begin
: void'(this.log.text("Cannot grab a channel during playback"));
: this.log.end_msg();
: end
: /* synopsys translate_on */
: while(0);
00309: return 0;
00310: end
00311:
00312: if (this.check_all_grab_owners(grabber)) begin
00313:
: do
: /* synopsys translate_off */
: if (this.log.start_msg(vmm_log::FAILURE_TYP, vmm_log::WARNING_SEV, "", -1)) begin
: void'(this.log.text("Cannot grab a channel that is already grabbed by you"));
: this.log.end_msg();
: end
: /* synopsys translate_on */
: while(0);
00314: return 0;
00315: end
00316:
00317: if ((this.grab_owners.size() == 0) ||
00318: (this.check_grab_owners(grabber))) begin
00319: this.grab_owners.push_front(grabber);
00320: this.notify.indicate(GRABBED);
00321: return 1;
00322: end
00323:
00324: return 0;
00328: endfunction: try_grab
00329:
00330:
00331: task vmm_channel::grab(vmm_scenario grabber);
00333: if (this.notify.is_on(PLAYBACK)) begin
00334: this.notify.wait_for(vmm_channel::PLAYBACK_DONE);
00335: end
00336:
00337: if (this.grab_owners.size()==0) begin
00338: this.grab_owners.push_front(grabber);
00339: this.notify.indicate(GRABBED);
00340: end
00341: else begin
00342: if (this.check_all_grab_owners(grabber)) begin
00343:
: do
: /* synopsys translate_off */
: if (this.log.start_msg(vmm_log::FAILURE_TYP, vmm_log::ERROR_SEV, "", -1)) begin
: void'(this.log.text("Cannot grab a channel that is already grabbed by you"));
: this.log.end_msg();
: end
: /* synopsys translate_on */
: while (0);
00344: end
00345: else if (this.check_grab_owners(grabber)) begin
00346: this.grab_owners.push_front(grabber);
00347: this.notify.indicate(GRABBED);
00348: end
00349: else begin
00350: this.notify.wait_for(vmm_channel::UNGRABBED);
00351: this.grab(grabber);
00352: end
00353: end
00357: endtask: grab
00358:
00359:
00360: function void vmm_channel::ungrab(vmm_scenario grabber);
00362: if (this.grab_owners.size()==0) begin
00363:
: do
: /* synopsys translate_off */
: if (this.log.start_msg(vmm_log::FAILURE_TYP, vmm_log::ERROR_SEV, "", -1)) begin
: void'(this.log.text("Cannot ungrab a channel that is not grabbed!"));
: this.log.end_msg();
: end
: /* synopsys translate_on */
: while (0);
00364: end
00365: else begin
00366: if (grabber == this.grab_owners[0]) begin
00367: void'(this.grab_owners.pop_front());
00368: this.notify.indicate(UNGRABBED);
00369: end
00370: else begin
00371:
: do
: /* synopsys translate_off */
: if (this.log.start_msg(vmm_log::FAILURE_TYP, vmm_log::ERROR_SEV, "", -1)) begin
: void'(this.log.text("Cannot ungrab a channel that you did not grab!"));
: this.log.end_msg();
: end
: /* synopsys translate_on */
: while (0);
00372: end
00373: end
00377: endfunction: ungrab
00378:
00379:
00380: function bit vmm_channel::is_grabbed();
00382: return (this.grab_owners.size() > 0);
00387: endfunction: is_grabbed
00388:
00389:
00390: function void vmm_channel::display(string prefix="");
00391: $display(this.psdisplay(prefix));
00392: endfunction: display
00393:
00394:
00395: function string vmm_channel::psdisplay(string prefix="");
00396: $sformat(psdisplay, "%sChannel %s(%s): Level = %0d of %0d (empty=%0d)",
00397: prefix, this.log.get_name(), this.log.get_instance(),
00398: this.level(), this.full, this.empty);
00399: case (this.locks)
00400: SOURCE+SINK : psdisplay = {psdisplay, " [src+snk locked]"};
00401: SOURCE: psdisplay = {psdisplay, " [src locked]"};
00402: SINK: psdisplay = {psdisplay, " [snk locked]"};
00403: endcase
00404: if (this.is_sunk) psdisplay = {psdisplay, " (sunk)"};
00406: if (this.is_grabbed()) psdisplay = {psdisplay, " (grabbed by %s)",
00407: this.grab_owners[0].scenario_name(0)};
00409:
00410: foreach(this.data[i]) begin
00411: $sformat(psdisplay, "%s\n%s", psdisplay, this.data[i].psdisplay($psprintf("%s [%0d] ",
00412: prefix, i)));
00413: end
00414: endfunction: psdisplay
00415:
00416:
00418: task vmm_channel::put(vmm_data obj,
00419: int offset=-1,
00420: vmm_scenario grabber=null);
00421: if (obj == null)
00422: begin
00423:
: do
: /* synopsys translate_off */
: if (this.log.start_msg(vmm_log::FAILURE_TYP, vmm_log::ERROR_SEV, "", -1)) begin
: void'(this.log.text("Attempted to put null instance into channel"));
: this.log.end_msg();
: end
: /* synopsys translate_on */
: while (0);
00424: return;
00425: end // if obj == null
00426:
00428: this.block_producer(grabber);
00429: this.is_put = 1'b1;
00430: this.sneak(obj, offset, grabber);
00431: this.is_put = 1'b0;
00432: this.block_producer(grabber);
00440: endtask: put
00442:
00444: task vmm_channel::XputX(vmm_data obj,
00445: int offset=-1,
00446: vmm_scenario grabber=null);
00451: while (this.full_chan)
00452: @this.item_taken;
00453: this.is_playback = 1'b1;
00455: this.sneak(obj, offset, grabber);
00459: this.is_playback = 1'b0;
00460: while (this.full_chan)
00461: @this.item_taken;
00462:
00463: endtask: XputX
00464:
00466: function void vmm_channel::sneak(vmm_data obj,
00467: int offset=-1,
00468: vmm_scenario grabber=null);
00473: string txt;
00474: time diff_time;
00475:
00476: if (obj == null)
00477: begin
00478:
: do
: /* synopsys translate_off */
: if (this.log.start_msg(vmm_log::FAILURE_TYP, vmm_log::ERROR_SEV, "", -1)) begin
: void'(this.log.text("Attempted to sneak null instance into channel"));
: this.log.end_msg();
: end
: /* synopsys translate_on */
: while (0);
00479: return;
00480: end // obj == null
00481:
00483: if (this.grab_owners.size() &&
00484: (this.check_grab_owners(grabber) == 0)) begin
00485:
: do
: /* synopsys translate_off */
: if (this.log.start_msg(vmm_log::FAILURE_TYP, vmm_log::ERROR_SEV, "", -1)) begin
: void'(this.log.text("Attempted to sneak in a grabbed channel from a scenario that is not a current grabber"));
: this.log.end_msg();
: end
: /* synopsys translate_on */
: while (0);
00486: return;
00487: end
00489:
00490: if (this.is_sunk) return;
00491:
00492: if (offset == -1 || (offset == 0 && this.data.size() == 0))
00493: begin
00494: this.data.push_back(obj);
00495: end
00496: else
00497: begin
00498: int idx = this.index(offset);
00499: if (idx < 0) return;
00500:
00501: this.data.insert(offset, obj);
00502: end // if offset
00503:
00504: if (this.log.start_msg(vmm_log::INTERNAL_TYP, vmm_log::DEBUG_SEV))
00505: begin
00506: $sformat(txt, "New instance added to channel @%0d (level %0d of %0d/%0d)\n%s",
00507: offset, this.level(), this.full, this.empty,
00508: obj.psdisplay(" "));
00509: void'(this.log.text(txt));
00510: this.log.end_msg();
00511: end // if dbg
00512:
00513: this.notify.indicate(PUT, obj);
00514:
00515: if (this.level() >= this.full)
00516: begin
00517: this.full_chan = 1;
00518: this.notify.indicate(FULL);
00519: end
00520:
00521: if (this.level() > this.empty)
00522: begin
00523: this.notify.reset(EMPTY);
00524: end
00525: //recording
00526: if(this.notify.is_on(RECORDING))
00527: begin
00528:
00529: diff_time = $time - this.last_record_time;
00530: if(this.is_put == 1'b0)
00531: this.Xrecord_to_fileX(8'h02,offset,diff_time);
00532: else
00533: this.Xrecord_to_fileX(8'h01,offset,diff_time);
00534:
00535: //save object
00536: obj.save(this.record_fp);
00537: this.last_record_time = $time;
00538: end
00539:
00540: //Playback
00541: if(this.notify.is_on(PLAYBACK) && !this.is_playback)
00542: begin
00543:
: do
: /* synopsys translate_off */
: if (this.log.start_msg(vmm_log::FAILURE_TYP, vmm_log::WARNING_SEV, "", -1)) begin
: void'(this.log.text("vmm_channel::sneak accessed by source while playback is ON"));
: this.log.end_msg();
: end
: /* synopsys translate_on */
: while(0);
00544: end
00545:
00546: -> this.item_added;
00547: endfunction: sneak
00548:
00549:
00550: function vmm_data vmm_channel::unput(int offset=-1);
00551:
00552: time diff_time;
00553:
00554: if (this.size() == 0)
00555: begin
00556:
: do
: /* synopsys translate_off */
: if (this.log.start_msg(vmm_log::FAILURE_TYP, vmm_log::ERROR_SEV, "", -1)) begin
: void'(this.log.text("Cannot unput from an empty channel"));
: this.log.end_msg();
: end
: /* synopsys translate_on */
: while (0);
00557: return null;
00558: end // if size == 0
00559:
00560: if (offset == -1)
00561: begin
00562: unput = this.data.pop_back();
00563: end
00564: else
00565: begin
00566: int idx = this.index(offset);
00567: if (idx < 0)
00568: begin
00569: unput = null;
00570: end
00571: else
00572: begin
00573: unput = this.data[idx];
00574: this.data.delete(idx);
00575: end
00576: end // if offset != -1
00577:
00578: if (unput != null) begin
00579: this.notify.indicate(GOT, unput);
00580: if (this.log.start_msg(vmm_log::INTERNAL_TYP, vmm_log::DEBUG_SEV))
00581: begin
00582: string txt;
00583: $sformat(txt, "Instance unput from channel @%0d (level %0d of %0d/%0d)\n%s",
00584: offset, this.level(), this.full, this.empty,
00585: unput.psdisplay(" "));
00586: void'(this.log.text(txt));
00587: this.log.end_msg();
00588: end // if dbg_lvl
00589:
00590: //recording
00591: if(this.notify.is_on(RECORDING))
00592: begin
00593: diff_time = $time - this.last_record_time;
00594: this.Xrecord_to_fileX(8'h03,offset,diff_time);
00595: this.last_record_time = $time;
00596: end
00597:
00598: end
00599:
00600: this.unblock_producer();
00601: endfunction: unput
00602:
00603: function void vmm_channel::Xrecord_to_fileX(bit [7:0] op_code,
00604: int offset,
00605: time diff_time);
00606:
00607: bit [7:0] bytes[13];
00608: bit [63:0] bit_conv;
00609:
00610: bytes[0] = op_code;
00611:
00612: bit_conv[31:0] = offset;
00613: bytes[1] = bit_conv[7:0];
00614: bytes[2] = bit_conv[15:8];
00615: bytes[3] = bit_conv[23:16];
00616: bytes[4] = bit_conv[31:24];
00617:
00618: bit_conv[63:0] = diff_time;
00619: bytes[5] = bit_conv[7:0];
00620: bytes[6] = bit_conv[15:8];
00621: bytes[7] = bit_conv[23:16];
00622: bytes[8] = bit_conv[31:24];
00623: bytes[9] = bit_conv[39:32];
00624: bytes[10] = bit_conv[47:40];
00625: bytes[11] = bit_conv[55:48];
00626: bytes[12] = bit_conv[63:56];
00627:
00628: //<1byte type><4byte offset><8byte time>
00629: foreach(bytes[i]) begin
00630: $fwrite(this.record_fp, "%c", bytes[i]);
00631: end
00632: //space
00633: if(op_code == 8'h03)
00634: $fwrite(this.record_fp, "\n");
00635: else
00636: $fwrite(this.record_fp, " ");
00637:
00638: endfunction: Xrecord_to_fileX
00639:
00640: task vmm_channel::get1(output vmm_data obj,
00641: input int offset=0);
00642: if (offset == 0)
00643: begin
00644: obj = this.data.pop_front();
00645: end
00646: else
00647: begin
00648: int idx = this.index(offset);
00649: if (idx < 0)
00650: begin
00651: obj = null;
00652: end
00653: else
00654: begin
00655: obj = this.data[idx];
00656: this.data.delete(idx);
00657: end // else if idx < 0
00658: end // else if offset
00659:
00660: if (obj != null)
00661: begin
00662: this.notify.indicate(GOT, obj);
00663: if (this.log.start_msg(vmm_log::INTERNAL_TYP, vmm_log::DEBUG_SEV))
00664: begin
00665: string txt;
00666: $sformat(txt, "New instance removed from channel @%0d (level %0d of %0d/%0d)\n%s",
00667: offset, this.level(), this.full, this.empty,
00668: obj.psdisplay(" "));
00669: void'(this.log.text(txt));
00670: this.log.end_msg();
00671: end // if dbg_lvl
00672:
00673: if (this.tee_on)
00674: begin
00675: this.tee_data.push_back(obj);
00676: -> this.teed;
00677: end // tee_on
00678:
00703: end // if obj != null
00704: endtask: get1
00705:
00706:
00707: task vmm_channel::get(output vmm_data obj,
00708: input int offset=0);
00709: this.block_consumer();
00710: this.get1(obj, offset);
00711: this.unblock_producer();
00712: endtask: get
00713:
00714: task vmm_channel::peek(output vmm_data obj,
00715: input int offset=0);
00716: string txt;
00717: int idx;
00718:
00719: this.block_consumer();
00720:
00721: idx = this.index(offset);
00722: if (idx < 0)
00723: begin
00724: obj = null;
00725: end
00726: else
00727: begin
00728: obj = this.data[idx];
00729: end
00730:
00731: if (obj != null)
00732: begin
00733: this.notify.indicate(PEEKED, obj);
00734: if (this.log.start_msg(vmm_log::INTERNAL_TYP, vmm_log::DEBUG_SEV))
00735: begin
00736: $sformat(txt, "New instance peeked from channel @%0d (level %0d of %0d/%0d)\n%s",
00737: offset, this.level(), this.full, this.empty,
00738: obj.psdisplay(" "));
00739: void'(this.log.text(txt));
00740: this.log.end_msg();
00741: end // if dbg_lvl
00742: end // obj != null
00743:
00744: this.unblock_producer();
00745: endtask: peek
00746:
00747:
00748: task vmm_channel::activate(output vmm_data obj,
00749: input int offset=0);
00750: string txt;
00751:
00752: // Empty the active slot
00753: if (active != null)
00754: void'(this.remove());
00755:
00756: while (this.size() == 0)
00757: @this.item_added;
00758:
00759: if (offset == 0)
00760: begin
00761: obj = this.data.pop_front();
00762: end
00763: else
00764: begin
00765: int idx = this.index(offset);
00766: if (idx < 0)
00767: begin
00768: obj = null;
00769: end
00770: else
00771: begin
00772: obj = this.data[idx];
00773: this.data.delete(idx);
00774: end
00775: end // else if offset == 0
00776:
00777:
00778: if (obj != null)
00779: begin
00780: this.active = obj;
00781: this.active_status = PENDING ;
00782: this.notify.indicate(ACTIVATED, obj);
00783: this.notify.indicate(PEEKED, obj);
00784:
00785: if (this.log.start_msg(vmm_log::INTERNAL_TYP, vmm_log::DEBUG_SEV))
00786: begin
00787: $sformat(txt, "New instance activated from channel @%0d (level %0d of %0d/%0d)\n%s",
00788: offset, this.level(), this.full, this.empty,
00789: obj.psdisplay(" "));
00790: void'(this.log.text(txt));
00791: this.log.end_msg();
00792: end // if dbg_lvl
00793:
00794: if (this.tee_on)
00795: begin
00796: this.tee_data.push_back(obj);
00797: -> this.teed;
00798: end
00799: end // if obj != null
00800: endtask: activate
00801:
00802:
00803: function vmm_data vmm_channel::active_slot();
00804: active_slot = this.active;
00805: endfunction: active_slot
00806:
00807:
00808: function vmm_data vmm_channel::start();
00809: if (this.active == null)
00810: begin
00811:
: do
: /* synopsys translate_off */
: if (this.log.start_msg(vmm_log::FAILURE_TYP, vmm_log::FATAL_SEV, "", -1)) begin
: void'(this.log.text("Cannot start without prior activate"));
: this.log.end_msg();
: end
: /* synopsys translate_on */
: while (0);
00812: return null;
00813: end // if active == null
00814:
00815: if (this.active_status == STARTED)
00816: begin
00817:
: do
: /* synopsys translate_off */
: if (this.log.start_msg(vmm_log::FAILURE_TYP, vmm_log::WARNING_SEV, "", -1)) begin
: void'(this.log.text("Active slot already start'ed"));
: this.log.end_msg();
: end
: /* synopsys translate_on */
: while(0);
00818: end // if STARTED
00819:
00820: this.active_status = STARTED;
00821: this.notify.indicate(ACT_STARTED, this.active);
00822: this.active.notify.indicate(vmm_data::STARTED);
00823: start = this.active;
00824: endfunction: start
00825:
00826:
00827: function vmm_data vmm_channel::complete(vmm_data status=null);
00828: if (this.active == null)
00829: begin
00830:
: do
: /* synopsys translate_off */
: if (this.log.start_msg(vmm_log::FAILURE_TYP, vmm_log::FATAL_SEV, "", -1)) begin
: void'(this.log.text("Cannot complete without prior activate"));
: this.log.end_msg();
: end
: /* synopsys translate_on */
: while (0);
00831: return null;
00832: end
00833: if (this.active_status != STARTED)
00834: begin
00835:
: do
: /* synopsys translate_off */
: if (this.log.start_msg(vmm_log::FAILURE_TYP, vmm_log::WARNING_SEV, "", -1)) begin
: void'(this.log.text("complete called without start"));
: this.log.end_msg();
: end
: /* synopsys translate_on */
: while(0);
00836: end
00837:
00838: this.active_status = COMPLETED;
00839: this.notify.indicate(ACT_COMPLETED, this.active);
00840: this.active.notify.indicate(vmm_data::ENDED, status);
00841: complete = this.active;
00842: endfunction: complete
00843:
00844:
00845: function vmm_data vmm_channel::remove();
00846: if (this.active == null)
00847: begin
00848:
: do
: /* synopsys translate_off */
: if (this.log.start_msg(vmm_log::FAILURE_TYP, vmm_log::FATAL_SEV, "", -1)) begin
: void'(this.log.text("Cannot remove without prior activate"));
: this.log.end_msg();
: end
: /* synopsys translate_on */
: while (0);
00849: return null;
00850: end
00851:
00852: // OK to remove if not started or completed
00853: if (this.active_status == STARTED)
00854: begin
00855:
: do
: /* synopsys translate_off */
: if (this.log.start_msg(vmm_log::FAILURE_TYP, vmm_log::WARNING_SEV, "", -1)) begin
: void'(this.log.text("remove called without complete"));
: this.log.end_msg();
: end
: /* synopsys translate_on */
: while(0);
00856: end
00857:
00858: this.notify.indicate(ACT_REMOVED, this.active);
00859: this.notify.indicate(GOT, this.active);
00860: if (this.active_status != COMPLETED)
00861: begin
00862: this.active.notify.indicate(vmm_data::ENDED);
00863: end
00864: this.active_status = INACTIVE;
00865: remove = this.active;
00866: this.active = null;
00867:
00868: this.unblock_producer();
00869: endfunction: remove
00870:
00871:
00872: function vmm_channel::active_status_e vmm_channel::status();
00873: status = this.active_status;
00874: endfunction: status
00875:
00876:
00877: function bit vmm_channel::tee_mode(bit is_on);
00878: string txt;
00879: if (this.log.start_msg(vmm_log::INTERNAL_TYP, vmm_log::TRACE_SEV))
00880: begin
00881: $sformat(txt, "tee branch turned %0s", (is_on) ? "ON" : "OFF");
00882: void'(this.log.text(txt));
00883: this.log.end_msg();
00884: end
00885:
00886: tee_mode = this.tee_on;
00887: this.tee_on = is_on;
00888: endfunction: tee_mode
00889:
00890:
00891: task vmm_channel::tee(output vmm_data obj);
00892: string txt;
00893: while (this.tee_data.size() == 0)
00894: @this.teed;
00895:
00896: obj = this.tee_data.pop_front();
00897:
00898: if (this.log.start_msg(vmm_log::INTERNAL_TYP, vmm_log::DEBUG_SEV))
00899: begin
00900: $sformat(txt, "New instance teed from channel (level %0d of %0d/%0d)\n%s",
00901: this.level(), this.full, this.empty,
00902: obj.psdisplay(" "));
00903: void'(this.log.text(txt));
00904: this.log.end_msg();
00905: end
00906: endtask: tee
00907:
00908:
00909: function void vmm_channel::connect(vmm_channel downstream);
00910: // Do not disrupt an already-established connection
00911: if (this.downstream == downstream) return;
00912:
00913: // Indicate a new connection
00914: this.downstream = downstream;
00915: -> this.new_connection;
00916: endfunction: connect
00917:
00918:
00919: function vmm_data vmm_channel::for_each(bit reset=0);
00920: if (reset) this.iterator = 0;
00921: else this.iterator++;
00922:
00923: if (this.iterator >= this.data.size()) for_each = null;
00924: else for_each = this.data[this.iterator];
00925: endfunction: for_each
00926:
00927:
00928: function int unsigned vmm_channel::for_each_offset();
00929: for_each_offset = this.iterator;
00930: endfunction: for_each_offset
00931:
00932:
00933: function bit vmm_channel::record(string filename);
00934: if (filename == "")
00935: begin
00936: if(this.notify.is_on(RECORDING))
00937: begin
00938: $fclose(this.record_fp);
00939: this.notify.reset(RECORDING);
00940: return 1;
00941: end
00942: else
00943: begin
00944:
: do
: /* synopsys translate_off */
: if (this.log.start_msg(vmm_log::FAILURE_TYP, vmm_log::WARNING_SEV, "", -1)) begin
: void'(this.log.text("A valid 'filename' must be specified to start recording. vmm_channel::record is ignoring call"));
: this.log.end_msg();
: end
: /* synopsys translate_on */
: while(0);
00945: return 0;
00946: end
00947: end
00948: else
00949: begin
00950: if(this.notify.is_on(RECORDING))
00951: begin
00952:
: do
: /* synopsys translate_off */
: if (this.log.start_msg(vmm_log::FAILURE_TYP, vmm_log::WARNING_SEV, "", -1)) begin
: void'(this.log.text("vmm_channel::record is already started. Ignoring call"));
: this.log.end_msg();
: end
: /* synopsys translate_on */
: while(0);
00953: return 0;
00954: end
00955: else
00956: begin
00957: this.record_fp = $fopen(filename,"wb");
00958: if(this.record_fp == 0)
00959: begin
00960:
: do
: /* synopsys translate_off */
: if (this.log.start_msg(vmm_log::FAILURE_TYP, vmm_log::ERROR_SEV, "", -1)) begin
: void'(this.log.text($psprintf("vmm_channel::record is not able to open file: %s for recording",filename)));
: this.log.end_msg();
: end
: /* synopsys translate_on */
: while (0);
00961: this.record_fp = -1;
00962: return 0;
00963: end
00964: this.notify.indicate(RECORDING);
00965: this.last_record_time = $time;
00966: return 1;
00967: end
00968: end
00969:
00970: endfunction: record
00971:
00973: task vmm_channel::playback(output bit success,
00974: input string filename,
00975: input vmm_data factory,
00976: input bit metered=0,
00977: vmm_scenario grabber=null);
00984: int playback_fp;
00985: bit [7:0] bytes[14];
00986: bit [7:0] op_code;
00987: bit [63:0] bit_conv;
00988: int offset;
00989: time time_delay;
00990:
00992: if (this.grab_owners.size() &&
00993: (this.check_grab_owners(grabber) == 0)) begin
00994:
: do
: /* synopsys translate_off */
: if (this.log.start_msg(vmm_log::FAILURE_TYP, vmm_log::ERROR_SEV, "", -1)) begin
: void'(this.log.text("Cannot playback on a grabbed channel"));
: this.log.end_msg();
: end
: /* synopsys translate_on */
: while (0);
00995: return;
00996: end
00998:
00999: this.notify.indicate(PLAYBACK);
01000:
01001: if(filename == "")
01002: begin
01003: success = 0;
01004:
: do
: /* synopsys translate_off */
: if (this.log.start_msg(vmm_log::FAILURE_TYP, vmm_log::ERROR_SEV, "", -1)) begin
: void'(this.log.text("vmm_channel::playback found null on input argument filename"));
: this.log.end_msg();
: end
: /* synopsys translate_on */
: while (0);
01005: this.notify.reset(PLAYBACK);
01006: this.notify.indicate(PLAYBACK_DONE);
01007: return;
01008: end
01009:
01010: if(factory == null)
01011: begin
01012: success = 0;
01013:
: do
: /* synopsys translate_off */
: if (this.log.start_msg(vmm_log::FAILURE_TYP, vmm_log::ERROR_SEV, "", -1)) begin
: void'(this.log.text("vmm_channel::playback found null on input argument factory"));
: this.log.end_msg();
: end
: /* synopsys translate_on */
: while (0);
01014: this.notify.reset(PLAYBACK);
01015: this.notify.indicate(PLAYBACK_DONE);
01016: return;
01017: end
01018:
01019: playback_fp = $fopen(filename,"rb");
01020:
01021: if(playback_fp == 0)
01022: begin
01023: success = 0;
01024:
: do
: /* synopsys translate_off */
: if (this.log.start_msg(vmm_log::FAILURE_TYP, vmm_log::ERROR_SEV, "", -1)) begin
: void'(this.log.text($psprintf("vmm_channel::playback can not open file %s: file does not exist",filename)));
: this.log.end_msg();
: end
: /* synopsys translate_on */
: while (0);
01025: this.notify.reset(PLAYBACK);
01026: this.notify.indicate(PLAYBACK_DONE);
01027: return;
01028: end
01029:
01030: if($feof(playback_fp))
01031: begin
01032: $fclose(playback_fp);
01033: success = 0;
01034:
: do
: /* synopsys translate_off */
: if (this.log.start_msg(vmm_log::FAILURE_TYP, vmm_log::ERROR_SEV, "", -1)) begin
: void'(this.log.text($psprintf("vmm_channel::playback file %s is empty",filename)));
: this.log.end_msg();
: end
: /* synopsys translate_on */
: while (0);
01035: this.notify.reset(PLAYBACK);
01036: this.notify.indicate(PLAYBACK_DONE);
01037: return;
01038: end
01039:
01040: success = 1;
01041:
01042: this.lock(SOURCE);
01043:
01044: while(!$feof(playback_fp))
01045: begin
01046: foreach(bytes[i])
01047: begin
01048: int c = $fgetc(playback_fp);
01049: bytes[i] = c;
01050: end
01051:
01052: if(bytes[0] == 8'hff)
01053: break;
01054:
01055: op_code = bytes[0];
01056: offset = {bytes[4],bytes[3],bytes[2],bytes[1]};
01057: time_delay = {bytes[12],bytes[11],bytes[10],bytes[9],bytes[8],bytes[7],bytes[6],bytes[5]};
01058:
01059: if(op_code == 8'h01)
01060: begin
01061: if(!factory.load(playback_fp))
01062: begin
01063:
: do
: /* synopsys translate_off */
: if (this.log.start_msg(vmm_log::FAILURE_TYP, vmm_log::ERROR_SEV, "", -1)) begin
: void'(this.log.text("vmm_data::load failed"));
: this.log.end_msg();
: end
: /* synopsys translate_on */
: while (0);
01064: success = 0;
01065: break;
01066: end
01067:
01068: if(metered)
01069: begin
01070: #time_delay;
01071: this.is_playback = 1'b1;
01073: this.sneak(factory.copy(), offset, grabber);
01077: this.is_playback = 1'b0;
01078: end
01079: else
01081: this.XputX(factory.copy(), offset, grabber);
01085: end
01086: else if(op_code == 8'h02)
01087: begin
01088: if(!factory.load(playback_fp))
01089: begin
01090:
: do
: /* synopsys translate_off */
: if (this.log.start_msg(vmm_log::FAILURE_TYP, vmm_log::ERROR_SEV, "", -1)) begin
: void'(this.log.text("vmm_data::load failed"));
: this.log.end_msg();
: end
: /* synopsys translate_on */
: while (0);
01091: success = 0;
01092: break;
01093: end
01094: if(metered)
01095: #time_delay;
01096:
01097: this.is_playback = 1'b1;
01099: this.sneak(factory.copy(),offset, grabber);
01103: this.is_playback = 1'b0;
01104: end
01105: else if(op_code == 8'h03)
01106: begin
01107: if(metered)
01108: #time_delay;
01109: if(this.unput(offset) == null)
01110:
: do
: /* synopsys translate_off */
: if (this.log.start_msg(vmm_log::FAILURE_TYP, vmm_log::WARNING_SEV, "", -1)) begin
: void'(this.log.text("vmm_channel::playback found improper offset for unput operation"));
: this.log.end_msg();
: end
: /* synopsys translate_on */
: while(0);
01111: end
01112: else
01113: begin
01114:
: do
: /* synopsys translate_off */
: if (this.log.start_msg(vmm_log::FAILURE_TYP, vmm_log::ERROR_SEV, "", -1)) begin
: void'(this.log.text($psprintf("vmm_channel::playback file %s is corrupted",filename)));
: this.log.end_msg();
: end
: /* synopsys translate_on */
: while (0);
01115: success = 0;
01116: break;
01117: end
01118: end
01119:
01120: $fclose(playback_fp);
01121: this.unlock(SOURCE);
01122: this.notify.reset(PLAYBACK);
01123: this.notify.indicate(PLAYBACK_DONE);
01124:
01125: endtask: playback
01126:
01127:
01128: function int vmm_channel::index(int offset);
01129: string txt;
01130: index = offset;
01131: if (offset < 0) index += this.data.size() + offset + 1;
01132: if (index < 0 || index >= this.data.size())
01133: begin
01134: if (this.log.start_msg(vmm_log::FAILURE_TYP, vmm_log::FATAL_SEV))
01135: begin
01136: $sformat(txt, "Invalid offset %0d specified. Not in {0:%0d}.\n",
01137: offset, this.data.size()-1);
01138: void'(this.log.text(txt));
01139: this.log.end_msg();
01140: end
01141: index = -1;
01142: end
01143: endfunction: index
01144:
01145:
01147: task vmm_channel::block_producer(vmm_scenario grabber);
01148: while (this.full_chan || this.is_locked(SOURCE) ||
01149: (this.grab_owners.size() &&
01150: (this.check_grab_owners(grabber) == 0))) begin
01151: fork
01152: begin
01153: if (this.grab_owners.size() &&
01154: (this.check_grab_owners(grabber) == 0)) begin
01155: this.notify.wait_for(vmm_channel::UNGRABBED);
01156: end
01157: end
01158: begin
01159: if(this.full_chan || this.is_locked(SOURCE)) begin
01160: @this.item_taken;
01161: end
01162: end
01163: join
01164: end
01170: endtask : block_producer
01171:
01172:
01173: task vmm_channel::block_consumer();
01174: while (this.size() == 0 || this.is_locked(SINK))
01175: @this.item_added;
01176: endtask: block_consumer
01177:
01178:
01179: function void vmm_channel::unblock_producer();
01180: if (this.level() <= this.empty)
01181: begin
01182: this.full_chan = 0;
01183: this.notify.indicate(EMPTY);
01184: end
01185:
01186: if (this.level() < this.full)
01187: begin
01188: this.notify.reset(FULL);
01189: end
01190:
01191: -> this.item_taken;
01192: endfunction: unblock_producer
01193:
01194:
01195: function vmm_xactor vmm_channel::get_producer();
01196: get_producer = this.producer;
01197: endfunction: get_producer
01198:
01199:
01200: function vmm_xactor vmm_channel::get_consumer();
01201: get_consumer = this.consumer;
01202: endfunction: get_consumer
01203:
01204:
01205: function void vmm_channel::set_producer(vmm_xactor producer);
01206: if (producer == null && this.producer == null) begin
01207:
: do
: /* synopsys translate_off */
: if (this.log.start_msg(vmm_log::FAILURE_TYP, vmm_log::ERROR_SEV, "", -1)) begin
: void'(this.log.text("Attempted to set null producer"));
: this.log.end_msg();
: end
: /* synopsys translate_on */
: while (0);
01208: return;
01209: end
01210:
01211: if (this.producer == producer) return;
01212:
01213: if (this.producer != null) begin
01214: if(producer != null) begin
01215:
: do
: /* synopsys translate_off */
: if (this.log.start_msg(vmm_log::FAILURE_TYP, vmm_log::WARNING_SEV, "", -1)) begin
: void'(this.log.text("Producer is already set"));
: this.log.end_msg();
: end
: /* synopsys translate_on */
: while(0);
01216: end
01217: foreach(this.producer.Xoutput_chansX[i]) begin
01218: if (this.producer.Xoutput_chansX[i] == this) begin
01219: this.producer.Xoutput_chansX.delete(i);
01220: break;
01221: end
01222: end
01223: end
01224: this.producer = producer;
01225: if(producer != null) begin
01226: this.producer.Xoutput_chansX.push_back(this);
01227: end
01228: endfunction: set_producer
01229:
01230:
01231: function void vmm_channel::set_consumer(vmm_xactor consumer);
01232: if (consumer == null && this.consumer == null) begin
01233:
: do
: /* synopsys translate_off */
: if (this.log.start_msg(vmm_log::FAILURE_TYP, vmm_log::ERROR_SEV, "", -1)) begin
: void'(this.log.text("Attempted to set null consumer"));
: this.log.end_msg();
: end
: /* synopsys translate_on */
: while (0);
01234: return;
01235: end
01236:
01237: if (this.consumer == consumer) return;
01238:
01239: if (this.consumer != null) begin
01240: if (consumer != null) begin
01241:
: do
: /* synopsys translate_off */
: if (this.log.start_msg(vmm_log::FAILURE_TYP, vmm_log::WARNING_SEV, "", -1)) begin
: void'(this.log.text("Consumer is already set"));
: this.log.end_msg();
: end
: /* synopsys translate_on */
: while(0);
01242: end
01243: foreach(this.consumer.Xinput_chansX[i]) begin
01244: if (this.consumer.Xinput_chansX[i] == this) begin
01245: this.consumer.Xinput_chansX.delete(i);
01246: break;
01247: end
01248: end
01249: end
01250: this.consumer = consumer;
01251: if (consumer != null) begin
01252: this.consumer.Xinput_chansX.push_back(this);
01253: end
01254: endfunction: set_consumer
01255:
01256:
01257: function void vmm_channel::kill();
01258: if (this.consumer != null) begin
01259: foreach(this.consumer.Xinput_chansX[i]) begin
01260: if(this.consumer.Xinput_chansX[i] == this) begin
01261: this.consumer.Xinput_chansX.delete(i);
01262: break;
01263: end
01264: end
01265: end
01266:
01267: if (this.producer != null) begin
01268: foreach(this.producer.Xoutput_chansX[i]) begin
01269: if (this.producer.Xoutput_chansX[i] == this) begin
01270: this.producer.Xoutput_chansX.delete(i);
01271: break;
01272: end
01273: end
01274: end
01275:
01276: this.downstream = null;
01277: -> this.new_connection;
01278:
01279: this.producer = null;
01280: this.consumer = null;
01281:
01282: if (!this.shared_log) this.log.kill();
01283: endfunction: kill
01284:
01285:
01286:
01287:
01288:
01324: