0
点赞
收藏
分享

微信扫一扫

UVM中sequence机制

ivy吖 2022-03-25 阅读 61

目录

1.概述

2.sequence

2.1sequence的启动与执行

2.2sequence相关宏

2.3vitual sequence

2.4sequence library

3.sequencer

3.1sequencer的仲裁机制

3.2锁定机制

4.drive

1.概述

为什么要有sequence机制,要将数据输入到平台中怎么输入sequence,sequence,sequencer,driver之间的通信过程又是如何?

首先,无论是sequence还是driver,它们的通话对象都是sequencer。当多个sequence试图挂载到一个sequencer上时,涉及sequencer的仲裁功能,之后会详谈,先略过。重点分析sequencer作为sequence和driver之间的握手桥梁,是如何扮演这个角色的。如图所示

对于sequence而言,无论是flat sequence还是hierarchical sequence,进一步切分的话,流向sequencer的都是sequence item,所以就每个item的成长周期来看,它起始于creat_item(),继而通过start_item()尝试从sequencer获取可以通过的权限。

对于sequencer的仲裁机制和使用方法先略过,而driver一侧一直处于"吃不饱"状态,如果它没有item可以使用,则使用get_next_item()来尝试从sequencer一侧来获取item。

sequencer将通过权限交给某一个sequence前,目标sequence中的item应完成随机化,继而在获取sequencer通过权限之后执行finish_item()。

接下来sequence中的item将通过sequencer到达driver一侧

driver得到新的item后,会提取有效的数据信息,将其驱动到与DUT连接的接口上

完成驱动后,driver应该通过item_done()来告知sequence已完成了数据传送,sequence在获取消息之后,则表示driver与sequence双方完成了这一次的item握手传输。

2.sequence

2.1sequence的启动与执行

举例:一个常见的sequence应包含body()任务,当一个sequence启动后会自动调用body任务

class sequence1 extends uvm_sequence #(my_transaction);
...
virutal task pre_body();
...
endtask

virtual task body();
...
//发送数据
endtask

virtual task post_body();
...
endtask
`uvm_object_utils(sequence1)
endclass

有两种方式可以启动sequence,直接启动(利用start任务),和间接启动(利用default_sequence启动)

sequence1 my_seq;
my_seq=sequence1::type_id::creat("my_seq");
my_seq.start(sequencer);//直接启动
uvm_config_db#(uvm_object_wrapper)::set(this,"env.i_agt.sqr.main_phase",/
"defult_sequence",sequence1::type_id::get());//间接启动

2.2sequence相关宏

1)uvm_do系列宏主要有八个,其他7个宏都是用uvm_do_on_pri_with宏来实现的,举个例子:

`uvm_do_on_pri_with(SEQ_OR_ITEM,m_sequencer,-1,{})第一个参数是transaction的指针,第二个参数是sequencer的指针,第三个参数是优先级,第四个是约束,其余uvm_do系列宏的参数即在这个范围之中。

2)除了用uvm_do宏产生transaction,还可以用uvm_create宏和uvm_send宏来产生,uvm_create宏的作用是实例化transaction,当一个transaction被实例化之后可以对其做更多的处理,处理完毕之后使用uvm_send宏发送出去。举个例子:

class sequence1 extends uvm_sequence #(my_transaction)
..
    virtual task body();
        repeat(10)
            begin
            `uvm_create(m_trans)
            assert(m_trans.randomize());
            `uvm_send(m_trans)
            end
    endtask
...
endclass

除此之外,还有uvm_send_pri宏,它的作用是将transaction交给sequencer时设定优先级,同理还有uvm_rand_send宏,它还有着对transaction随机化的功能,这里不一一赘述。

2.3vitual sequence

为解决sequence之间的同步问题,最好的方法就是采用virtual sequence,virtual sequence不发送任何transaction,只是控制其他的sequence,起统一调度的作用。而类似地,virtual sequencer桥接着所有底层sequencer的句柄,其本身也不需要传递item,不需要和driver连接。

举个例子:

先定义三个扁平型sequence

class drv0_seq extends uvm_sequence #(my_transaction);
...
virtual task body();
    repeat(10) begin
        `uvm_do(m_trans)
        end
    endtask
endclass

class drv1_seq extends uvm_sequence #(my_transaction);
...
virtual task body();
    repeat(10) begin
        `uvm_do(m_trans)
        end
    endtask
endclass

class read_file_seq extends uvm_sequence #(my_transaction);
    my_transaction m_trans;
    string file_name;
...
endclass

再定义virtual sequence对他们进行调度

