Friday, May 16, 2008

Implementing Linked Methods of rvm_env/vmm_env/avm_env/ovm_env

If you have used RVM (Reference Verification Methodology) in Vera or VMM (Verification Methodology Manual), AVM (Advanced Verification Methodology) or OVM (Open Verification Methodology) in SystemVerilog, then you will be familiar with rvm_env, vmm_env, avm_env, etc. base classes. These classes has set of methods build, cfg_dut, run, etc. which are getting called in predefined order. When you call any single method, it will make sure that previous methods in given order set has already called, and if not, it will be called first to ensure ordering. Do you know how this order can be maintained in *_env (rvm_env, vmm_env, avm_env or ovm_env) classes? In this article, I will try to explain one way of implementing this chain of method calls. I don't know how exactly, it is implemented in *_env but they can be implemented as follows also. Who knows they might be implemented as described below in *_env?.

I will try to explain this flow using vmm_env class. vmm_env class has following methods which are executed in the order metioned as below.



    1.  gen_cfg()
    2.  build()
    3.  reset_dut()
    4.  cfg_dut()
    5.  start()
    6.  wait_for_end()
    7.  stop()
    8.  clean()
    9.  report()
    10. run()

When you call build() and if gen_cfg() is not called before that, gen_cfg() will be called first then build will execute.

Same way, if you call gen_cfg() followed by cfg_dut() followed by report(), then cfg_dut() will make sure to call reset_dut() first "before executing itself", report will make sure to call start(), wait_for_end(), stop(), clean(), in the order given, "before executing itself".

There is one more top level method, called run(). If you don't call any of the previous method and just call run(), it will make sure all the previous methods called in the given order "before executing itself". I am giving emphasis on "before executing itself" because it is key of this chain flow of method calling.

This is just an overview of method chaining. Now, let see how it can be implemented. If you look at the implementation, logic is very easy...


Look at the following code.


class vmm_env();


    local bit gen_cfg_done;
    local bit build_done;
    local bit reset_dut_done;
    local bit cfg_dut_done;
    local bit start_done;
    local bit wait_for_end_done;
    local bit stop_done;
    local bit clean_done;
    local bit report_done;

    function new();
        gen_cfg_done      = 0;
        build_done        = 0;
        reset_dut_done    = 0;
        cfg_dut_done      = 0;
        start_done        = 0;
        wait_for_end_done = 0;
        stop_done         = 0;
        clean_done        = 0;
        report_done       = 0;
    endfunction

    function void gen_cfg();
        gen_cfg_done = 1;
    endfunction

    function void build();
        if(gen_cfg_done == 0)
            gen_cfg();
        build_done = 1;
    endfunction

    task reset_dut();
        if(build_done == 0)
            build();
        reset_dut_done = 1;
    endtask

    task cfg_dut();
        if(reset_dut_done == 0)
            reset_dut();
        cfg_dut_done = 1;
    endtask

    task start();
        if(cfg_dut_done == 0)
            cfg_dut();
        start_done = 1;
    endtask

    task wait_for_end();
        if(start_done == 0)
            start();
        wait_for_end_done = 1;
    endtask

    task stop();
        if(wait_for_end_done == 0)
            wait_for_end();
        stop_done = 1;
    endtask

    task clean();
        if(stop_done == 0)
            stop();
        clean_done = 1;
    endtask

    task report();
        if(clean_done == 0)
            clean();
        clean_done = 1;
    endtask

    task run();
        if(report_done == 0)
            report();
    endtask

endclass

Very easy... Isn't it?
Now see, when you call only run() without calling any other method, following will happen.

run()
{
    if(!report_done)
    {
        report()
        {
            if(!clean_done)
            {
                clean()
                {
                    if(!stop_done)
                    {
                        stop()
                        {
                            if(!wait_for_end_done)
                            {
                                wait_for_end()
                                {
                                    if(!start_done)
                                    {
                                        start()
                                        {
                                            if(!cfg_dut_done)
                                            {
                                                cfg_dut()
                                                {
                                                    if(!reset_dut_done)
                                                    {
                                                        reset_dut()
                                                        {
                                                            if(!build_done)
                                                            {
                                                                if(!gen_cfg_done)
                                                                {
                                                                    gen_cfg();
                                                                }
                                                            }
                                                        }
                                                    }
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}

I guess do_test() of avm_env/ovm_env might have the same logic.

Now you might also came to know that why super.<method>() (super.build(), super.reset_dut(), super.cfg_dut(), etc.) is compulsory at the start of these methods in class extended from *_env. If you don't call super.<method>(), above mentioned internal functionality of base class required for chaining will not execute properly.

I hope this information will be useful to you.

Leave comment if you have any suggestion/question/doubt about his article.

$finish;


1 comment: