In this post, we will discuss the interesting challenge of reset during simulation.
Specman has a very robust implementation of reset during test, which imitates a return to cycle 0. All threads are terminated, the run() method is called again, and evaluation of temporal expressions is restarted. UVM Testflow has the option to go back to any phase, not just to cycle 0, by calling rerun_phase(target phase). When issuing rerun_phase, making the extreme decision to "just kill all threads" is generally a bad idea. For example, some monitoring threads should run continuously throughout the test, uninterrupted, recording all activities on line.
The UVM Testflow contains an API providing the verification engineers and test writers fine tuned control of component behavior during the rerun_phase.
Let us look, for example, at sequences. Three entities are part of the sequence mechanism:
- 1. Sequence(s)
- 2. BFM
- 3. Sequence driver (seq-er).
Sequence
Some sequences are phase independent. These sequences should continue running completely unaffected by the rerun_phase().
On the other hand, some sequences define a scenario which is phase dependant. Example -- a series of initialization transactions is phase dependant: If the INIT_DUT phase is terminated with a rerun_phase, the initialization sequence should stop.
If a sequence is phase dependent, you should register it to the appropriate phase, so as to achieve the following:
- 1. The sequence is terminated if the phase is terminated.
- 2. If you registered the sequence with blocking == TRUE (that is, the sequence blocks the phase), the domain will not proceed to next phase before the sequence had finished.
You register sequences to a phase using register_sequence. For example:
extend MAIN MAIN_TEST my_seq {!sub_seq1 : SEND_DATA my_seq;
body() @driver.clock is only {
gen sub_seq1 keeping {.driver == me.driver; .ctr == 1};
sub_seq1.start_sequence();
// register to the FINISH_TEST phase, as blocking
driver.tf_get_domain_mgr().register_sequence(sub_seq1,
FINISH_TEST,
TRUE);
};
};
Bus Functional Model (BFM)
If a BFM serves one domain, it can be seen as belonging to the domain, and get rerun whenever the domain undergoes reset. On the other hand, if a BFM serves sequences from various domains, the BFM should not be affected by rerun_phase, and should run continuously throughout the test.
Registration of a BFM to a phase is done using the register_thread_by_name api: For example:
extend my_bfm {
tf_main_test()@tf_phase_clock is also {
// start the main TCM
start getting_items();
driver.tf_get_domain_mgr().register_thread_by_name(me,
"getting_items",
POST_TEST,
FALSE);
};
};
Sequence Driver (seq-er)
The seq-er maintains a list of ‘do' requests coming from the running sequences. When rerun_phase is issued, there is a question of what to do with the items in the queue.
One option is for the seq-er to clean the queue, that is, to remove all items and "start from fresh."
However, if the seq-er handles items coming from higher levels that are unaware of the reset, it should not clean the queue. Instead, once reset is finished and BFM up and running again, the seq-er should continue passing to the BFM the items have been waiting in the queue there since before the reset. In this case, the reset of the low level and its BFM is said to be transparent to the high level sequences.
Defining the seq-er behavior upon rerun_phase is done using the seq-er Testflow API. For example:
extend my_driver {
tf_to_clean_previous_bfm_call(next_phase: tf_phase_t) : bool is {
result = TRUE;
};
tf_to_clean_do_queue(next_phase : tf_phase_t) : bool is {
result = TRUE;
};
};
Read more about Testflow, rerun_phase, and registration of objects in the UVM e User Guide and UVM e Reference manual.
Efrat Shneydor,
UVM e