Flow control with virtual sequence

Hi all!
i’m trying to make a virtual sequence with a little bit more complex flow control, then described in UVM cookbook (maybe, there are examples there like the one i need, but i could’n find it=\ ).

class enchancer_virtual_sequence extends uvm_sequence#( uvm_sequence_item );

  v_data_sequencer	#(...)  v_data_seqr;

  enchancer_coefs_sequencer 	enchancer_coefs_seqr;
	
  v_data_sequence 					v_data_seq;
  enchancer_coefs_sequence 	enchancer_coefs_seq;
	
	
  function new( string name = "" );
     super.new( name );
  endfunction: new

task body();
fork: f_block
begin
v_data_seq = v_data_sequence::type_id::create( .name( "v_data_seq" ) );
v_data_seq.start( .sequencer( v_data_seqr ), .parent_sequence( this ) );
disable f_block;
end
			
begin
forever
begin
enchancer_coefs_seq = enchancer_coefs_sequence::type_id::create( .name( "enchancer_coefs_seq" ) );
enchancer_coefs_seq.start( .sequencer( enchancer_coefs_seqr ), .parent_sequence( this ) );

end
end
join

endtask: body
   
   `uvm_object_utils( enchancer_virtual_sequence )

endclass: enchancer_virtual_sequence

i have two flows here: one with video data, and another with coefficients.
video ata sequene looks like this

class v_data_sequence extends uvm_sequence#( v_data_transaction	#(...));

  function new( string name = "" );
    super.new( name );
  endfunction: new
  
task body();
  v_data_transaction	#(...) v_data_tx;
int line_num = 0;
int elem_n = 0;

for (int line_num = 0; line_num < 1024; line_num++)
begin
for (int elem_n = 0; elem_n < 20+4+4; elem_n++)
begin
v_data_tx = v_data_transaction	#(...)::type_id::create( .name( "v_data_tx" ));
start_item( v_data_tx );
assert( v_data_tx.randomize() );

if ((elem_n >= 4) && (elem_n <= 23))
begin
v_data_tx.x_active = 1;
end
else
begin
v_data_tx.x_active = 0;
End
finish_item( v_data_tx );
end
end
endtask: body

  `uvm_object_utils( v_data_sequence )

endclass: v_data_sequence

i want to send coefficients onle when x_active (signal in video data flow) is low. Yet i don’t know, what is the proper way to synchronize my coefficient flow with this event.

here’s video data seqence item:

class v_data_transaction #(...) extends uvm_sequence_item;
  
 rand bit [N_COMP-1:0][V_DATA_WIDTH-1:0] v_data;
 rand bit [Y_WIDTH-1:0] y;
 rand bit[X_WIDTH-1:0] x;
 bit x_active;
...

how should i synchronize my data lows?
thank you for reading

In reply to trogers:

Hi trogers,

I think if there is virtual interface handle in the env config, the signal information can be got in the virtual sequence through its sequencer. 

Best regards,
Yao He

In reply to yaohe:

Hi yaohe,

thank you for your reply.
I’m not sure that i understand it. You want to say, that i need to track signal “x_active” through virtual interface from my virtual sequence? If that’s correct, could you please give an example?

Ok, i’ve found out how to synchronyze my sequences. i’ve decided to write tasks in agent’s configuration objects, like this:

class v_data_agent_config #(
parameter V_DATA_WIDTH = 10,
parameter N_COMP       = 1,
parameter Y_WIDTH      = 10,
parameter X_WIDTH      = 10
) extends uvm_object;
  `uvm_object_param_utils( v_data_agent_config #(
.V_DATA_WIDTH(V_DATA_WIDTH),
.N_COMP(N_COMP),
.Y_WIDTH(Y_WIDTH),
.X_WIDTH(X_WIDTH)
)
)

  uvm_active_passive_enum active = UVM_ACTIVE;// if active, has sequencer and driver,
	//otherwise has only monitor
  bit has_v_data_fc_sub = 1; // switch to instantiate a functional coverage subscriber
	
  virtual v_data_if #(
.V_DATA_WIDTH	(V_DATA_WIDTH),
.N_COMP	(N_COMP),
.Y_WIDTH		(Y_WIDTH),
.X_WIDTH		(X_WIDTH)
) v_data_bus;
	
	
  function new( string name = "" );
    super.new( name );
  endfunction: new
	
	extern task wait_for_unactive_part;
	
endclass: v_data_agent_config

task v_data_agent_config::wait_for_unactive_part;
	@(negedge v_data_bus.x_active);
endtask: wait_for_unactive_part
class avalon_mm_agent_config #(
parameter ADDR_WIDTH = 10,
parameter DATA_WIDTH = 10
) extends uvm_object;
	`uvm_object_param_utils( avalon_mm_agent_config #(
.DATA_WIDTH(DATA_WIDTH),
.ADDR_WIDTH(ADDR_WIDTH)
)
)

	uvm_active_passive_enum active = UVM_ACTIVE;// if active, has sequencer and driver,
	//otherwise has only monitor
	bit has_avalon_mm_fc_sub = 1; // switch to instantiate a functional coverage subscriber
	
	virtual avalon_mm_if #(
.DATA_WIDTH(DATA_WIDTH),
.ADDR_WIDTH(ADDR_WIDTH)
) avalon_mm_bus;

	function new( string name = "" );
		super.new( name );
	endfunction: new
	
	task wait_for_readdata (bit [DATA_WIDTH-1:0] readdata);
		@(posedge avalon_mm_bus.readdatavalid);
		readdata = avalon_mm_bus.readdata;
	endtask

	task wait_clock (int i);
		repeat (i) @(posedge this.avalon_mm_bus.clk);
	endtask
	
endclass: avalon_mm_agent_config

i have these configuration objects in uvm database, so i “::get” them in my sequences and use task to synchronize.
BUT i get an error at elaboration time:

" Virtual interface resolution cannot find a matching instance of interface 'avalon_mm_if '." 

Elaboration goes well for ‘v_data_if’, but fails for ‘avalon_mm_if’.

i commented tasks in avalon_mm_agent_config and looked local variables it that object. This interface does exist (it’s not null). And, actually, my driver sends data through it.

Here Virtual interface resolution cannot find a matching instance of interface | Verification Academy i’ve found posts, describing a problem, which looks just like mine, but didn’t find an explanation, because true matching interface IS found (otherwise avalon_mm_bus would be null, right?). Why does this happen? Is it Questa’s bug?