Sunday, April 13, 2014

Hierarchical Sequences in UVM

Rising design complexity is leading to near exponential increase in verification efforts. The industry has embraced verification reuse by adopting UVM, deploying VIPs and plugging block level env components at sub system or SoC level. According to a verification study conducted by Wilson research in 2012 (commissioned by Mentor) the engineers spend ~60% of their time in developing/running tests and debugging failures. While the report doesn’t zoom in further, the verification fraternity would agree that a considerable chunk of this bandwidth is spent because the test developer didn’t have flexible APIs (sequences) to create tests and ill planned verification environment lead to extra debug. UVM provides a recommended framework that if incorporated effectively can overcome such challenges. Hierarchical Sequences in UVM is one such concept suggesting sequence development in a modular fashion to enable easier debug, maintenance and reuse of the code.

As in LEGO, hierarchical sequences postulate development of base structures and assembling them in an orderly fashion to build desired structures. This process demands considerable planning right from the beginning with theend goal in mind. Definition of the base sequences determine the flexibility offered for effective reuse. The aim is to develop atomic sequences such that any complex sequence can be broken down into a series of base sequences. A few aspects worth considering include –

TIP 1: Define a sequence that generates a basic transaction depending upon the constraints passed to the sequence. To implement this, local variables corresponding to the sequence item members are defined in the sequence. These fields can be assigned values directly while calling the sequence from the high level sequences or test. The values received by the sequence are passed as inline constraints while generating the transaction. This provides full control to the user to generate the desired transaction.

TIP 2: Bundle the fields to be controlled into a configuration object and use the values set for this object to derive the inline constraints of the transaction to be generated. This is a complex version of TIP 1 particularly useful when either there is large number of variables in the transaction class or multiple base sequences are created having similar variables to be configured. This class can have fields directly linked to the sequence item and additional variables to control the sequence behavior. It is best to define a method to set the Config object. Note that this Config object has nothing to do with Config DB in UVM.

TIP 3: UVM provides Configuration DB to program the components of environment for a given scenario. As complexity increases, it is desired to read the configuration of a given component or understand the current state of a component and use this information while generating the transaction. Having a handle of the UVM component hierarchy in the base sequence facilitates development of sequences is such cases.

Once the base sequences are defined properly, a hierarchy can be developed enabling reuse and reducing margin of error. Let’s apply this to a bus protocol e.g. AMBA AHB. Irrespective of the scenario, an AHB master would finally drive a READ or a WRITE transaction on the bus. So our base sequence can be L0_AHB_READ and L0_AHB_WRITE. These sequences generate an AHB transaction based on the constraints provided to them as in TIP 1. Next level (L1) would be to call these sequences in a loop wherein the no. of iterations is user defined. Further we can develop a READ_AFTER _WRITE sequence wherein the sequences L1_LOOP_WRITE and L1_LOOP_READ are called within another loop such that it can generate Single Write followed by Read OR Bulk Write followed by Read. Using the above set of sequences any scenario can be generated such as configuration of any IP, reading data from an array/file and converting it into AHB transactions or interrupt/DMA sequences etc.

Deploying UVM is a first step towards reuse. To control the efforts spent on developing tests and debugging verification code, UVM needs to be applied effectively and that is beyond the syntax or proposed base class library. Hierarchical sequences demand proper planning and a disciplined approach. The observed returns are certainly multi-fold. This reminds me of a famous quote from Einstein – Everything Should Be Made as Simple as Possible, But Not Simple!

Suggested Reading -


  1. I find that Tip 1 disagrees with the final quote of making things simple. Why create an extra layer of complexity around a sequence item just to start that as a sequence? I'm a big fan of sequence layering, but this step just seems useless to me. You're anyway going to spend most of your time writing sequences at a higher level than just doing bus writes and reads (think register layering).

  2. Timi,

    Thanks much for sharing your comment. In the example referenced, if we see AHB only in the context of register programming where the adapter would take care of converting the register RW calls into AHB RW transactions then TIP 1 may be less relevant. As mentioned we need to keep the end goal in mind. As a VIP developer one would want to consider other applications where the transactions are not only register related. Interestingly if you read the Sequence layering post, the hierarchical sequence concept may seem redundant. IMO these are concepts that need to be applied based on the context or desired applications of the code. SIMPLE always helps in whatever way it is :)

  3. I think you have missed a massive opportunity to discuss abstraction sequences. Yes I agree that we can use hierarchical sequences to generate specific combinations of sequence items, however the principle of constrained random verification is to start unconstrained and constrain as required.
    To that end I prefer abstractions sequences: sequences that are of an abstract concept to a bus, e.g. video frames. This sequence would run on a separate sequencer (outside of a UVC). A sequence generates random frames, a conversion sequence running on the UVC sequencer would translate these sequence items to whatever level of sequence hierarchy is required on the UVC sequencer.
    This approach is much more manageable than aimlessy extending sequence after sequence.

  4. Thanks much for bringing out this specific point. The abstract sequence that you are referring to is a concept coming out from "Sequence layering" in UVM. We develop tests at an abstract level in a layering agent that connects to the sequence of underlying protocol to convert into protocol specific transaction. Please refer to an earlier blog post on this topic -

    Hierarchy is protocol specific (the same sequence item continues) while layering is adding abstraction (a new abstract sequence item is introduced).