ajustesen Posted November 4, 2011 Report Share Posted November 4, 2011 Consider the following situation: A DUT has interfaces A, B, C and D. The DUT's normal flow is like this: 1. DUT receives a transaction on interface A 2. DUT sends a transaction related to A on interface B 3. DUT receives a transaction on interface C that's a response to the transaction on interface B 4. DUT sends a transaction on interface D related to the transaction on interfaces A & C. We have separate, reusable agents on each interface (i.e. agent A, agent B, agent C and agent D). The DUT is pipelined, so we can send transactions on interface A back-to-back. In other words, we can send a second transaction on interface A before the first transaction appears on interface B. The data in transaction C has dependencies on transaction A, so I would like to have constraints on C based on A. What is the best way to solve this problem? What we have done in the past is create a top level sequence (it used to be called a virtual sequence) that would create and randomize sequences for agents A & C. The top sequence sends sequence A, waits for transaction B via a monitor subscriber, sends transaction C, and possibly waits for transaction D via a different monitor subscriber. We have been putting these subscribers in our top sequencer. The obvious problem with this is that this sequence doesn't allow for pipelined behavior. Sequencers only run one sequence at a time. The sequencer will not get the next sequence until the first sequence's body() task has completed. The solution that we had come up with until UVM 1.1 was to have the body() task of the top sequence fork off a thread to handle submitting the other sequences and exit in zero time. The sequencer would then start the next sequence while that thread from the first sequence was still executing. The sequence would look something like this: class top_sequence extends uvm_sequence; a_sequence a_seq; c_sequence c_seq; `uvm_declare_p_sequencer(top_sequencer) `uvm_object_utils(top_sequence) virtual task body(); a_seq = a_sequence::type_id::create("a_seq"); c_seq = c_sequence::type_id::create("c_seq"); a_seq.randomize() with {...}; c_seq.randomize() with {...}; fork begin a_seq.start(p_sequencer.a_seqr); p_sequencer.b_subscriber.wait_for_trans(); c_seq.start(p_sequencer.c_seqr); p_sequencer.d_subscriber.wait_for_trans(); end join_none endtask : body endclass : top_sequence When we upgraded to UVM 1.1, we started seeing these error messages: UVM_ERROR ../../uvm/src/seq/uvm_sequencer_base.svh(1196) @ 1895.804 ns: uvm_test_top.env.top_sequencer [sEQFINERR] Parent sequence 'uvm_test_top.env.top_sequencer.top_seq' should not finish before all items from itself and items from descendent sequences are processed. The item request from the sequence 'uvm_test_top.env.top_sequencer.top_seq.a_seq' is being removed. This tells me that we're not supposed to be doing what we were doing! Specifically, sequences need to be done when they exit their body() task. So I need a new solution to this problem. Ideally, I'd like to continue to use my existing top sequences and find some way to run them in parallel (perhaps without a fork-join_none). Thanks in advance for any ideas and constructive comments. Quote Link to comment Share on other sites More sharing options...
Erling Posted November 4, 2011 Report Share Posted November 4, 2011 One thing to try could be to have the top_sequence block until the subsequences are finished, and then from wherever you start the top_sequence, run the desired number of top_sequences in parallel. For this to work, there has to be some way to relate a dut response to the right request due to the pipelining, but I guess you have a solution for that problem already. Erling Quote Link to comment Share on other sites More sharing options...
dkrening Posted August 30, 2012 Report Share Posted August 30, 2012 If you need to fork threads in parallel you must use fork/join_none. But if you want to keep the top sequence alive you would like to use fork/join instead. Usually the solution to this dilemma is to use a fork/join_none/wait construct. fork . . . join_none wait fork; Now all your child sequences will fork off in parallel, but the top sequence won't exit until all the threads complete. Quote Link to comment Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.