class case0_vseq extends uvm_sequence;
...
    virtual task body();
        my_transaction tr;
        read_file_seq seq0;
        drv1_seq seq1;
        
        `uvm_do_with(tr,p_sequencer.p_sqr0,{})
        seq0=new("seq0");
        seq0.file_name="data.text";
        seq1=new("seq1");
        fork
            seq0.start(p_sequencer.p_sqr0);
            seq1.start(p_sequencer.p_sqr1);
        join
..
    endtask
endclass

这就解决了sequence的同步问题

2.4sequence library

所谓sequence library就是一系列sequence集合,sequence library派生自uvm_sequence,从本质上说它还是一个sequence。它根据特定的算法随机选择注册在其中的一些sequence,并在body中执行这些sequence。

1)定义一个sequence library

class simple_seq_library extends uvm_sequence_library #(my_transaction);
    function new(string name="simple_sequence_library");
        super.new(name);
        init_sequence_library();
    endfunction

    `uvm_object_utils(simple_sequene_library)
    `uvm_sequence_library_utils(simple_seq_library);
endclass

值得注意的是,从uvm_sequence派生的时候要指明sequence library产生的transaction类型;其次在new()函数之中要调用init_sequence_library();最后要调用uvm_sequence_library_utils注册。

 2)将sequence加入sequence library中

class seq0 extends uvm_sequence #(my_transaction);
...
    `uvm_object_utils(seq0)
    `uvm_add_to_seq_lib(seq0,simple_seq_library)
    virtual task body();
        ...
    endtask
endclass

 uvm_add_to_seq_lib有两个参数,第一个是sequence名字,第二个是要加入的sequence library的名字。一个sequence可以加入多个不同的sequence library之中,同样地,多个sequence也可以加入同一个sequence library之中。

3)将sequence library作为sequencer的default sequence,这样UVM会随机从加入simple_seq_library的sequence中随机选择并启动。

function void my_case0::build_phase(uvm_phase phase);
    super.build_phase(phase);
    uvm_config_db#(uvm_object_wrapper)::set(this,
                                            "env.i_agt.sqr.main_phase",
                                            "default_sequence",
                                            simple_seq_library::type_id::get());
endfunction

当然我们也可以控制sequence library的选择算法,它由selection_mode决定:UVM_SEQ_LIB_RAND就是完全随机,UVM_SEQ_LIB_RANDC就是周期性随机;UVM_SEQ_LIB_ITEM是sequence library不执行其sequence队列中的sequence,而是自己产生transaction;UVM_SEQ_LIB_USER是用户自定义算法。举个例子:

function void my_case0::build_phase(uvm_phase phase);
...
    uvm_config_db#(uvm_sequence_lib_mode)::set(this,
                                              "env.i_agt.sqr.main_phase",
                                              "default_sequence.selection_mode",
                                              UVM_SEQ_LIB_RANDC);
endfunction

 我们还可以控制sequence library的执行次数,sequence library会在min_random_count和max_random_count之间随意选择一个数来作为执行次数,举个例子:

function void my_case0::build_phase(uvm_phase phase);
...
    uvm_config_db#(int unsigned)::set(this,
                                      "env.i_agt.sqr.main_phase",
                                      "default_sequence.min_random_count",
                                       5);
    uvm_config_db#(int unsigned)::set(this,
                                      "env.i_agt.sqr.main_phase",
                                      "default_sequence.max_random_count",
                                       20);
endfunction

 上述的设置最多产生20个,最少产生5个transaction。

3.sequencer

3.1sequencer的仲裁机制

此前在上文中介绍了sequence的优先级概念。可以通过uvm_do_pri以及uvm_do_pri_with改变transaction的优先级,优先级越高越先执行。sequencer的仲裁机制有以下几种,我们可以通过uvm_sequencer::set_arbitration()来设置仲裁模式:

1)UVM_SEQ_ARB_FIFO:默认模式。按照FIFO先入先出方式依次授权,和优先级没有关系。

2)UVM_SEQ_ARB_WEIGHTED:按照它们的优先级随机授权

3)UVM_SEQ_ARB_RANDOM:无视抵达顺序和优先级,随机授权

4)UVM_SEQ_ARB_STRICT_FIFO:按照它们优先级和抵达顺序依次授权

5)UVM_SEQ_ARB_STRICT_RANDOM:按照它们最高优先级随机授权

6)UVM_SEQ_ARB_USER:用户自定义

3.2锁定机制

uvm_sequencer提供了两种锁定机制,分别通过lock()和grab()方法实现:

1)lock()和unlock()这对方法可以为sequence提供排外的访问权限,但前提条件是,该sequence首先要按照sequencer的仲裁机制获得权限。而一旦sequence获得权限,则无需担心被收回,只有该sequence主动unlock他的sequencer才可以释放这一锁定权限。

2)grab()和ungrab()也可以为sequence提供排外的访问权限,而且它只需要在sequencer下一次授权周期就可以无条件获取授权。与lock方法相比,grab方法无视同一时刻发起的传送请求的其他sequence。

3)需要注意的是,"解铃还须系铃人",如果sequence使用了lock或者grab方法,必须在sequence结束前调用unlock或者ungrab方法来释放权限,否则sequencer会进入死锁状态。

4.driver

task my_driver::main_phase(uvm_phase phase);
    while(1) begin
        seq_item_port.get_next_item(req);
        drive_one_pkt(req);
        rsp=new("rsp");
        rsp.set_id_info(req);
        seq_item_port.put_response(rsp);
        seq_item_port.item_done();
    end
endtask

sequence机制提供反馈的支持,允许driver将一个response返回给sequence。

举报

相关推荐

0 条评论