I. Overview
Similar to one-way communication, the two ends of two-way communication are also divided into initiator and target, but the data flow is bidirectional between end-to-end. Both ends of the two-way communication play the role of producer and consumer at the same time, and the initiator, as the request initiator, waits for the response to return after initiating the request.
UVM bidirectional ports are divided into the following types:
- uvm_blocking_transport_PORT
- uvm_nonblocking_transport_PORT
- uvm_transport_PORT
- uvm_blocking_master_PORT
- uvm_nonblocking_master_PORT
- uvm_master_PORT
- uvm_blocking_slave_PORT
- uvm_nonblocking_slave_PORT
- uvm_slave_PORT
PORT represents port, export
2. Classification
According to the communication handshake mode, bidirectional ports can be divided into:
- transaction two-way communication
- Two-way communication between master and slave
The transport port can complete the sending and returning of REQ and RSP in the same method call process through the transport() method.
The communication mode of master and slave must be called by put, get and peek respectively, and a handshake communication can be completed only by using two methods. The difference between the master port and the slave port is that when the initiator acts as the master, it will send a REQ to the target, and then obtain the RSP from the target. When the initiator uses the slave port, it will first obtain the REQ from the target, and then send the RSP to the target. Send it to the target side.
Three, transport
transport two-way communication
class comp1 extends uvm_component;
uvm_blocking_transport_port #(itrans, otrans) bt_port;
`uvm_component_utils(comp1)
...
task run_phase(uvm_phase phase);
itrans itr;
otrans otr;
int trans_num = 2;
for(int i = 0; i < trans_num; i++) begin
itr = new("itr", this);
itr.id = i;
itr.data = 'h10 + i;
this.bt_port.transport(itr, otr);
`uvm_info("TRSPT", $sformatf("put itrans id: 'h%0x, data: 'h%0x | get otrans id: 'h%0x, data: 'h%0x", itr.id, itr.data, otr.id, otr.data), UVM_LOW)
end
endtask
endclass
class comp2 extends uvm_component;
uvm_blocking_transport_imp #(itrans, otrans, comp2) bt_imp;
`uvm_component_utils(comp2)
...
task transport(itrans req, output otrans rsp);
rsp = new("rsp", this);
rsp.id = req.id;
rsp.data = req.data << 8;
endtask
endclass
class env1 extends uvm_env;
comp1 c1;
comp2 c2;
`uvm_component_utils(env1)
...
function void build_phase(uvm_phase phase);
super.build_phase(phase);
c1 = comp1::type_id::create("c1", this);
c2 = comp2::type_id::create("c2", this);
endfunction
function void connect_phase(uvm_phase phase);
super.connect_phase(phase);
c1.bt_port.connect(c2.bt_imp);
endfunction
endclass
Bidirectional port processing is similar to unidirectional port instantiation and connection, the difference is that the corresponding bidirectional transmission tasks are required to be implementedtask transport(itrans req, output otrans rsp)