ovm_port_base.svh

Go to the documentation of this file.
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
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
Doxygen Version: 1.5.5
Wed Jan 7 19:27:18 2009
Find a documentation bug? Report bugs to: bugs.intelligentdv.com Project: DoxygenFilterSV