Here’s a typical TLM application using uvm_blocking_put_port and um_blocking_put_imp to connect a producer and a consumer.
class producer extends uvm_component;
uvm_blocking_put_port#(instruction) put_port;
function new(string name, uvm_component p = null);
super.new(name,p);
put_port = new("put_port", this);
endfunction
task run;
for(int i = 0; i < 10; i++)
begin
instruction ints;
#10;
ints = new();
if(ints.randomize()) begin
`uvm_info("producer", $sformatf("sending %s",ints.inst.name()), UVM_MEDIUM)
put_port.put(ints);
end
end
endtask
endclass : producer
class consumer extends uvm_component;
uvm_blocking_put_imp#(instruction,consumer) put_export;
function new(string name, uvm_component p = null);
super.new(name,p);
put_export = new("put_export", this);
endfunction
task put(instruction t);
`uvm_info("consumer", $sformatf("receiving %s",t.inst.name()), UVM_MEDIUM)
//push the transaction into queue or array
//or drive the transaction to next level
//or drive to interface
endtask
endclass : consumer
class env extends uvm_env;
producer p;
consumer c;
function new(string name = "env");
super.new(name);
p = new("producer", this);
c = new("consumer", this);
endfunction
function void connect();
p.put_port.connect(c.put_export);
endfunction
One thing that bothers me in this application is that: Why would the put() function which belongs to class consumer get executed when we are calling the put() function which belongs to class put_port– “put_port.put(ints)” inside class producer. Is there some UVM magic happening at the connect step?