Hi,
I’m trying to understand Non-blocking behavior as the described in TLM Interfaces, Ports, and Exports
blocking A blocking interface conveys transactions in blocking fashion; its methods do not return until the transaction has been successfully sent or retrieved. Because delivery may consume time to complete, the methods in such an interface are declared as tasks.
non-blocking A non-blocking interface attempts to convey a transaction without consuming simulation time. Its methods are declared as functions. Because delivery may fail (e.g. the target component is busy and can not accept the request), the methods may return with failed status
So I was made a simple example from referencing example
class Packet extends uvm_object;
rand bit[7:0] addr;
rand bit[7:0] data;
`uvm_object_utils_begin(Packet)
`uvm_field_int(addr, UVM_ALL_ON)
`uvm_field_int(data, UVM_ALL_ON)
`uvm_object_utils_end
function new(string name = "Packet");
super.new(name);
endfunction
endclass
class componentA extends uvm_component;
`uvm_component_utils (componentA)
// Rest of the code remains same
virtual task run_phase (uvm_phase phase);
phase.raise_objection(this);
repeat (m_num_tx) begin
bit success;
Packet pkt = Packet::type_id::create ("pkt");
assert(pkt.randomize ());
// Print the packet to be displayed in log
`uvm_info ("COMPA", "Packet sent to CompB", UVM_LOW)
pkt.print (uvm_default_line_printer);
// do-while loop uses a "try_put" to keep the sender blocked until the receiver is ready. Return
// type of the try_put indicates if the transfer was successful. So, lets just try putting
// the same packet until the receiver returns a 1 indicating successful transfer.
// Note that this is the same as using "put" but we are doing it with "try_put" and a loop
do begin
success = m_put_port.try_put(pkt);
if (success)
`uvm_info("COMPA", $sformatf("COMPB was ready to accept and transfer is successful"), UVM_MEDIUM)
else
`uvm_info("COMPA", $sformatf("COMPB was NOT ready to accept and transfer failed, try after 1ns"), UVM_MEDIUM)
#1;
end while (!success);
end
phase.drop_objection(this);
endtask
endclass
class componentB extends uvm_component;
`uvm_component_utils (componentB)
virtual function bit try_put (Packet pkt);
bit ready;
std::randomize(ready);
if (ready) begin
`uvm_info ("COMPB", "Packet received", UVM_LOW)
pkt.print(uvm_default_line_printer);
return 1;
end else begin
return 0;
end
endfunction
virtual function bit can_put();
endfunction
endclass
class my_test extends uvm_test;
`uvm_component_utils (my_test)
componentA compA;
componentB compB;
function new (string name = "my_test", uvm_component parent = null);
super.new (name, parent);
endfunction
// Create objects of both components, set number of transfers
virtual function void build_phase (uvm_phase phase);
super.build_phase (phase);
compA = componentA::type_id::create ("compA", this);
compB = componentB::type_id::create ("compB", this);
compA.m_num_tx = 2;
endfunction
virtual function void connect_phase (uvm_phase phase);
compA.m_put_port.connect (compB.m_put_imp);
endfunction
virtual function void end_of_elaboration_phase(uvm_phase phase);
super.end_of_elaboration_phase(phase);
uvm_top.print_topology();
endfunction
endclass
Especially, I want to modify componentB for understanding non-blocking with time consumption in componentB. Whether the function in componentB can return value or not during in stall.
But I can’t implement such as time delay # delay in a function at componentB. because function can’t implement # delay.