00001 //------------------------------------------------------------------------------ 00002 // Copyright 2007-2008 Mentor Graphics Corporation 00003 // Copyright 2007-2008 Cadence Design Systems, Inc. 00004 // All Rights Reserved Worldwide 00005 // 00006 // Licensed under the Apache License, Version 2.0 (the "License"); you may not 00007 // use this file except in compliance with the License. You may obtain a copy 00008 // of the License at 00009 // 00010 // http://www.apache.org/licenses/LICENSE-2.0 00011 // 00012 // Unless required by applicable law or agreed to in writing, software 00013 // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 00014 // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 00015 // License for the specific language governing permissions and limitations 00016 // under the License. 00017 //------------------------------------------------------------------------------ 00018 00019 typedef enum { 00020 OVM_PORT , 00021 OVM_EXPORT , 00022 OVM_IMPLEMENTATION 00023 } ovm_port_type_e; 00024 00025 `const int OVM_UNBOUNDED_CONNECTIONS = -1; 00026 `const string s_connection_error_id = "Connection Error"; 00027 `const string s_connection_warning_id = "Connection Warning"; 00028 `const string s_spaces = " "; 00029 00030 typedef class ovm_port_component_base; 00031 typedef ovm_port_component_base ovm_port_list[string]; 00032 00033 //------------------------------------------------------------------------------ 00034 // 00035 // CLASS: ovm_port_component_base 00036 // 00037 //------------------------------------------------------------------------------ 00038 // This class defines an interface for obtaining a port's connectivity lists 00039 // after or during the end_of_elaboration phase. The sub-class, 00040 // ovm_port_component #(PORT), implements this interface. 00041 // 00042 // The connectivity lists are returned in the form of handles to objects of this 00043 // type. This allowing traversal of any port's fan-out and fan-in network 00044 // through recursive calls to get_connected_to and get_provided_to. Each port's 00045 // full name and type name can be retrieved using get_full_name and 00046 // get_type_name methods inherited from ovm_component. 00047 //------------------------------------------------------------------------------ 00048 00049 virtual class ovm_port_component_base extends ovm_component; 00050 00051 function new (string name, ovm_component parent); 00052 super.new(name,parent); 00053 endfunction 00054 00055 pure virtual function void get_connected_to(ref ovm_port_list list); 00056 pure virtual function void get_provided_to(ref ovm_port_list list); 00057 00058 pure virtual function bit is_port(); 00059 pure virtual function bit is_export(); 00060 pure virtual function bit is_imp(); 00061 00062 endclass 00063 00064 00065 //------------------------------------------------------------------------------ 00066 // 00067 // CLASS: ovm_port_component #(PORT) 00068 // 00069 //------------------------------------------------------------------------------ 00070 // See description of ovm_port_base for information about this class 00071 //------------------------------------------------------------------------------ 00072 00073 00074 class ovm_port_component #(type PORT=ovm_void) extends ovm_port_component_base; 00075 00076 PORT m_port; 00077 00078 function new (string name, ovm_component parent, PORT port); 00079 super.new(name,parent); 00080 if (port == null) 00081 ovm_report_fatal("Bad usage", "Null handle to port"); 00082 m_port = port; 00083 endfunction 00084 00085 virtual function string get_type_name(); 00086 if(m_port == null) return "ovm_port_component"; 00087 return m_port.get_type_name(); 00088 endfunction 00089 00090 virtual function void resolve_bindings(); 00091 m_port.resolve_bindings(); 00092 endfunction 00093 00094 function PORT get_port(); 00095 return m_port; 00096 endfunction 00097 00098 function void do_display (int max_level=-1, int level=0, 00099 bit display_connectors=0); 00100 m_port.do_display(max_level,level,display_connectors); 00101 endfunction 00102 00103 virtual function void get_connected_to(ref ovm_port_list list); 00104 m_port.get_connected_to(list); 00105 endfunction 00106 00107 virtual function void get_provided_to(ref ovm_port_list list); 00108 m_port.get_provided_to(list); 00109 endfunction 00110 00111 function bit is_port (); 00112 return m_port.is_port(); 00113 endfunction 00114 00115 function bit is_export (); 00116 return m_port.is_export(); 00117 endfunction 00118 00119 function bit is_imp (); 00120 return m_port.is_imp(); 00121 endfunction 00122 00123 endclass 00124 00125 00126 //------------------------------------------------------------------------------ 00127 // 00128 // CLASS: ovm_port_base #(IF) 00129 // 00130 //------------------------------------------------------------------------------ 00131 // 00132 // The base class for ports, exports, and implementations (imps). The template 00133 // parameter, IF, specifies the base interface class for the port. Derivations 00134 // of this class must then implement that interface. 00135 // 00136 // The ovm_port_base class provides the means to connect the ports together. 00137 // Later, after a process called "binding resolution," each port and export holds 00138 // a list of all imps that connect to it, directly or indirectly via other ports 00139 // and exports. In effect, we are collapsing the port's fanout, which can span 00140 // several levels of hierarchy up and down, into a single array held local to the 00141 // port. When accessing the interface via the port at run-time, the port merely 00142 // looks up the indexed interface in this list and calls the appropriate 00143 // interface method. 00144 // 00145 // SV does not support multiple inheritance. Thus, two classes are used 00146 // to define a single, logical port: ovm_port_base, which inherits from the 00147 // user's interface class, and ovm_port_component, which inherits from 00148 // ovm_component. The ovm_port_base class constructor creates an instance of 00149 // the ovm_port_component and passes a handle to itself to its constructor, 00150 // effectively linking the two. 00151 // 00152 // The OVM provides a complete set of ports, exports, and imps for the OSCI- 00153 // standard TLM interfaces. These can be found in the .../src/tlm/ directory. 00154 // 00155 // get_name 00156 // get_full_name 00157 // get_parent 00158 // These methods provide the leaf name, the full name, and the handle to the 00159 // parent component, respectively. The implementations of these methods 00160 // delegate to the port's component proxy. 00161 // 00162 // min_size 00163 // max_size 00164 // Returns the lower and upper bound on the required number of imp 00165 // connections. 00166 // 00167 // is_unbounded 00168 // Returns 1 if the max_size is set to OVM_UNBOUNDED_CONNECTIONS. 00169 // 00170 // is_port 00171 // is_export 00172 // is_imp 00173 // Returns 1 if true, 0 if false. The port type is a constructor argument. 00174 // 00175 // size 00176 // Returns the total number of imps connected to this port. The number is 00177 // only valid at and after the end_of_elaboration phase. It is 0 before then. 00178 // 00179 // set_if 00180 // Sets the default imp to use when calling an interface method. The default 00181 // is 0. Use this to access a specific imp when size() > 0. 00182 // 00183 // connect 00184 // Binds this port to another port given as an argument after validating the 00185 // legality of the connection. See the connect and m_check_relationship 00186 // method implementations for more information. 00187 // 00188 // resolve_bindings 00189 // This callback is called just before entering the end_of_elaboration phase. 00190 // It recurses through this port's fanout to determine all the imp destina- 00191 // tions. It then checks against the required min and max connections. 00192 // After resolution, size() returns a valid value and set_if() can be used 00193 // to access a particular imp. 00194 // 00195 //------------------------------------------------------------------------------ 00196 00197 virtual class ovm_port_base #(type IF=ovm_void) extends IF; 00198 00199 00200 typedef ovm_port_base #(IF) this_type; 00201 00202 // local, protected, and non-user properties 00203 protected int unsigned m_if_mask; 00204 protected this_type m_if; // REMOVE 00205 protected int unsigned m_def_index; 00206 ovm_port_component #(this_type) m_comp; 00207 local this_type m_provided_by[string]; 00208 local this_type m_provided_to[string]; 00209 local ovm_port_type_e m_port_type; 00210 local int m_min_size; 00211 local int m_max_size; 00212 local bit m_resolved; 00213 local this_type m_imp_list[string]; 00214 00215 function new (string name, 00216 ovm_component parent, 00217 ovm_port_type_e port_type, 00218 int min_size=0, 00219 int max_size=1); 00220 ovm_component comp; 00221 int tmp; 00222 m_port_type = port_type; 00223 m_min_size = min_size; 00224 m_max_size = max_size; 00225 m_comp = new(name, parent, this); 00226 00227 if (!m_comp.get_config_int("check_connection_relationships",tmp)) 00228 m_comp.set_report_id_action(s_connection_warning_id, OVM_NO_ACTION); 00229 00230 endfunction 00231 00232 function string get_name(); 00233 return m_comp.get_name(); 00234 endfunction 00235 00236 virtual function string get_full_name(); 00237 return m_comp.get_full_name(); 00238 endfunction 00239 00240 virtual function ovm_component get_parent(); 00241 return m_comp.get_parent(); 00242 endfunction 00243 00244 virtual function ovm_port_component_base get_comp(); 00245 return m_comp; 00246 endfunction 00247 00248 virtual function string get_type_name(); 00249 case( m_port_type ) 00250 OVM_PORT : return "port"; 00251 OVM_EXPORT : return "export"; 00252 OVM_IMPLEMENTATION : return "implementation"; 00253 endcase 00254 endfunction 00255 00256 function int max_size (); 00257 return m_max_size; 00258 endfunction 00259 00260 function int min_size (); 00261 return m_min_size; 00262 endfunction 00263 00264 function bit is_unbounded (); 00265 return (m_max_size == OVM_UNBOUNDED_CONNECTIONS); 00266 endfunction 00267 00268 function bit is_port (); 00269 return m_port_type == OVM_PORT; 00270 endfunction 00271 00272 function bit is_export (); 00273 return m_port_type == OVM_EXPORT; 00274 endfunction 00275 00276 function bit is_imp (); 00277 return m_port_type == OVM_IMPLEMENTATION; 00278 endfunction 00279 00280 function int size (); 00281 return m_imp_list.num(); 00282 endfunction 00283 00284 function void set_if (int index=0); 00285 m_if = get_if(index); 00286 if (m_if != null) 00287 m_def_index = index; 00288 endfunction 00289 00290 function void set_default_index (int index); 00291 m_def_index = index; 00292 endfunction 00293 00294 00295 // connect 00296 // ------- 00297 00298 function void connect (this_type provider); 00299 00300 // Check that the provider port meets the interface requirements of this 00301 // port. Each port has an interface mask that encodes the interface(s) it 00302 // supports. If the bitwise AND of these masks is equal to the this 00303 // port's mask, the requirement is met. 00304 00305 if (provider == null) begin 00306 m_comp.ovm_report_error(s_connection_error_id, 00307 "Cannot connect to null port handle"); 00308 return; 00309 end 00310 00311 if ((provider.m_if_mask & m_if_mask) != m_if_mask) begin 00312 m_comp.ovm_report_error(s_connection_error_id, 00313 {provider.get_full_name(), 00314 " (of type ",provider.get_type_name(), 00315 ") does not provide the complete interface required of this port (type ", 00316 get_type_name(),")"}); 00317 return; 00318 end 00319 00320 // IMP.connect(anything) is illegal 00321 if (is_imp()) begin 00322 m_comp.ovm_report_error(s_connection_error_id, 00323 $psprintf( 00324 "Cannot call an imp port's connect method. An imp is connected only to the component passed in its constructor. (You attempted to bind this imp to %s)", provider.get_full_name())); 00325 return; 00326 end 00327 00328 // EXPORT.connect(PORT) are illegal 00329 if (is_export() && provider.is_port()) begin 00330 m_comp.ovm_report_error(s_connection_error_id, 00331 $psprintf( 00332 "Cannot connect exports to ports Try calling port.connect(export) instead. (You attempted to bind this export to %s).", provider.get_full_name())); 00333 return; 00334 end 00335 00336 void'(m_check_relationship(provider)); 00337 00338 m_provided_by[provider.get_full_name()] = provider; 00339 provider.m_provided_to[get_full_name()] = this; 00340 00341 endfunction 00342 00343 00344 // debug_connected_to 00345 // ------------------ 00346 00347 function void debug_connected_to (int level=0, int max_level=-1); 00348 int sz, num, curr_num; 00349 string s_sz; 00350 static string indent, save; 00351 this_type port; 00352 00353 if (level < 0) level = 0; 00354 if (level == 0) begin save = ""; indent=" "; end 00355 00356 if (max_level != -1 && level >= max_level) 00357 return; 00358 00359 num = m_provided_by.num(); 00360 00361 if (m_provided_by.num() != 0) begin 00362 foreach (m_provided_by[nm]) begin 00363 curr_num++; 00364 port = m_provided_by[nm]; 00365 save = {save, indent, " | \n"}; 00366 save = {save, indent, " |_",nm," (",port.get_type_name(),")\n"}; 00367 indent = (num > 1 && curr_num != num) ? {indent, " | "} : {indent, " "}; 00368 port.debug_connected_to(level+1, max_level); 00369 indent = indent.substr(0,indent.len()-4-1); 00370 end 00371 end 00372 00373 if (level == 0) begin 00374 if (save != "") 00375 save = {"This port's fanout network:\n\n ", 00376 get_full_name()," (",get_type_name(),")\n",save,"\n"}; 00377 if (m_imp_list.num() == 0) begin 00378 if (end_of_elaboration_ph.is_done() || end_of_elaboration_ph.is_in_progress()) 00379 save = {save," Connected implementations: none\n"}; 00380 else 00381 save = {save," Connected implementations: not resolved until end-of-elab\n"}; 00382 end 00383 else begin 00384 save = {save," Resolved implementation list:\n"}; 00385 foreach (m_imp_list[nm]) begin 00386 port = m_imp_list[nm]; 00387 s_sz.itoa(sz); 00388 save = {save, indent, s_sz, ": ",nm," (",port.get_type_name(),")\n"}; 00389 sz++; 00390 end 00391 end 00392 m_comp.ovm_report_info("debug_connected_to", save); 00393 end 00394 endfunction 00395 00396 00397 // debug_provided_to 00398 // ----------------- 00399 00400 function void debug_provided_to (int level=0, int max_level=-1); 00401 string nm; 00402 int num,curr_num; 00403 this_type port; 00404 static string indent, save; 00405 00406 if (level < 0) level = 0; 00407 if (level == 0) begin save = ""; indent = " "; end 00408 00409 if (max_level != -1 && level > max_level) 00410 return; 00411 00412 num = m_provided_to.num(); 00413 00414 if (num != 0) begin 00415 foreach (m_provided_to[nm]) begin 00416 curr_num++; 00417 port = m_provided_to[nm]; 00418 save = {save, indent, " | \n"}; 00419 save = {save, indent, " |_",nm," (",port.get_type_name(),")\n"}; 00420 indent = (num > 1 && curr_num != num) ? {indent, " | "} : {indent, " "}; 00421 port.debug_provided_to(level+1, max_level); 00422 indent = indent.substr(0,indent.len()-4-1); 00423 end 00424 end 00425 00426 if (level == 0) begin 00427 if (save != "") 00428 save = {"This port's fanin network:\n\n ", 00429 get_full_name()," (",get_type_name(),")\n",save,"\n"}; 00430 if (m_provided_to.num() == 0) 00431 save = {save,indent,"This port has not been bound\n"}; 00432 m_comp.ovm_report_info("debug_provided_to", save); 00433 end 00434 00435 endfunction 00436 00437 00438 // get_connected_to 00439 // ---------------- 00440 00441 function void get_connected_to (ref ovm_port_list list); 00442 this_type port; 00443 list.delete(); 00444 foreach (m_provided_by[name]) begin 00445 port = m_provided_by[name]; 00446 list[name] = port.get_comp(); 00447 end 00448 endfunction 00449 00450 00451 // get_provided_to 00452 // --------------- 00453 00454 function void get_provided_to (ref ovm_port_list list); 00455 this_type port; 00456 list.delete(); 00457 foreach (m_provided_to[name]) begin 00458 port = m_provided_to[name]; 00459 list[name] = port.get_comp(); 00460 end 00461 endfunction 00462 00463 00464 // m_check_relationship 00465 // -------------------- 00466 00467 local function bit m_check_relationship (this_type provider); 00468 string s; 00469 this_type from; 00470 ovm_component from_parent; 00471 ovm_component to_parent; 00472 ovm_component from_gparent; 00473 ovm_component to_gparent; 00474 00475 // Checks that the connection is between ports that are hierarchically 00476 // adjacent (up or down one level max, or are siblings), 00477 // and check for legal direction, requirer.connect(provider). 00478 00479 // if we're an analysis port, allow connection to anywhere 00480 if (get_type_name() == "ovm_analysis_port") 00481 return 1; 00482 00483 from = this; 00484 from_parent = get_parent(); 00485 to_parent = provider.get_parent(); 00486 00487 // skip check if we have a parentless port 00488 if (from_parent == null || to_parent == null) 00489 return 1; 00490 00491 from_gparent = from_parent.get_parent(); 00492 to_gparent = to_parent.get_parent(); 00493 00494 // Connecting port-to-port: CHILD.port.connect(PARENT.port) 00495 // 00496 if (from.is_port() && provider.is_port() && from_gparent != to_parent) begin 00497 s = {provider.get_full_name(), 00498 " (of type ",provider.get_type_name(), 00499 ") is not up one level of hierarchy from this port. ", 00500 "A port-to-port connection takes the form ", 00501 "child_component.child_port.connect(parent_port)"}; 00502 m_comp.ovm_report_warning(s_connection_warning_id, s); 00503 return 0; 00504 end 00505 00506 // Connecting port-to-export: SIBLING.port.connect(SIBLING.export) 00507 // Connecting port-to-imp: SIBLING.port.connect(SIBLING.imp) 00508 // 00509 else if (from.is_port() && (provider.is_export() || provider.is_imp()) && 00510 from_gparent != to_gparent) begin 00511 s = {provider.get_full_name(), 00512 " (of type ",provider.get_type_name(), 00513 ") is not at the same level of hierarchy as this port. ", 00514 "A port-to-export connection takes the form ", 00515 "component1.port.connect(component2.export)"}; 00516 m_comp.ovm_report_warning(s_connection_warning_id, s); 00517 return 0; 00518 end 00519 00520 // Connecting export-to-export: PARENT.export.connect(CHILD.export) 00521 // Connecting export-to-imp: PARENT.export.connect(CHILD.imp) 00522 // 00523 else if (from.is_export() && (provider.is_export() || provider.is_imp()) && 00524 from_parent != to_gparent) begin 00525 s = {provider.get_full_name(), 00526 " (of type ",provider.get_type_name(), 00527 ") is not down one level of hierarchy from this export. ", 00528 "An export-to-export or export-to-imp connection takes the form ", 00529 "parent_export.connect(child_component.child_export)"}; 00530 m_comp.ovm_report_warning(s_connection_warning_id, s); 00531 return 0; 00532 end 00533 00534 return 1; 00535 endfunction 00536 00537 00538 // m_add_list 00539 // ---------- 00540 00541 local function void m_add_list (this_type provider); 00542 string sz; 00543 this_type imp; 00544 00545 for (int i = 0; i < provider.size(); i++) begin 00546 imp = provider.get_if(i); 00547 if (!m_imp_list.exists(imp.get_full_name())) 00548 m_imp_list[imp.get_full_name()] = imp; 00549 end 00550 00551 endfunction 00552 00553 00554 // resolve_bindings 00555 // ---------------- 00556 00557 function void resolve_bindings(); 00558 if (m_resolved) // don't repeat ourselves 00559 return; 00560 00561 if (is_imp()) begin 00562 m_imp_list[get_full_name()] = this; 00563 end 00564 else begin 00565 foreach (m_provided_by[nm]) begin 00566 this_type port; 00567 port = m_provided_by[nm]; 00568 port.resolve_bindings(); 00569 m_add_list(port); 00570 end 00571 end 00572 00573 m_resolved = 1; 00574 00575 if (size() < min_size() ) begin 00576 m_comp.ovm_report_error(s_connection_error_id, 00577 $psprintf("connection count of %0d does not meet required minimum of %0d", 00578 size(), min_size())); 00579 end 00580 00581 if (max_size() != OVM_UNBOUNDED_CONNECTIONS && size() > max_size() ) begin 00582 m_comp.ovm_report_error(s_connection_error_id, 00583 $psprintf("connection count of %0d exceeds maximum of %0d", 00584 size(), max_size())); 00585 end 00586 00587 if (size()) 00588 set_if(0); 00589 00590 endfunction 00591 00592 00593 `include "compatibility/urm_port_compatibility.svh" 00594 00595 // get_if 00596 // ------ 00597 00598 function ovm_port_base #(IF) get_if(int index=0); 00599 string s; 00600 if (size()==0) begin 00601 m_comp.ovm_report_warning("get_if", 00602 "Port size is zero; cannot get interface at any index"); 00603 return null; 00604 end 00605 if (index < 0 || index >= size()) begin 00606 $sformat(s, "Index %0d out of range [0,%0d]", index, size()-1); 00607 m_comp.ovm_report_warning(s_connection_error_id, s); 00608 return null; 00609 end 00610 foreach (m_imp_list[nm]) begin 00611 if (index == 0) 00612 return m_imp_list[nm]; 00613 index--; 00614 end 00615 endfunction 00616 00617 00618 00619 //------------------------------------ 00620 // Deprecated members below this point 00621 00622 00623 function this_type lookup_indexed_if(int i=0); 00624 return get_if(i); 00625 endfunction 00626 00627 function void do_display (int max_level=-1, int level=0, 00628 bit display_connectors=0); 00629 if (display_connectors) 00630 m_comp.ovm_report_info("hierarchy debug" , "" , 1000 ); 00631 endfunction 00632 00633 function void remove(); 00634 return; 00635 endfunction 00636 00637 local function bit check_phase (this_type provider); 00638 return 1; 00639 endfunction 00640 00641 local function void check_min_connection_size (); 00642 return; 00643 endfunction 00644 00645 endclass 00646
![]() Intelligent Design Verification Project: OVM, Revision: 2.0.1 |
Copyright (c) 2008 Intelligent Design Verification. Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.2 or any later version published by the Free Software Foundation; with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts. A copy of the license is included here: http://www.intelligentdv.com/licenses/fdl.txt |
![]() Doxygen Version: 1.5.5 Wed Jan 7 19:27:18 2009 |