Multi-directional communication (more important)

Table of contents

1. Overview (there are many application scenarios)

Two, examples 


1. Overview (there are many application scenarios)

  • The multi-directional communication service is still the communication between two components, not the communication between multiple components . After all, the communication of multiple components can still be constructed by the basic communication method of two components.
  • Multi-directional communication refers to the processing solution if the number of the same TLM port between the initiator and the target exceeds one.

 comp1 has two uvm_blocking_put_ports, and comp2 has two uvm_blocking_put_imp ports. Different names can be given to port instantiation, and connections can also be indexed by different names, but the problem is that two task puts (itrans t) need to be implemented in comp2, and because different ports require a dedicated method on the side of the imp port, This causes a method naming conflict , that is, two put tasks with the same name cannot be defined in comp2.

UVM solves this problem through port macro declaration . The core of its solution is to make different ports correspond to tasks with different names. According to the naming method of the port name, UVM is divided into macros to solve multi-directional communication problems:

Note: _decl: declaration statement

      (SFX): indicates the suffix name

Two, examples 


`uvm_blocking_put_imp_decl(_p1)  //宏声明:定义第一个独一无二端口
`uvm_blocking_put_imp_decl(_p2)  //宏声明:第一第二个独一无二端口
class comp1 extends uvm_component;
	uvm_blocking_put_port #(itrans) bp_port1;
	uvm_blocking_put_port #(itrans) bp_port2;
	`uvm_component_utils(comp1)
	...
	task run_phase(uvm_phase phase);
		itrans itr1, itr2;
		int trans_num = 2;
		fork
			for(int i = 0; i < trans_num; i++) begin
				itr1 = new("itr1", this);
				itr1.id = i;
				itr1.data = 'h10 + i;
				this.bp_port1.put(itr1);
			end
			for(int j = 0; j < trans_num; j++) begin
				itr2 = new("itr2", this);
				itr2.id = i;
				itr2.data = 'h10 + i;
				this.bp_port2.put(itr2);
			end
		join
	endtask
endclass

class comp2 extends uvm_component;
	uvm_blocking_put_imp_p1 #(itrans, comp2) bt_imp_p1;
	uvm_blocking_put_imp_p2 #(itrans, comp2) bt_imp_p2;
	itrans itr_q[$];
	semaphore key;
	`uvm_component_utils(comp2)
	...
	task put_p1(itrans t);
		key.get();
		itr_q.push_back(t);
		`uvm_info("PUTP1", $sformatf("get otrans id: 'h%0x, data: 'h%0x", t.id, t.data), UVM_LOW)
		key.put();
	endtask
	task put_p2(itrans t);
		key.get();
		itr_q.push_back(t);
		`uvm_info("PUTP2", $sformatf("get otrans id: 'h%0x, data: 'h%0x", t.id, t.data), UVM_LOW)
		key.put();
	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_port1.connect(c2.bt_imp_p1);
		c1.bt_port2.connect(c2.bt_imp_p2);
	endfunction
endclass

Guess you like

Origin blog.csdn.net/Arvin_ing/article/details/127709841