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_channel.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: // ToDo: Fill level based on bytes 00024: 00025: function vmm_channel::new(string name, 00026: string inst, 00027: int unsigned full, 00028: int unsigned empty, 00029: bit fill_as_bytes); 00033: 00034: if (this.one_log) begin 00035: if (this.shared_log == null) begin 00036: this.shared_log = new("VMM Channel", "[shared]"); 00037: end 00038: this.log = shared_log; 00039: end else this.log = new(name, inst); 00040: 00041: this.notify = new(this.log); 00042: this.notify.configure(FULL, vmm_notify::ON_OFF); 00043: this.notify.configure(EMPTY, vmm_notify::ON_OFF); 00044: this.notify.configure(PUT); 00045: this.notify.configure(GOT); 00046: this.notify.configure(PEEKED); 00047: this.notify.configure(ACTIVATED); 00048: this.notify.configure(ACT_STARTED); 00049: this.notify.configure(ACT_COMPLETED); 00050: this.notify.configure(ACT_REMOVED); 00051: this.notify.configure(LOCKED); 00052: this.notify.configure(UNLOCKED); 00053: 00054: if (full <= 0) full = 1; 00055: if (empty < 0 || empty > full) empty = full; 00056: 00057: this.full = full; 00058: this.empty = empty; 00059: this.is_sunk = 0; 00060: 00061: this.active = null; 00062: this.active_status = INACTIVE; 00063: this.tee_on = 0; 00064: this.downstream = null; 00065: this.locks = 2'b00; 00066: 00067: this.full_chan = 0; 00068: this.notify.indicate(EMPTY); 00069: 00070: this.iterator = 0; 00071: 00072: // 00073: // Thread to manage connection requests 00074: // 00075: fork: connection_requests 00076: while (1) 00077: begin : new_while_loop 00078: vmm_data data = null; 00079: 00080: // Broken connection? 00081: if (this.downstream != null) 00082: begin 00083: if (this.log.start_msg(vmm_log::INTERNAL_TYP, vmm_log::TRACE_SEV)) 00084: begin 00085: string txt; 00086: txt = {"Channel connection established: ", 00087: this.log.get_name(), 00088: "(", this.log.get_instance(), ") -> ", 00089: this.downstream.log.get_name(), 00090: "(", this.downstream.log.get_instance(), ")"}; 00091: 00092: this.log.text(txt); 00093: this.log.end_msg(); 00094: end // if debug level 00095: 00096: // Fork the data mover thread 00097: fork 00098: while (1) 00099: begin : inner_while_loop 00100: // Simple blocking interface 00101: data = null; 00102: this.peek(data); 00103: this.downstream.put(data); 00104: this.get(data); 00105: end // inner_while_loop 00106: join_none 00107: end // if downstream != null 00108: 00109: // Wait for new connection requests 00110: @this.new_connection; 00111: 00112: // Stop the data mover thread 00113: disable fork; 00114: 00115: // Remove any datum that was forwarded 00116: // to the downstream channel but not removed 00117: // from this channel because of the blocking 00118: // model. Otherwise, the same datum will be 00119: // obtained from this channel twice. 00120: if (data != null) this.get(data); 00121: end // while (1) 00122: join_none // connection_requests 00123: endfunction : new 00124: 00125: 00126: function void vmm_channel::reconfigure(int full, 00127: int empty, 00128: logic fill_as_bytes); 00129: if (full < 0) full = this.full; 00130: if (full == 0) full = 1; 00131: if (empty < 0) empty = this.empty; 00132: 00133: if (full < empty) 00134: begin 00135: : do : if (this.log.start_msg(vmm_log::FAILURE_TYP, vmm_log::ERROR_SEV)) begin : void'(this.log.text("Cannot reconfigure channel with FULL < EMPTY")); : this.log.end_msg(); : end : while (0); 00136: return; 00137: end 00138: 00139: this.full = full; 00140: this.empty = empty; 00141: 00142: if (this.level() >= this.full) 00143: begin 00144: this.full_chan = 1; 00145: this.notify.indicate(FULL); 00146: this.notify.reset(EMPTY); 00147: end 00148: else if (this.level() <= this.empty) 00149: begin 00150: this.full_chan = 0; 00151: -> this.item_taken; 00152: this.notify.indicate(EMPTY); 00153: this.notify.reset(FULL); 00154: end 00155: else 00156: begin 00157: this.full_chan = 0; 00158: -> this.item_taken; 00159: this.notify.reset(EMPTY); 00160: this.notify.reset(FULL); 00161: end 00162: endfunction: reconfigure 00163: 00164: 00165: function int unsigned vmm_channel::full_level(); 00166: full_level = this.full; 00167: endfunction: full_level 00168: 00169: 00170: function int unsigned vmm_channel::empty_level(); 00171: empty_level = this.empty; 00172: endfunction: empty_level 00173: 00174: 00175: function int unsigned vmm_channel::level(); 00176: level = this.data.size() + ((this.active == null) ? 0 : 1); 00177: endfunction: level 00178: 00179: 00180: function int unsigned vmm_channel::size(); 00181: size = this.data.size() + ((this.active == null) ? 0 : 1); 00182: endfunction : size 00183: 00184: 00185: function bit vmm_channel::is_full(); 00186: is_full = full_chan; 00187: endfunction : is_full 00188: 00189: 00190: function void vmm_channel::flush(); 00191: vmm_data obj; 00192: if (this.downstream != null) 00193: this.downstream.flush(); 00194: 00201: // This works in VCS 2008.03 00202: this.data = '{}; 00203: this.tee_data = '{}; 00205: full_chan = 0; 00206: this.active = null; 00207: this.active_status = INACTIVE ; 00208: -> this.item_taken; 00209: this.notify.reset(FULL); 00210: this.notify.indicate(EMPTY); 00211: endfunction: flush 00212: 00213: 00214: function void vmm_channel::sink(); 00215: this.flush(); 00216: this.is_sunk = 1; 00217: endfunction: sink 00218: 00219: 00220: function void vmm_channel::flow(); 00221: this.is_sunk = 0; 00222: endfunction: flow 00223: 00224: 00225: function void vmm_channel::reset(); 00226: this.flush(); 00227: endfunction: reset 00228: 00229: 00230: function void vmm_channel::lock(bit [1:0] who); 00231: this.locks |= who; 00232: this.notify.indicate(LOCKED); 00233: endfunction: lock 00234: 00235: 00236: function void vmm_channel::unlock(bit [1:0] who); 00237: this.locks &= ~who; 00238: this.notify.indicate(UNLOCKED); 00239: // May cause a consumer or producer to unblock 00240: -> this.item_taken; 00241: -> this.item_added; 00242: endfunction: unlock 00243: 00244: 00245: function bit vmm_channel::is_locked(bit [1:0] who); 00246: is_locked = (this.locks & who) ? 1 : 0; 00247: endfunction: is_locked 00248: 00249: 00250: function void vmm_channel::display(string prefix); 00251: $display(this.psdisplay(prefix)); 00252: endfunction: display 00253: 00254: 00255: function string vmm_channel::psdisplay(string prefix); 00256: $sformat(psdisplay, "%sChannel %s(%s): Level = %0d of %0d (empty=%0d)", 00257: prefix, this.log.get_name(), this.log.get_instance(), 00258: this.level(), this.full, this.empty); 00259: case (this.locks) 00260: SOURCE+SINK : psdisplay = {psdisplay, " [src+snk locked]"}; 00261: SOURCE: psdisplay = {psdisplay, " [src locked]"}; 00262: SINK: psdisplay = {psdisplay, " [snk locked]"}; 00263: endcase 00264: if (this.is_sunk) psdisplay = {psdisplay, " (sunk)"}; 00265: 00266: foreach(this.data[i]) begin 00267: $sformat(psdisplay, "%s\n%s", psdisplay, this.data[i].psdisplay($psprintf("%s [%0d] ", 00268: prefix, i))); 00269: end 00270: endfunction: psdisplay 00271: 00272: 00274: task vmm_channel::put(vmm_data obj, 00275: int offset); 00276: if (obj == null) 00277: begin 00278: : do : if (this.log.start_msg(vmm_log::FAILURE_TYP, vmm_log::ERROR_SEV)) begin : void'(this.log.text("Attempted to put null instance into channel")); : this.log.end_msg(); : end : while (0); 00279: return; 00280: end // if obj == null 00281: 00282: this.block_producer(); 00283: this.sneak(obj, offset); 00284: this.block_producer(); 00285: endtask: put 00287: 00288: function void vmm_channel::sneak(vmm_data obj, 00289: int offset); 00290: string txt; 00291: 00292: if (obj == null) 00293: begin 00294: : do : if (this.log.start_msg(vmm_log::FAILURE_TYP, vmm_log::ERROR_SEV)) begin : void'(this.log.text("Attempted to sneak null instance into channel")); : this.log.end_msg(); : end : while (0); 00295: return; 00296: end // obj == null 00297: 00298: if (this.is_sunk) return; 00299: 00300: if (offset == -1 || (offset == 0 && this.data.size() == 0)) 00301: begin 00302: this.data.push_back(obj); 00303: end 00304: else 00305: begin 00306: int idx = this.index(offset); 00307: if (idx < 0) return; 00308: 00309: this.data.insert(offset, obj); 00310: end // if offset 00311: 00312: if (this.log.start_msg(vmm_log::INTERNAL_TYP, vmm_log::DEBUG_SEV)) 00313: begin 00314: $sformat(txt, "New instance added to channel @%0d (level %0d of %0d/%0d)\n%s", 00315: offset, this.level(), this.full, this.empty, 00316: obj.psdisplay(" ")); 00317: this.log.text(txt); 00318: this.log.end_msg(); 00319: end // if dbg 00320: 00321: this.notify.indicate(PUT, obj); 00322: 00323: if (this.level() >= this.full) 00324: begin 00325: this.full_chan = 1; 00326: this.notify.indicate(FULL); 00327: end 00328: 00329: if (this.level() > this.empty) 00330: begin 00331: this.notify.reset(EMPTY); 00332: end 00333: 00334: -> this.item_added; 00335: endfunction: sneak 00336: 00337: 00338: function vmm_data vmm_channel::unput(int offset); 00339: if (this.size() == 0) 00340: begin 00341: : do : if (this.log.start_msg(vmm_log::FAILURE_TYP, vmm_log::ERROR_SEV)) begin : void'(this.log.text("Cannot unput from an empty channel")); : this.log.end_msg(); : end : while (0); 00342: return null; 00343: end // if size == 0 00344: 00345: if (offset == -1) 00346: begin 00347: unput = this.data.pop_back(); 00348: end 00349: else 00350: begin 00351: int idx = this.index(offset); 00352: if (idx < 0) 00353: begin 00354: unput = null; 00355: end 00356: else 00357: begin 00358: unput = this.data[idx]; 00359: this.data.delete(idx); 00360: end 00361: end // if offset != -1 00362: 00363: if (unput != null) begin 00364: this.notify.indicate(GOT, unput); 00365: if (this.log.start_msg(vmm_log::INTERNAL_TYP, vmm_log::DEBUG_SEV)) 00366: begin 00367: string txt; 00368: $sformat(txt, "Instance unput from channel @%0d (level %0d of %0d/%0d)\n%s", 00369: offset, this.level(), this.full, this.empty, 00370: unput.psdisplay(" ")); 00371: this.log.text(txt); 00372: this.log.end_msg(); 00373: end // if dbg_lvl 00374: end 00375: 00376: this.unblock_producer(); 00377: endfunction: unput 00378: 00379: 00380: task vmm_channel::get1(output vmm_data obj, 00381: input int offset); 00382: if (offset == 0) 00383: begin 00384: obj = this.data.pop_front(); 00385: end 00386: else 00387: begin 00388: int idx = this.index(offset); 00389: if (idx < 0) 00390: begin 00391: obj = null; 00392: end 00393: else 00394: begin 00395: obj = this.data[idx]; 00396: this.data.delete(idx); 00397: end // else if idx < 0 00398: end // else if offset 00399: 00400: if (obj != null) 00401: begin 00402: this.notify.indicate(GOT, obj); 00403: if (this.log.start_msg(vmm_log::INTERNAL_TYP, vmm_log::DEBUG_SEV)) 00404: begin 00405: string txt; 00406: $sformat(txt, "New instance removed from channel @%0d (level %0d of %0d/%0d)\n%s", 00407: offset, this.level(), this.full, this.empty, 00408: obj.psdisplay(" ")); 00409: this.log.text(txt); 00410: this.log.end_msg(); 00411: end // if dbg_lvl 00412: 00413: if (this.tee_on) 00414: begin 00415: this.tee_data.push_back(obj); 00416: -> this.teed; 00417: end // tee_on 00418: 00443: end // if obj != null 00444: endtask: get1 00445: 00446: 00447: task vmm_channel::get(output vmm_data obj, 00448: input int offset); 00449: this.block_consumer(); 00450: this.get1(obj, offset); 00451: this.unblock_producer(); 00452: endtask: get 00453: 00454: task vmm_channel::peek(output vmm_data obj, 00455: input int offset); 00456: string txt; 00457: int idx; 00458: 00459: this.block_consumer(); 00460: 00461: idx = this.index(offset); 00462: if (idx < 0) 00463: begin 00464: obj = null; 00465: end 00466: else 00467: begin 00468: obj = this.data[idx]; 00469: end 00470: 00471: if (obj != null) 00472: begin 00473: this.notify.indicate(PEEKED, obj); 00474: if (this.log.start_msg(vmm_log::INTERNAL_TYP, vmm_log::DEBUG_SEV)) 00475: begin 00476: $sformat(txt, "New instance peeked from channel @%0d (level %0d of %0d/%0d)\n%s", 00477: offset, this.level(), this.full, this.empty, 00478: obj.psdisplay(" ")); 00479: this.log.text(txt); 00480: this.log.end_msg(); 00481: end // if dbg_lvl 00482: end // obj != null 00483: 00484: this.unblock_producer(); 00485: endtask: peek 00486: 00487: 00488: task vmm_channel::activate(output vmm_data obj, 00489: input int offset); 00490: string txt; 00491: 00492: // Empty the active slot 00493: if (active != null) 00494: this.remove(); 00495: 00496: while (this.size() == 0) 00497: @this.item_added; 00498: 00499: if (offset == 0) 00500: begin 00501: obj = this.data.pop_front(); 00502: end 00503: else 00504: begin 00505: int idx = this.index(offset); 00506: if (idx < 0) 00507: begin 00508: obj = null; 00509: end 00510: else 00511: begin 00512: obj = this.data[idx]; 00513: this.data.delete(idx); 00514: end 00515: end // else if offset == 0 00516: 00517: 00518: if (obj != null) 00519: begin 00520: this.active = obj; 00521: this.active_status = PENDING ; 00522: this.notify.indicate(ACTIVATED, obj); 00523: this.notify.indicate(PEEKED, obj); 00524: 00525: if (this.log.start_msg(vmm_log::INTERNAL_TYP, vmm_log::DEBUG_SEV)) 00526: begin 00527: $sformat(txt, "New instance activated from channel @%0d (level %0d of %0d/%0d)\n%s", 00528: offset, this.level(), this.full, this.empty, 00529: obj.psdisplay(" ")); 00530: this.log.text(txt); 00531: this.log.end_msg(); 00532: end // if dbg_lvl 00533: 00534: if (this.tee_on) 00535: begin 00536: this.tee_data.push_back(obj); 00537: -> this.teed; 00538: end 00539: end // if obj != null 00540: endtask: activate 00541: 00542: 00543: function vmm_data vmm_channel::active_slot(); 00544: active_slot = this.active; 00545: endfunction: active_slot 00546: 00547: 00548: function vmm_data vmm_channel::start(); 00549: if (this.active == null) 00550: begin 00551: : do : if (this.log.start_msg(vmm_log::FAILURE_TYP, vmm_log::FATAL_SEV)) begin : void'(this.log.text("Cannot start() without prior activate()")); : this.log.end_msg(); : end : while (0); 00552: return null; 00553: end // if active == null 00554: 00555: if (this.active_status == STARTED) 00556: begin 00557: : do : if (this.log.start_msg(vmm_log::FAILURE_TYP, vmm_log::WARNING_SEV)) begin : void'(this.log.text("Active slot already start()'ed")); : this.log.end_msg(); : end : while(0); 00558: end // if STARTED 00559: 00560: this.active_status = STARTED; 00561: this.notify.indicate(ACT_STARTED, this.active); 00562: this.active.notify.indicate(vmm_data::STARTED); 00563: start = this.active; 00564: endfunction: start 00565: 00566: 00567: function vmm_data vmm_channel::complete(vmm_data status); 00568: if (this.active == null) 00569: begin 00570: : do : if (this.log.start_msg(vmm_log::FAILURE_TYP, vmm_log::FATAL_SEV)) begin : void'(this.log.text("Cannot complete() without prior activate()")); : this.log.end_msg(); : end : while (0); 00571: return null; 00572: end 00573: if (this.active_status != STARTED) 00574: begin 00575: : do : if (this.log.start_msg(vmm_log::FAILURE_TYP, vmm_log::WARNING_SEV)) begin : void'(this.log.text("complete() called without start()")); : this.log.end_msg(); : end : while(0); 00576: end 00577: 00578: this.active_status = COMPLETED; 00579: this.notify.indicate(ACT_COMPLETED, this.active); 00580: this.active.notify.indicate(vmm_data::ENDED, status); 00581: complete = this.active; 00582: endfunction: complete 00583: 00584: 00585: function vmm_data vmm_channel::remove(); 00586: if (this.active == null) 00587: begin 00588: : do : if (this.log.start_msg(vmm_log::FAILURE_TYP, vmm_log::FATAL_SEV)) begin : void'(this.log.text("Cannot remove() without prior activate()")); : this.log.end_msg(); : end : while (0); 00589: return null; 00590: end 00591: 00592: // OK to remove if not started or completed 00593: if (this.active_status == STARTED) 00594: begin 00595: : do : if (this.log.start_msg(vmm_log::FAILURE_TYP, vmm_log::WARNING_SEV)) begin : void'(this.log.text("remove() called without complete()")); : this.log.end_msg(); : end : while(0); 00596: end 00597: 00598: this.notify.indicate(ACT_REMOVED, this.active); 00599: this.notify.indicate(GOT, this.active); 00600: if (this.active_status != COMPLETED) 00601: begin 00602: this.active.notify.indicate(vmm_data::ENDED); 00603: end 00604: this.active_status = INACTIVE; 00605: remove = this.active; 00606: this.active = null; 00607: 00608: this.unblock_producer(); 00609: endfunction: remove 00610: 00611: 00612: function vmm_channel::active_status_e vmm_channel::status(); 00613: status = this.active_status; 00614: endfunction: status 00615: 00616: 00617: function bit vmm_channel::tee_mode(bit is_on); 00618: string txt; 00619: if (this.log.start_msg(vmm_log::INTERNAL_TYP, vmm_log::TRACE_SEV)) 00620: begin 00621: $sformat(txt, "tee branch turned %0s", (is_on) ? "ON" : "OFF"); 00622: this.log.text(txt); 00623: this.log.end_msg(); 00624: end 00625: 00626: tee_mode = this.tee_on; 00627: this.tee_on = is_on; 00628: endfunction: tee_mode 00629: 00630: 00631: task vmm_channel::tee(output vmm_data obj); 00632: string txt; 00633: while (this.tee_data.size() == 0) 00634: @this.teed; 00635: 00636: obj = this.tee_data.pop_front(); 00637: 00638: if (this.log.start_msg(vmm_log::INTERNAL_TYP, vmm_log::DEBUG_SEV)) 00639: begin 00640: $sformat(txt, "New instance teed from channel (level %0d of %0d/%0d)\n%s", 00641: this.level(), this.full, this.empty, 00642: obj.psdisplay(" ")); 00643: this.log.text(txt); 00644: this.log.end_msg(); 00645: end 00646: endtask: tee 00647: 00648: 00649: function void vmm_channel::connect(vmm_channel downstream); 00650: // Do not disrupt an already-established connection 00651: if (this.downstream == downstream) return; 00652: 00653: // Indicate a new connection 00654: this.downstream = downstream; 00655: -> this.new_connection; 00656: endfunction: connect 00657: 00658: 00659: function vmm_data vmm_channel::for_each(bit reset); 00660: if (reset) this.iterator = 0; 00661: else this.iterator++; 00662: 00663: if (this.iterator >= this.data.size()) for_each = null; 00664: else for_each = this.data[this.iterator]; 00665: endfunction: for_each 00666: 00667: 00668: function int unsigned vmm_channel::for_each_offset(); 00669: for_each_offset = this.iterator; 00670: endfunction: for_each_offset 00671: 00672: 00673: function bit vmm_channel::record(string filename); 00674: if (filename == "") 00675: begin 00676: return 1; 00677: end 00678: 00679: : do : if (this.log.start_msg(vmm_log::FAILURE_TYP, vmm_log::WARNING_SEV)) begin : void'(this.log.text("vmm_channel::record() not implemented yet")); : this.log.end_msg(); : end : while(0); 00680: record = 0; 00681: endfunction: record 00682: 00683: 00684: task vmm_channel::playback(output bit success, 00685: input string filename, 00686: input vmm_data loader, 00687: input bit metered); 00688: : do : if (this.log.start_msg(vmm_log::FAILURE_TYP, vmm_log::FATAL_SEV)) begin : void'(this.log.text("vmm_channel::playback() not implemented yet")); : this.log.end_msg(); : end : while (0); 00689: success = 0; 00690: endtask: playback 00691: 00692: 00693: function int vmm_channel::index(int offset); 00694: string txt; 00695: index = offset; 00696: if (offset < 0) index += this.data.size() + offset + 1; 00697: if (index < 0 || index >= this.data.size()) 00698: begin 00699: if (this.log.start_msg(vmm_log::FAILURE_TYP, vmm_log::FATAL_SEV)) 00700: begin 00701: $sformat(txt, "Invalid offset %0d specified. Not in {0:%0d}.\n", 00702: offset, this.data.size()-1); 00703: this.log.text(txt); 00704: this.log.end_msg(); 00705: end 00706: index = -1; 00707: end 00708: endfunction: index 00709: 00710: 00712: task vmm_channel::block_producer(); 00713: while (this.full_chan || this.is_locked(SOURCE)) 00714: @this.item_taken; 00715: endtask : block_producer 00716: 00717: 00718: task vmm_channel::block_consumer(); 00719: while (this.size() == 0 || this.is_locked(SINK)) 00720: @this.item_added; 00721: endtask: block_consumer 00723: 00724: 00725: function void vmm_channel::unblock_producer(); 00726: if (this.level() <= this.empty) 00727: begin 00728: this.full_chan = 0; 00729: this.notify.indicate(EMPTY); 00730: end 00731: 00732: if (this.level() < this.full) 00733: begin 00734: this.notify.reset(FULL); 00735: end 00736: 00737: -> this.item_taken; 00738: endfunction: unblock_producer 00739: 00740: 00741: 00742: 00743: 00744: 00780: