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         {"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
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
Doxygen Version: 1.4.6
Mon Sep 29 14:23:30 2008
Find a documentation bug? Report bugs to: bugs.intelligentdv.com Project: DoxygenFilterSV