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 {"Cannot call an imp port's connect method. An imp is connected only ", 00324 "to the component passed in its constructor. ", 00325 "(You attempted to bind this imp to ", provider.get_full_name(),")"}); 00326 return; 00327 end 00328 00329 // EXPORT.connect(PORT) are illegal 00330 if (is_export() && provider.is_port()) begin 00331 m_comp.ovm_report_error(s_connection_error_id, 00332 {"Cannot connect exports to ports ", 00333 "Try calling port.connect(export) instead. ", 00334 "(You attempted to bind this export to ", provider.get_full_name(),"). "}); 00335 return; 00336 end 00337 00338 void'(m_check_relationship(provider)); 00339 00340 m_provided_by[provider.get_full_name()] = provider; 00341 provider.m_provided_to[get_full_name()] = this; 00342 00343 endfunction 00344 00345 00346 // debug_connected_to 00347 // ------------------ 00348 00349 function void debug_connected_to (int level=0, int max_level=-1); 00350 int sz, num, curr_num; 00351 string s_sz; 00352 static string indent, save; 00353 this_type port; 00354 00355 if (level < 0) level = 0; 00356 if (level == 0) begin save = ""; indent=" "; end 00357 00358 if (max_level != -1 && level >= max_level) 00359 return; 00360 00361 num = m_provided_by.num(); 00362 00363 if (m_provided_by.num() != 0) begin 00364 foreach (m_provided_by[nm]) begin 00365 curr_num++; 00366 port = m_provided_by[nm]; 00367 save = {save, indent, " | \n"}; 00368 save = {save, indent, " |_",nm," (",port.get_type_name(),")\n"}; 00369 indent = (num > 1 && curr_num != num) ? {indent, " | "} : {indent, " "}; 00370 port.debug_connected_to(level+1, max_level); 00371 indent = indent.substr(0,indent.len()-4-1); 00372 end 00373 end 00374 00375 if (level == 0) begin 00376 if (save != "") 00377 save = {"This port's fanout network:\n\n ", 00378 get_full_name()," (",get_type_name(),")\n",save,"\n"}; 00379 if (m_imp_list.num() == 0) begin 00380 if (end_of_elaboration_ph.is_done() || end_of_elaboration_ph.is_in_progress()) 00381 save = {save," Connected implementations: none\n"}; 00382 else 00383 save = {save," Connected implementations: not resolved until end-of-elab\n"}; 00384 end 00385 else begin 00386 save = {save," Resolved implementation list:\n"}; 00387 foreach (m_imp_list[nm]) begin 00388 port = m_imp_list[nm]; 00389 s_sz.itoa(sz); 00390 save = {save, indent, s_sz, ": ",nm," (",port.get_type_name(),")\n"}; 00391 sz++; 00392 end 00393 end 00394 m_comp.ovm_report_info("debug_connected_to", save); 00395 end 00396 endfunction 00397 00398 00399 // debug_provided_to 00400 // ----------------- 00401 00402 function void debug_provided_to (int level=0, int max_level=-1); 00403 string nm; 00404 int num,curr_num; 00405 this_type port; 00406 static string indent, save; 00407 00408 if (level < 0) level = 0; 00409 if (level == 0) begin save = ""; indent = " "; end 00410 00411 if (max_level != -1 && level > max_level) 00412 return; 00413 00414 num = m_provided_to.num(); 00415 00416 if (num != 0) begin 00417 foreach (m_provided_to[nm]) begin 00418 curr_num++; 00419 port = m_provided_to[nm]; 00420 save = {save, indent, " | \n"}; 00421 save = {save, indent, " |_",nm," (",port.get_type_name(),")\n"}; 00422 indent = (num > 1 && curr_num != num) ? {indent, " | "} : {indent, " "}; 00423 port.debug_provided_to(level+1, max_level); 00424 indent = indent.substr(0,indent.len()-4-1); 00425 end 00426 end 00427 00428 if (level == 0) begin 00429 if (save != "") 00430 save = {"This port's fanin network:\n\n ", 00431 get_full_name()," (",get_type_name(),")\n",save,"\n"}; 00432 if (m_provided_to.num() == 0) 00433 save = {save,indent,"This port has not been bound\n"}; 00434 m_comp.ovm_report_info("debug_provided_to", save); 00435 end 00436 00437 endfunction 00438 00439 00440 // get_connected_to 00441 // ---------------- 00442 00443 function void get_connected_to (ref ovm_port_list list); 00444 this_type port; 00445 list.delete(); 00446 foreach (m_provided_by[name]) begin 00447 port = m_provided_by[name]; 00448 list[name] = port.get_comp(); 00449 end 00450 endfunction 00451 00452 00453 // get_provided_to 00454 // --------------- 00455 00456 function void get_provided_to (ref ovm_port_list list); 00457 this_type port; 00458 list.delete(); 00459 foreach (m_provided_to[name]) begin 00460 port = m_provided_to[name]; 00461 list[name] = port.get_comp(); 00462 end 00463 endfunction 00464 00465 00466 // m_check_relationship 00467 // -------------------- 00468 00469 local function bit m_check_relationship (this_type provider); 00470 string s; 00471 this_type from; 00472 ovm_component from_parent; 00473 ovm_component to_parent; 00474 ovm_component from_gparent; 00475 ovm_component to_gparent; 00476 00477 // Checks that the connection is between ports that are hierarchically 00478 // adjacent (up or down one level max, or are siblings), 00479 // and check for legal direction, requirer.connect(provider). 00480 00481 // if we're an analysis port, allow connection to anywhere 00482 if (get_type_name() == "ovm_analysis_port") 00483 return 1; 00484 00485 from = this; 00486 from_parent = get_parent(); 00487 to_parent = provider.get_parent(); 00488 00489 // skip check if we have a parentless port 00490 if (from_parent == null || to_parent == null) 00491 return 1; 00492 00493 from_gparent = from_parent.get_parent(); 00494 to_gparent = to_parent.get_parent(); 00495 00496 // Connecting port-to-port: CHILD.port.connect(PARENT.port) 00497 // 00498 if (from.is_port() && provider.is_port() && from_gparent != to_parent) begin 00499 s = {provider.get_full_name(), 00500 " (of type ",provider.get_type_name(), 00501 ") is not up one level of hierarchy from this port. ", 00502 "A port-to-port connection takes the form ", 00503 "child_component.child_port.connect(parent_port)"}; 00504 m_comp.ovm_report_warning(s_connection_warning_id, s); 00505 return 0; 00506 end 00507 00508 // Connecting port-to-export: SIBLING.port.connect(SIBLING.export) 00509 // Connecting port-to-imp: SIBLING.port.connect(SIBLING.imp) 00510 // 00511 else if (from.is_port() && (provider.is_export() || provider.is_imp()) && 00512 from_gparent != to_gparent) begin 00513 s = {provider.get_full_name(), 00514 " (of type ",provider.get_type_name(), 00515 ") is not at the same level of hierarchy as this port. ", 00516 "A port-to-export connection takes the form ", 00517 "component1.port.connect(component2.export)"}; 00518 m_comp.ovm_report_warning(s_connection_warning_id, s); 00519 return 0; 00520 end 00521 00522 // Connecting export-to-export: PARENT.export.connect(CHILD.export) 00523 // Connecting export-to-imp: PARENT.export.connect(CHILD.imp) 00524 // 00525 else if (from.is_export() && (provider.is_export() || provider.is_imp()) && 00526 from_parent != to_gparent) begin 00527 s = {provider.get_full_name(), 00528 " (of type ",provider.get_type_name(), 00529 ") is not down one level of hierarchy from this export. ", 00530 "An export-to-export or export-to-imp connection takes the form ", 00531 "parent_export.connect(child_component.child_export)"}; 00532 m_comp.ovm_report_warning(s_connection_warning_id, s); 00533 return 0; 00534 end 00535 00536 return 1; 00537 endfunction 00538 00539 00540 // m_add_list 00541 // ---------- 00542 00543 local function void m_add_list (this_type provider); 00544 string sz; 00545 this_type imp; 00546 00547 for (int i = 0; i < provider.size(); i++) begin 00548 imp = provider.get_if(i); 00549 if (!m_imp_list.exists(imp.get_full_name())) 00550 m_imp_list[imp.get_full_name()] = imp; 00551 end 00552 00553 endfunction 00554 00555 00556 // resolve_bindings 00557 // ---------------- 00558 00559 function void resolve_bindings(); 00560 if (m_resolved) // don't repeat ourselves 00561 return; 00562 00563 if (is_imp()) begin 00564 m_imp_list[get_full_name()] = this; 00565 end 00566 else begin 00567 foreach (m_provided_by[nm]) begin 00568 this_type port; 00569 port = m_provided_by[nm]; 00570 port.resolve_bindings(); 00571 m_add_list(port); 00572 end 00573 end 00574 00575 m_resolved = 1; 00576 00577 if (size() < min_size() ) begin 00578 m_comp.ovm_report_error(s_connection_error_id, 00579 $psprintf("connection count of %0d does not meet required minimum of %0d", 00580 size(), min_size())); 00581 end 00582 00583 if (max_size() != OVM_UNBOUNDED_CONNECTIONS && size() > max_size() ) begin 00584 m_comp.ovm_report_error(s_connection_error_id, 00585 $psprintf("connection count of %0d exceeds maximum of %0d", 00586 size(), max_size())); 00587 end 00588 00589 if (size()) 00590 set_if(0); 00591 00592 endfunction 00593 00594 00595 `include "compatibility/urm_port_compatibility.svh" 00596 00597 // get_if 00598 // ------ 00599 00600 function ovm_port_base #(IF) get_if(int index=0); 00601 string s; 00602 if (size()==0) begin 00603 m_comp.ovm_report_warning("get_if", 00604 "Port size is zero; cannot get interface at any index"); 00605 return null; 00606 end 00607 if (index < 0 || index >= size()) begin 00608 $sformat(s, "Index %0d out of range [0,%0d]", index, size()-1); 00609 m_comp.ovm_report_warning(s_connection_error_id, s); 00610 return null; 00611 end 00612 foreach (m_imp_list[nm]) begin 00613 if (index == 0) 00614 return m_imp_list[nm]; 00615 index--; 00616 end 00617 endfunction 00618 00619 00620 00621 //------------------------------------ 00622 // Deprecated members below this point 00623 00624 00625 function this_type lookup_indexed_if(int i=0); 00626 return get_if(i); 00627 endfunction 00628 00629 function void do_display (int max_level=-1, int level=0, 00630 bit display_connectors=0); 00631 if (display_connectors) 00632 m_comp.ovm_report_info("hierarchy debug" , "" , 1000 ); 00633 endfunction 00634 00635 function void remove(); 00636 return; 00637 endfunction 00638 00639 local function bit check_phase (this_type provider); 00640 return 1; 00641 endfunction 00642 00643 local function void check_min_connection_size (); 00644 return; 00645 endfunction 00646 00647 endclass 00648
![]() Intelligent Design Verification Project: OVM, Revision: 1.1.0 |
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.4.6 Mon Sep 29 14:23:30 2008 |