On the DUT I have two channels each consisting of a data interface and a sideband interface. The transactions that are sent down these channels must in order but one channel can stall back while the other channel catches up. I.E: I send transaction A down channel 0, transaction C down channel 1, but channel 1 will not accept transaction C until channel 0 has recieved transaction B.
Furthermore the data interface can be slower than the sideband interface on each channel and certain sideband transactions do not require data to be sent with them.
Currently the tests are set up to create the individual data and sideband sequences, place them into queues then split the queues into the number of channels and send them. However this is becoming difficult to maintain with interface changes on the channels and varying number of channels per configuration. So ideally I'd like to write the test sequence so that it has no knowledge of how many channels are there or what interface needs data for the abstract transaction.
The top sequence should just generate sequences like this:
'uvm_do(open_data_stream_sequence);
'uvm_do_with(send_data_sequence, {send_data_sequence.packet_number == 0;});
'uvm_do_with(send_data_sequence, {send_data_sequence.packet_number == 1;});
'uvm_do_with(send_data_sequence, {send_data_sequence.packet_number == 2;});
'uvm_do_with(send_data_sequence, {send_data_sequence.packet_number == 3;});
'uvm_do(close_data_stream_sequence);
The problem with this approach is that I do not want one channel to block the other or one interface to block the other unless both are stalled back. If I use a virtual sequence like above, the open_data_stream_sequence may stall for that individual channel when I want to pipeline the send_data_sequence into the other channel or it may stall on the sideband interface but I want to pipeline the send_data_sequence data transaction onto the same channel's data interface.
However I'm struggling to figure out how to implement the arbitration between the subsequencers. I thought about sequence layering and the use of fifos to only stall when all interfaces are saturated in a kind of middle layer. Is there asny UVM tricks I'm missing?