Analysis Port - naveen0215/uvm_sequence_library GitHub Wiki

Earlier we have seen TLM put() and get() methods which was having one-on-one connections that is either port-to-export or port-to-imp connections. whereas this analysis port are used for one-to many connections that is broadcast of transactions to any number of components or receivers(even if there is no receiver analysis port broadcasts the data). hence we can conclude it as analysis port may be connected to zero, one or many Analysis Exports.

Analysis port

uvm_analysis_port : Broadcast port

The uvm_analysis_port is a specialized TLM port which has non-blocking function, write(). The uvm_analysis_port calls an analysis_port.write(transaction) method to broadcast a transaction. A uvm_analysis_port can be connected to other uvm_analysis_ports, uvm_analysis_exports and uvm_analysis_imps.

uvm_analysis_export : Transfer port

The uvm_analysis_export is similar to a transfer‐point connection and it lies between the broadcasting uvm_analysis_port source and each uvm_analysis_imp termination point. uvm_analysis_export(s) can be viewed as a transfer port.

uvm_analysis_imp : Termination port

Each uvm_analysis_imp defines a write() method that is executed when the analysis port calls the write() method. In the parent environment, the analysis port gets connected to the analysis export of the desired components, such as coverage collectors and scoreboards in a typical UVM testbench.

The uvm_analysis_port is a specialized TLM class which consists of a function write() and this can be used to transfer the data from where we need. This port also contains list of analysis exports and analysis implementations that are connected to it. Later by using the analysis_port.write() in one component we can broadcast the data to each connected exports. Components which have a read() function will receive the datas which are broadcasted. Generally monitor will be using analysis_port to broadcast the data to multiple components like scoreboard, coverage collector, subscribers.

  • Syntax:

        class my_class_name extends uvm_component;   
                 .....   
               uvm_analysis_port #(my_data) port_name;   
                 .....   
         endclass    
    

Example:

analysis-port

In this example, let us consider a componentB from which we broadcast or send the data to three different subscribers (sub1,sub2,sub3). Since we need to perform broadcasting of the data ,we use a special type of connection called uvm_analysis_port.

Producer Class

      class transaction extends uvm_sequence_item;
          rand bit[2:0]a;
          rand bit[2:0]b;

        `uvm_object_utils_begin(transaction)
        `uvm_field_int(a,UVM_DEFAULT+UVM_DEC)
        `uvm_field_int(b,UVM_DEFAULT+UVM_DEC)
        `uvm_object_utils_end


        function new (string name = "transaction");
            super.new(name);
        endfunction

    endclass

    class componentB extends uvm_component;

         `uvm_component_utils(componentB)

          transaction trans;
         uvm_analysis_port #(transaction) ap;

         function new (string name = "componentB" , uvm_component parent);
              super.new (name,parent);
              ap = new("WRITE",this);
         endfunction

        virtual function void build_phase(uvm_phase phase);
             super.build_phase(phase);
             trans = transaction::type_id::create("trans",this);
       endfunction

       virtual task run_phase(uvm_phase phase);
            repeat(3) begin
            `uvm_info(get_type_name(),"sending Data to subscribers.......",UVM_NONE)
            void'(trans.randomize());
            ap.write(trans);
            trans.print();
             end
      endtask

  endclass

In the above code snippet, we are extending transaction class from uvm_sequence_item which is a base class. we defined two class properties 'a' and 'b' of rand bit type. since uvm_sequence_item is a object, we registered this class using pre-defined factory macro uvm_component_utils and the fields are also registered within this factory registration.

We have defined a class componentB extending from uvm_component. This class is registered using factory macro. Now, in this example we are defining a special type of port called uvm_analysis_port. After declaring some random_name('ap') to analysis_port, we have to specify that port operations as write(to specify this as a producer). using ap.write(trans) we broadcasted the data from the componentB.

Consumer Classes

      class sub1 extends uvm_component;
         transaction trans;

         `uvm_component_utils(sub1)
          uvm_analysis_imp #(transaction , sub1) aimp;

          function new (string name = "sub1" , uvm_component parent);
                super.new (name,parent);
                 aimp = new("READ",this);
          endfunction
  
          virtual function void write (input transaction t);
               t.print();
               `uvm_info(get_type_name(),"Data Received to sub1!!",UVM_NONE)
          endfunction
       endclass

         class sub2 extends uvm_component;
              transaction trans;
             `uvm_component_utils(sub2)
              uvm_analysis_imp #(transaction , sub2) aimp;

              function new (string name = "sub2" , uvm_component parent);
                      super.new (name,parent);
                      aimp = new("READ",this);
              endfunction

              virtual function void write (input transaction t);
                      t.print();
                     `uvm_info(get_type_name(),"Data Received to sub2!!",UVM_NONE)
             endfunction
         endclass


        class sub3 extends uvm_component;
               transaction trans;
               `uvm_component_utils(sub3)
               uvm_analysis_imp #(transaction , sub3) aimp;

              function new (string name = "sub2" , uvm_component parent);
                  super.new (name,parent);
                  aimp = new("READ",this);
              endfunction

              virtual function void write (input transaction t);
                    t.print();
                   `uvm_info(get_type_name(),"Data Received to sub3!!",UVM_NONE)
               endfunction
            endclass

We extended 3 different class sub1,sub2 and sub3 from uvm_component. Since this class need to receive the datas which are broadcasted from componentB we are defining a uvm_analysis_imp with a name as 'aimp' and during its build phase we are declaring this port as READ type(consuming type). We have defined a virtual function with name as write and we are passing the transaction as an argument to it. This is similar for all 3 consumer classes.

      class my_env extends uvm_env;
          componentB  comB;
          sub1 s1;
          sub2 s2;
           sub3 s3;
          `uvm_component_utils(my_env)

          function new (string name = "my_env" , uvm_component parent);
            super.new (name,parent);
          endfunction

         virtual function void build_phase (uvm_phase phase);
            super.build_phase(phase);
            comB = componentB::type_id::create("comB",this);
            s1 = sub1::type_id::create("s1",this);
            s2 = sub2::type_id::create("s2",this);
            s3 = sub3::type_id::create("s3",this);
         endfunction

          virtual function void connect_phase (uvm_phase phase);
            super.connect_phase(phase);
            comB.ap.connect(s1.aimp);
            comB.ap.connect(s2.aimp);
           comB.ap.connect(s3.aimp);
        endfunction
     endclass

        class test extends uvm_test;
            my_env env;
            `uvm_component_utils(test)

             function new (string name = "test" , uvm_component parent);
                   super.new (name,parent);
             endfunction

             virtual function void build_phase(uvm_phase phase);
                    super.build_phase(phase);
                    env = my_env::type_id::create("env",this);
             endfunction

             virtual function void end_of_elaboration_phase(uvm_phase phase);
                         super.end_of_elaboration_phase(phase);
                        `uvm_info(get_type_name(),"end_of_elaboration_phase",UVM_NONE)
                        uvm_top.print_topology();
              endfunction
       endclass

We extended my_env class from uvm_env and instantiated the producer and the consumer classes with a name and also at this level it is very easier to have connection between the components.So, we created object for the instantiated classes during the build_phase and during the connect phase we connected the producer_port to the consumer_port.

Finally we extended the test class from uvm_test and we instatiated and created a object using create method for derived env class. Also during end_of_elaboration_phase we are printing the whole topology which includes the name of derived class and the base class.

  • Output:

analysis_port

analysis_port1

From the above output snaps, we can see that componentB is sending the data to consumers and all 3 consumers are driving or receiving the same output from componentB.