Welcome ! This website will help YOU (recent graduates/professionals) learn verification languages like SystemVerilog and UVM. Register for free and access more content !

It's going to be a bit tricky when crossing hierarchies because it's easy to get confused on whether a port or export should be used. Fear not ! We'll explore now on how to do just that.

We'll take the testbench setup we saw in the previous session and rename componentA and componentB to subComponent1 and subComponent2. Then we'll place it inside a new component and call it componentA. Similarly, we'll create another new component called componentB and place a TLM Fifo and subComponent3 inside it as shown in the diagram below.


GitHub

You can download/clone the example code from our repository at GitHub.


TestBench

tlm-hier

componentA will now contain two subcomponents connected by a TLM Fifo, and the code is the same as previous session, except that now we need a port to connect from subcomponent2 to componentA. For this purpose, we'll create a port called put_portA in both subcomponent2 and componentA using the class uvm_put_port. These two will be connected inside componentA. We'll see how subcomponent2 has been modified to include put_portA.

 
class subComponent2 extends uvm_component;
   `uvm_component_utils (subComponent2)
 
   // Mention type of transaction, and type of class that implements the put ()
   uvm_blocking_get_port #(simple_packet) get_port;
   uvm_put_port #(simple_packet)          put_portA;
 
   function new (string name = "subComponent2", uvm_component parent = null);
      super.new (name, parent);
   endfunction
 
   virtual function void build_phase (uvm_phase phase);
      super.build_phase (phase);
      get_port = new ("get_port", this);
      put_portA = new ("put_portA", this);
   endfunction
 
   virtual task run_phase (uvm_phase phase);
      simple_packet pkt;
      phase.raise_objection (this);
      repeat (5) begin
         #10;
         get_port.get (pkt);
         `uvm_info ("SCOMP2", "subComponent1 just gave me the packet", UVM_LOW)
         pkt.print ();
 
         // Remember to send this packet through the port, else ComponentB will not get data
         `uvm_info ("SCOMP2", "Send this to subComponent3", UVM_LOW)
         put_portA.put (pkt);
      end
      phase.drop_objection (this);
   endtask
endclass
 

In componentA, we'll connect the port of subcomponent with the port of componentA using the connect () method.

 
class componentA extends uvm_component;
   `uvm_component_utils (componentA)
 
   subComponent1 subComp1;
   subComponent2 subComp2;
   uvm_tlm_fifo #(simple_packet)    tlm_fifo;
   uvm_put_port #(simple_packet)  put_portA;
 
   function new (string name = "componentA", uvm_component parent = null);
      super.new (name, parent);
   endfunction
 
   virtual function void build_phase (uvm_phase phase);
      super.build_phase (phase);
      // Create an object of both components
      subComp1 = subComponent1::type_id::create ("subComp1", this);
      subComp2 = subComponent2::type_id::create ("subComp2", this);
 
      // Create a FIFO with depth 2
      tlm_fifo = new ("tlm_fifo", this, 2);
 
      // Create a port to connect with subcomponent2
      put_portA = new ("put_portA", this);
   endfunction
 
   virtual function void connect_phase (uvm_phase phase);
      subComp1.put_port.connect (tlm_fifo.put_export);
      subComp2.get_port.connect (tlm_fifo.get_export);
 
      // Connect put_portA of componentA with subComponent2
      subComp2.put_portA.connect (this.put_portA);
   endfunction
endclass
 

As you can see, there's very little code change from the previous session.


Now, let's construct componentB which is the same as componentA, but without subcomponent1. Since the first block is the TLM Fifo which has an export, we'll create an export from uvm_put_export in componentB and connect it with the TLM Fifo put_export.

 
class componentB extends uvm_component;
   `uvm_component_utils (componentB)
 
   subComponent3                    subComp3;
   uvm_tlm_fifo #(simple_packet)    tlm_fifo;
   uvm_put_export #(simple_packet)  put_export;
 
   function new (string name = "componentB", uvm_component parent = null);
      super.new (name, parent);
   endfunction
 
   virtual function void build_phase (uvm_phase phase);
      super.build_phase (phase);
      // Create an object of both components
      subComp3 = subComponent3::type_id::create ("subComp3", this);
 
      // Create a FIFO with depth 2
      tlm_fifo = new ("tlm_fifo", this, 2);
 
      // Create the export to connect with subComponent
      put_export = new ("put_export", this);
   endfunction
 
   virtual function void connect_phase (uvm_phase phase);
      // Connect from componentB export to FIFO export
      put_export.connect (tlm_fifo.put_export);
 
      // Connect from FIFO export to subComponent3 port 
      subComp3.get_port.connect (tlm_fifo.get_export);
   endfunction
endclass
 

At the top environment level, we'll instantiate componentA/B and connect them using the connect() method of port in componentA.

 
virtual function void connect_phase (uvm_phase phase);
   compA.put_portA.connect (compB.put_export);
 endfunction
 

Until now, we have only seen connections between one component with another. What if a component wants to broadcast the data packet to whatever is connected with it ? And what kind of connection is required ? We are talking about an Analysis Port which will be discussed next.

Was this article helpful ?

We use cookies to personalize content and ads, to provide social media features and to analyze our traffic. You consent to our cookies if you continue to use our website. To find out more about the cookies we use and how to delete them, see our privacy policy.

  I accept cookies from this site.
Agree
EU Cookie Directive plugin by www.channeldigital.co.uk