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.
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.
- 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:
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.