TLM decl macros - vnrjoshi/UVM-Virtual-Sequence GitHub Wiki

TLM decl macros

In TLM Put, we have seen the scenario, where data sent to the consumer is executed using the put() method. Let us consider the case where there are two producers A and B connected to consumer export. Then, any data object sent by either producer A or producer B will be received by the consumer and operated upon by the same put() method. If there's a need to be able to process them separately, you would need to have two separate put() methods.

TLM1 drawio

UVM provides us with the uvm_*_put_imp_decl () macro to deal with cases when the producer needs to provide two put implementation ports.

  • Sample code:

    `uvm_put_imp_decl (_1)  
    `uvm_put_imp_decl (_2)  
    
     class consumer extends uvm_component
      uvm_put_imp_1 (packet, consumer) put_imp1;
      uvm_put_imp_2(packet, consumer) put_imp2;
    
    function void put_1(packet pkt);
      //puts coming from put_imp1
    endfunction
    
    function void put_2(packet pkt);
      //puts coming from put_imp2
    endfunction
    
    endclass
    

Note:

  • 'uvm_put_imp_decl should be outside the class.
  • uvm_put_imp class used consumer should have the argument passed to the macro appended to it.
  • put() function/task should also have an argument.

When the macros are called, UVM will create two new classes by the name uvm_put_imp_1 and uvm_put_imp_2. That is the reason why we have to append the argument to uvm_put_imp when trying to create an object. Even the put() method defined in those classes has the argument appended to it. we can give any names as the argument instead of _1 and _2, but need to use the same afterward also.

TLM1 drawio (2)

  • Example:

Let's first create Producer A and Producer B.

     //Producer A  

    class prodA extends uvm_component;   
    `uvm_component_utils(prodA)  

    uvm_blocking_put_port #(packet) send;  
    packet pkt;

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

    virtual function void build_phase(uvm_phase phase);
     super.build_phase(phase);
    send=new("send",this);
    endfunction

    virtual task run_phase(uvm_phase phase);
    repeat(2) begin
     pkt=packet::type_id::create("pkt");
     assert(pkt.randomize());
     `uvm_info("prodA", "packet sent to consumer", UVM_LOW)
     pkt.print();
     send.put(pkt);
    end
    endtask
    
    endclass

    //Producer A  

    class prodB extends uvm_component;   
    `uvm_component_utils(prodB)  

    uvm_blocking_put_port #(packet) send;  
    packet pkt;

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

    virtual function void build_phase(uvm_phase phase);
     super.build_phase(phase);
    send=new("send",this);
    endfunction

    virtual task run_phase(uvm_phase phase);
    repeat(2) begin
     pkt=packet::type_id::create("pkt");
     assert(pkt.randomize());
     `uvm_info("prodB", "packet sent to consumer", UVM_LOW)
     pkt.print();
     send.put(pkt);
    end
    endtask
    
    endclass  

Now let's us create consumer

     `uvm_blocking_put_imp_decl (_1)  //should be outside the class
     `uvm_blocking_put_imp_decl (_2)

     //Consumer

     class consumer extends uvm_component;
     `uvm_component_utils(consumer)

      uvm_blocking_put_imp_1 #(packet, consumer) put_imp1;
      uvm_blocking_put_imp_2 #(packet, consumer) put_imp2;

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

      virtual function void build_phase(uvm_phase phase);
       super.build_phase(phase);
      put_imp1=new("put_imp1", this);
      put_imp2=new("put_imp2", this);
      endfunction

      function void put_1(packet pkt);
       `uvm_info("CONS" , "packet received from put_1", UVM_LOW)
       pkt.print();
      endfunction

      function void put_2(packet pkt);
       `uvm_info("CONS" , "packet received from put_2", UVM_LOW)
       pkt.print();
     endfunction

     endclass

The environment will have all three component instantiations, and connect producer A with consumer put_imp1 port, while producer B will be connected to consumer put_imp2.

  //Environment

 class environment extends uvm_env;
 `uvm_component_utils(environment)

 prodA pA;
 prodB pB;
 consumer c;

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

 virtual function void build_phase(uvm_phase phase);
  super.build_phase(phase);
  pA = prodA::type_id::create("pA",this);
  pB = prodB::type_id::create("pB",this);
  c = consumer::type_id::create("c", this);
endfunction

 virtual function void connect_phase(uvm_phase phase);
  super.connect_phase(phase);
  pA.send.connect(c.put_imp1);
  pB.send.connect(c.put_imp2);
endfunction
endclass
  • Output:

output1 drawio (2)

output1 drawio (1)

As we can see in the output that the producer B sent a packet to the consumer i.e., a='he, b='hd, and c='h0, and now the consumer received a packet from put_2 i.e., a='he, b='hd, and c='h0. Producer A sent a packet to the consumer i.e., a='h9, b='h0, and c='h0, and now the consumer received a packet from put_1 i.e., a='h9, b='h0, and c='h0.
Here it will not override the values, it will store both producer A and B values in one consumer.