2 process writing on an analysis port from monitor

I have 2 process in monitor using same analysis port from monitor
This is the code :

class m_monitor extends uvm_monitor;
  ..........

  uvm_analysis_port#(sequence_item) mon_port;
  virtual intf_ vif;

  ..........

  sequence_item debugpkt, donepkt;  

  task detect_debug();
    wait(vif.debug_high == 1);
    debugpkt = sequence_item::type_id::create("debugpkt");
    debugpkt.DATAscanout = vif.DATAscanout;
    
    mon_port.write(debugpkt);
  endtask

  task detect_done();
    wait(vif.done_ == 1);
    donepkt = sequence_item::type_id::create("donepkt");
    donepkt.CTRLscanout = vif.CNRLscanout;
    
    mon_port.write(donepkt);
  endtask

  task run_phase(uvm_phase phase);
    for
      detect_debug();
      detect_done();
    join
  endtask
endclass : m_monitor

As you can see from code, I have 2 write operation into same analysis port.
Will my coding leads to any failure/data lose in writing operation into analysis port?

In reply to bachan21:

That all depends on the code subscribed to the analysis port. Each call to write() gets implemented into a separate call to write() in the subscriber. Does it know you have different names to the sequence items?

In reply to dave_59:

I am simply storing the objects into a queue in the scoreboard during the implementation. All I am bothered about one write call blocking another write calls execution if calls are made at same time. If it blocks some packets, I guess we can use a fifo to avoid the situation.

In reply to bachan21:

write() is a function; it cannot block(consume time).

Hi Dave,

Actually I also encounted the same problem. So in the above case, if the two write() happens at the same time, is the covergroup in the subscriber able to sample both debugpkt.DATAscanout and donepkt.CTRLscanout?

// The two write() happens at the same time in the above case
sequence_item debugpkt, donepkt;
mon_port.write(debugpkt);
mon_port.write(donepkt);

// Inside the subscriber
sequence_item my_seq_item;

function void my_subscriber::write(sequence_item t);
    my_seq_item = t;
    my_cg.sample();
endfunction

covergroup my_cg;
    coverpoint my_seq_item.DATAscanout;
    coverpoint my_seq_item.CTRLscanout;
endgroup

What is the difference between debugpkt and donepkt? It is all of type sequence_item. It should have the same data members.

Yes, they are the same type and they have the same data members. It’s only two objects for different tasks run in parallel in the above case, and each task handling different data members.

task run_phase(uvm_phase phase);
    fork
        detect_debug();
        detect_done();
    join
endtask

The way you have written your code, the covergroup gets sample twice and both items have DATAscanout and CTRLscanout fields. We don’t know how that affects your coverage model. (what is in debugpkt.CTRLscanout and donepkt.DATAscanout when each item gets sampled.

Sorry that I was using the code from the original post which makes it confusing. Please see the below code.

My question is that if the 3 ap.write() happens at the same time, is the covergroup able to sample all the pkt1, pkt2 and pkt3? Another question is that when monitoring the interface which has many signals, is it better to have multiple monitors or the below implementation is ok?

Any suggestions would be appreciated. Many thanks!

class my_seq_item extends uvm_sequence_item;

	logic [31:0]	lp_cfg;
	logic			lp_cfg_vld;
	
	logic [31:0]	pl_cfg;
	logic			pl_cfg_vld;
	
	logic [2:0]		pl_speedmode;
	
	......
	
endclass

class my_monitor extends uvm_monitor;

	......
	
	uvm_analysis_port#(my_seq_item)		ap;
	virtual	my_if						vif;
	
	my_seq_item		pkt1, pkt2, pkt3;
	
	......
	
	task run_phase(uvm_phase phase);
		fork
			get_lp_pkt();
			get_pl_pkt();
			get_speedmode();
		join
	endtask	
	
	task get_lp_pkt();
		forever begin
			@(negedge vif.clk);
			if (vif.lp_cfg_vld) begin
				pkt1 = my_seq_item::type_id::create("pkt1");
				pkt1.lp_cfg = vif.lp_cfg;
				ap.write(pkt1);
			end
		end
	endtask
	
	task get_pl_pkt();
		forever begin
			@(negedge vif.clk);
			if (vif.pl_cfg_vld) begin
				pkt2 = my_seq_item::type_id::create("pkt2");
				pkt2.pl_cfg = vif.pl_cfg;
				ap.write(pkt2);
			end
		end
	endtask
	
	task get_speedmode();
		forever begin
			@(negedge vif.clk);
			pkt3 = my_seq_item::type_id::create("pkt3");
			pkt3.pl_speedmode = vif.pl_speedmode;
			ap.write(pkt3);
		end
	endtask
	
endclass

class my_coverage extends uvm_subscriber#(my_seq_item);

	my_seq_item		pkt;
	
	......
	
	covergroup my_cg;
		coverpoint pkt.lp_cfg;
		coverpoint pkt.pl_cfg;
		coverpoint pkt.pl_speedmode;
	endgroup
	
	function void write(my_seq_item t);
		pkt = t;
		my_cg.sample();
	endfunction 
	
endclass

3 calls to ap.write() will never happen simultaneously; they will get called in some undefined yet deterministic order. But the way your covergroup is written, lp_cfg, pl_cfg, and pl_speedmode get sampled simultaneously times regardless of whether the 3 tasks in the monitor have set them. Given that you have defined them with a logic datatype they will have the value 'x and be ignored from coverage. If you had used a 2-state datatype like bit that would not be the case.

Thanks @dave_59 ! That is very helpful.

Besides, is there any advice on the below question? What’s the metric? If using multiple monitors instead, can I uvm_config_db#()::get() the same interface in different monitors?

Another question is that when monitoring the interface which has many signals, is it better to have multiple monitors or the below implementation is ok?

Multiple monitors, unless there is some benefit having them together.

1 Like