Verification Guild
A Community of Verification Professionals
Search


  Login  
Nickname

Password

Security Code:
Security Code
Type Security Code
BACKWARD
Don't have an account yet? You can create one. As a registered user you have some advantages like theme manager, comments configuration and post comments with your name.

  Modules  
  • Home
  • Downloads
  • FAQ
  • Feedback
  • Recommend Us
  • Web Links
  • Your Account

  •   Who's Online  
    There are currently, 125 guest(s) and 1 member(s) that are online.

    You are Anonymous user. You can register for free by clicking here

     
    Verification Guild :: View topic - Implementing Functional Coverage in Vera 6
     Forum FAQForum FAQ   SearchSearch   UsergroupsUsergroups   ProfileProfile   Private MessagesPrivate Messages   Log inLog in 

    Implementing Functional Coverage in Vera 6

     
    This forum is locked: you cannot post, reply to, or edit topics.   This topic is locked: you cannot edit posts or make replies.    Verification Guild Forum Index -> Coverage
    View previous topic :: View next topic  
    Author Message
    Newsletter
    Original Contribution


    Joined: Dec 08, 2003
    Posts: 1107

    PostPosted: Sat Aug 09, 2003 11:00 pm    Post subject: Implementing Functional Coverage in Vera 6 Reply with quote

    (Originally from Issue 4.13, Item 8.0)

    From: Mike Thompson Send e-mail

    We are transitioning from Vera5.2 to Vera6 and are working to define
    the optimal model for defining functional coverage in Vera6.0. The
    new "embedded coverage groups" in Vera6 are attractive, but we wish to
    keep our coverage model external to our class definitions. The reason
    for this is that a given Verification Component (VC) may be
    instantiated in multiple environments and have coverage goals unique
    to each environment. One way of using embedded coverage groups with
    this model is to extend the class and add embedded coverage to the
    extension:

    enum beer_brand = golden, guinness, harp, rickards;

    class beer_c {
    rand beer_brand brand;
    }

    class beer_cov_c extends beer_c {
    event randomized;

    coverage_group beer_cov {
    sample_event = sync(ANY, randomized); // see post_randomize()
    sample brand {
    state s_golden (golden);
    state s_guinness (guinness);
    state s_harp (harp);
    state s_rickards (rickards);
    at_least = 10;
    coverage_goal = 100; // goal for sample
    }
    coverage_goal = 100; // goal for group
    }

    // post_randomize() is automatically called after randomization
    task post_randomize() {
    trigger(ONE_BLAST, randomized); // emit for coverage
    }
    }

    The above works, but now the environment has to instantiate
    beer_cov_c, not beer_c. This has the potential of creating a
    maintenance situation. Are there any better ideas out there?
    Back to top
    View user's profile
    Newsletter
    Original Contribution


    Joined: Dec 08, 2003
    Posts: 1107

    PostPosted: Sun Aug 31, 2003 11:00 pm    Post subject: Implementing Functional Coverage in Vera 6 Reply with quote

    (Originally from Issue 4.14, Item 4.0)

    From: Frank Armbruster Send e-mail

    Well, I don't know a better way to do this in Vera, but with Specman
    and e, the solution is rather natural. This is due to the support of:

    - aspect oriented programming and
    - coverage group definitions per instance

    The first feature enables you to keep your coverage model external to
    your class definitions in the VC. You are able to define, or to
    change, the coverage group outside of your original verification
    component (VC) code.

    You can load your coverage definition on top of the VC code, which
    solves your maintenance issue.

    Per-instance coverage enables you to define different flavours of the
    same coverage group for each instance of the Verification Component.

    At the end you always end up load only one set of files containing the
    basic verification component (VC), plus one coverage configuration
    file that contains all the specifics for each instance of your VC.

    Taking your example it looks like:

    // VC code: i.e. file: beer_vc_base.e
    type beer_brand [golden, guinness, harp, rickards];

    struct beer_c {
    brand : beer_brand;
    };

    // What you do here:
    // - use aspect orientation to define coverage outside of base class
    // VC code: i.e. file: beer_vc_cover.e
    extend beer_c {
    event beer_cov;

    cover beer_cov is {
    // need 10 samples of each enum to report 100%
    item brand using at_least=10, per_instance;
    };

    post_generate() is also {
    emit beer_cov;
    };
    };

    // What you do here:
    // 1. - use aspect orientation to change coverage group outside of
    // VC code
    // 2. - use coverage per instance to define different bahavior for
    // each instance of the VC in the environment

    // your configuration file, i.e. beer_cover_config_project1.e
    // a.) want to have more guiness and less harp :-)
    // b.) leave the original definition of the group for all others
    extend beer_c {
    cover beer_cov(brand==guiness) is also {
    item using also at_least=20;
    };
    cover beer_cov(brand==harp) is also {
    item using also at_least=5;
    };
    };

    The import file for your verification environment looks like:

    import beer_vc_base; // VC base code
    import beer_vc_cover; // VC base code

    import beer_cover_config_project1; // your configuration

    You have seperation of the concerns pretty natural and therefore you
    can maintain them in seperate files.

    - Frank Armbruster, Lead Consulting Engineer
    Verisity Design
    Back to top
    View user's profile
    Newsletter
    Original Contribution


    Joined: Dec 08, 2003
    Posts: 1107

    PostPosted: Sun Aug 31, 2003 11:00 pm    Post subject: Implementing Functional Coverage in Vera 6 Reply with quote

    (Originally from Issue 4.14, Item 4.1)

    From: Janick Bergeron <a href="/contact.php?to=yW3ASxI7BUj-24-2bF8B8-2bF"><img src="/modules/Forums/templates/subSilver/images/lang_english/icon_email.gif" alt="Send e-mail" title="Send e-mail" border="0" /></a>

    You are wise to want to keep your functional coverage model separate
    from your data model. The former is DUT or test-specific whereas the
    latter is reusable between tests, environments and projects.

    First, let's answer the question you are asking...

    What you did so far is perfectly correct, except for your choice of
    beer brands and the way you have addressed the race condition between
    the triggering of the "randomized" event and the sampling of the
    functional coverage group.

    It would be better solved by using a regular trigger and an *ASYNC*
    coverage sampling. That way, you'll correctly sample consecutive
    randomizations of the same instance within the same simulation
    timestep:

    Code:

       class beer_cov_c extends beer_c {
          event randomized;
       
       
          coverage_group beer_cov {
              sample_event = sync(ANY, randomized) async; // <-- ASYNC sample
                  sample brand {
                      state s_sleemans        (sleemans);
                      state s_upper_canada    (upper_canada);
                      state s_blanche_chambly (blanche_chambly);
                      state s_rickards        (rickards);
                      at_least = 10;
                      coverage_goal = 100; // goal for sample
                   }
                   coverage_goal = 100; // goal for group
              }
       
       
          // post_randomize() is automatically called after randomization
          task post_randomize() {
              trigger(randomized); // emit for coverage
          }
       }


    If you have designed your generator to take advantage of the
    polymorphism offered by Vera's OO programming model, having the
    generator use beer_cov_c instead of beer_c is easy. First of all, you
    need to write your generators (or any transactors that creates
    instances of beer_c) to use a factory pattern. The factory should be a
    public data member initialized with a default factory instance in the
    constructor:

    Code:

       class beer_brewery_c {
          beer_c recipe;

          task new() {
             this.recipe = new;
          }

          function beer_c brew() {
             void = this.recipe.randomize();
             brew = new this.recipe;
          }
       }


    Your environment instantiates the brewery in the environment
    (preferably near a university), and supplies any recipe you wish, such
    as the one containing your coverage model:

    Code:

       class environment {
          brewery_c micro;

          task new() {
             beer_cov_c beer_with_cov = new;
             micro = new;
             micro.recipe = beer_with_cov;
          }
       }


    The nice thing with this approach is that your individual testcases on
    the environment can supply their own (different or augmented) recipes,
    or supply different recipes to different breweries...

    Code:

       class lager_c extends beer_cov_c {
          constraints lagers_only {
             brand in {sleemans; upper_canada};
          }
       }

       program testcase {
          environment pub = new;
          lager_c lager_with_cov = new;

          pub.micro.recipe = lager_with_cov;
          repeat (1000) {
             beer_c bottle = pub.micro.brew();
             ...
          }
       }



    However, I think I need to address what I think you want, not what you
    asked for...

    Functional coverage should be associated with components of your
    environment that have a static lifetime throughout a simulation
    (i.e. get created at the begining and be destroyed only at the end)
    such as transactors, bus-functional models, generators and DUT
    signals. It should not be associated with the data that flows through
    them or that is being covered.

    If functional coverage groups are ultimately instantiated in data
    objects, there will be several thousands instances, each recording few
    information items. The only useful analysis is through a cumulative
    analysis. Cross coverage with a stream identifier (if available) would
    be the only mechanism for differentiating functional coverage on
    different data streams.

    If the functional coverage groups are ultimately instantiated in
    transactors, they have a static lifetime throughout the simulation.
    They record a lot of information about the hundred of data items that
    flow through the transactor. Instance-specific metrics can be analyzed
    for stream-specific coverage information. Cumulative metrics can also
    be used to analyze global coverage.

    Furthermore, associating functional coverage with randomization may
    yeild unreliable coverage data: does the fact that an object instance
    has been generated implies that it has been transmitted, as-is, to the
    DUT? What if errors were subsequently injected in the data on its way
    to the DUT? What if the test was aborted before? Functional coverage
    should be collected as close as possible to the DUT (ideally from a
    monitor/checker stack directly on the primary DUT signals) where the
    relevant context information is available.

    Using your example above, I would associate the functional coverage
    with the drinkers, not the beer. I could then easily analyze who drank
    what and how many and if they were drunk enough to be admitted to the
    fraternity. Using cumulative metrics, I could see how much beer was
    consumed at the party, reguardless of who drank it.


    Next, to keep the functional coverage model separate from the
    transactor models, functional coverage groups should be encapsulated
    in their own coverage object. Each object contributes its information
    model to the overall coverage model.

    Code:

       class beer_cov_c {

          coverage_group beer_cov {

                  sample brand {
                      state s_sleemans        (sleemans);
                      state s_upper_canada    (upper_canada);
                      state s_blanche_chambly (blanche_chambly);
                      state s_rickards        (rickards);
                      at_least = 10;
                      coverage_goal = 100; // goal for sample
                   }
                   coverage_goal = 100; // goal for group
              }
       }


    Note that I have left out the sampling portion and only coded the
    information model portion of the coverage group. That's because
    sampling should be decoupled from the coverage information model, as
    they may not be directly compatible. For example, the functional
    coverage for a FIFO would be implemented by sampling the value of the
    READ and WRITE pointers after each push and pop operation. However,
    the coverage information model would be the FIFO occupancy, computed
    from the difference between the two values (modulo the FIFO
    size). Furthermore, the computed value would be assigned into one of 5
    states: empty, near-empty, neither, near-full, full. The functional
    coverage groups are coded to ease the interpretation and analysis of
    the report, reguardless of the sampling.

    Next, you must bridge the functional coverage information model with
    the sampling mechanism. You have to decide what data is available to
    be sampled, where, and at what point in time is it valid. The
    functional coverage class should have a sampling interface designed to
    match the available data and thus be easy to use. That interface can
    be implemented using methods (virtual or not), data members and Vera's
    rich coverage group sample event sets.


    For example, assume your drinker is originally modeled as:

    Code:

        class drinker_c {
           task drink(beer_c bottle) {
              ...
           }
        }


    with the following original environment:

    Code:

       class environment {
          brewery_c micro[4];
          drinker_c drinker[4];

          task new() {
             shadow integer i;
             for (i = 0; i < 4; i++) {
           this.micro[i] = new;
                this.drinker[i] = new;
                fork
              repeat (100) {
                      beer_c bottle = this.micro[i].brew();
                      this.drinker[i].drink(bottle);
                   }
                join none
             }
          }
       }


    The data interface for the coverage object can be implemented using a
    method that, when invoked, will cause the supplied arguments to be
    sampled and added to the coverage model.

    Code:

       class beer_cov_c {

          local brand_e brand;
          local event   cover_it;

          task cover(beer_c bottle) {
             this.brand = bottle.brand;
             trigger(this.cover_it);
          }

          coverage_group beer_cov {

                  sample brand {
                sample_event = sync(ALL, this.cover_it) async;
                     ...
                   }
              }
       }


    The DUT-specific coverage object can then be inserted in the original
    environment:

    Code:

                fork
              repeat (100) {
                      beer_c bottle = this.micro[i].brew();
                      this.beer_cov[i].cover(bottle);
                      this.drinker[i].drink(bottle);
                   }
                join none


    Given that functional coverage is going to be used, the transactor
    themselves should be designed to offer suitable interfaces to allow
    user-defined functional coverage sampling at relevant points. Many
    mechanisms can be used.

    The simplest mechanism is to use virtual methods that can be extended
    with pre- or post-execution statements:

    Code:

        class drinker_cov_c extends drinker_c {
           beer_cov_c beer_cov;
           
           virtual task drink(beer_c bottle) {
              this.beer_cov.cover(bottle);
         super.drink(bottle);
           }
        }


    But that simple mechanism only works if there exists a virtual method
    with the proper level of granularity to be overloaded. If the useful
    information to be sampled is generated internally to a thread embedded
    in a while(1) loop, it will not be so nicely visible. Transactors
    should provide mechanisms explicitly designed to give access to
    relevant information, internal or external. For example, a public data
    member and an event signalling its validity could be used:

    Code:

        class drinker_c {
           beer_c bottle;
           event  drinking;

           task drink(beer_c bottle) {
              this.bottle = bottle;
              trigger(this.drinking);
              ...
           }
        }


    The advantage is that any number of functional coverage objects (or
    scoreboards for that matter) can hang off the interface and sample the
    data as required, without modifying or extending the original
    transactor:

    Code:

       class beer_cov_c {

          local drinker_c drinker;

          task new(drinker_c drinker) {
             this.drinker = drinker;
          }

          coverage_group beer_cov {

                  sample brand (drinker.bottle.brand) {
                sample_event = sync(ALL, this.drinker.drinking) async;
                     ...
                   }
              }
       }


    Personally, I prefer to provide callback methods to give a
    well-defined and well-controlled interface at relevant execution
    points in transactors. These callbacks can be extended to have
    user-defined code (such as coverage sampling, scoreboard integration
    or error injection) executed:

    Code:

        class drinker_callbacks {
           virtual drinking(beer_c beer) {}
        }

        class drinker_c {
           drinker_callbacks cb[$];

           task register_callback(drinker_callbacks cb) {
              this.cb.push_back(cb);
           }

           task drink(beer_c bottle) {
              foreach (this.cb, i) {
                 this.cb[i].drinking(bottle);
              }
              ...
           }
        }


    DUT-specific coverage can then be added in the environment:

    Code:

       class drinker_coverage extends drinker_callbacks {
           beer_cov_c beer_cov;
           virtual drinking(beer_c beer) {
              this.beer_cov.cover(beer);
           }
       }

       class environment {
          brewery_c micro[4];
          drinker_c drinker[4];

          task new() {
             shadow integer i;
             for (i = 0; i < 4; i++) {
           this.micro[i] = new;
                this.drinker[i] = new;
                {
                   drinker_coverage dc = new;
                   this.drinker[i].register_callback(dc);
                }
                fork
              repeat (100) {
                      beer_c bottle = this.micro[i].brew();
                      this.drinker[i].drink(bottle);
                   }
                join none
             }
          }
       }


    and test-specific coverage can then be further added in the
    environment as well:

    Code:

       class test_coverage extends drinker_callbacks {
           beer_cov_c beer_cov;
           virtual drinking(beer_c beer) {
              this.beer_cov.cover(beer);
           }
       }

       program testcase {
          environment pub = new;
          {
             test_coverage tc = new;
             this.drinker[i].register_callback(tc);
          }
          ...
       }


    In summary:

    + Keep coverage separate from your data and transactor models
    + Associate coverage with static testbench functions
    + Define the coverage group to facilitate analysis
    + Design the coverage class interface to facilitate sampling
    + Design your transactors to allow for coverage extensions

    - Janick Bergeron, Principal R&D Engineer
    Synopsys Inc.
    Back to top
    View user's profile
    Newsletter
    Original Contribution


    Joined: Dec 08, 2003
    Posts: 1107

    PostPosted: Sun Sep 14, 2003 11:00 pm    Post subject: Implementing Functional Coverage in Vera 6 Reply with quote

    (Originally from Issue 4.15, Item 5.0)

    From: Chris Spear Send e-mail

    One small note - if you make brand to be an enumerated type, you won't
    have to define the states in the sample expression - Vera will do it
    for you.

    class beer_c extends beer_c {

    enum E_BEER {SLEEMANS, UPPER_CANADA, BLANCHE_CHAMBLY, RICKARDS};

    E_BEER brand;
    }

    class beer_cov_c extends beer_c {
    event randomized;

    coverage_group beer_cov {
    sample_event = sync(ANY, randomized) async; // <-- ASYNC sample
    sample brand {
    at_least = 10;
    coverage_goal = 100; // goal for sample
    }
    coverage_goal = 100; // goal for group
    }
    }

    Bottoms Up!

    - Chris Spear, Synopsys
    Back to top
    View user's profile
    Display posts from previous:   
    This forum is locked: you cannot post, reply to, or edit topics.   This topic is locked: you cannot edit posts or make replies.    Verification Guild Forum Index -> Coverage All times are GMT - 5 Hours
    Page 1 of 1

     
    Jump to:  
    You can post new topics in this forum
    You can reply to topics in this forum
    You cannot edit your posts in this forum
    You cannot delete your posts in this forum
    You cannot vote in polls in this forum

    Powered by phpBB © 2001, 2005 phpBB Group
    Verification Guild (c) 2006-2014 Janick Bergeron
    PHP-Nuke Copyright © 2005 by Francisco Burzi. This is free software, and you may redistribute it under the GPL. PHP-Nuke comes with absolutely no warranty, for details, see the license.
    Page Generation: 0.10 Seconds