UVM初学篇 -(17)UVM sequence激励产生与交互执行机制(一)

为了使激励的产生,发送和驱动分工更加的明确,分为了driver, sequencer和sequnce。而uvm中的sequence机制使得激励的产生和约束变得更加灵活。sequence机制是一种与sequencer,driver交互的过程,概括为:

1,通过sequence发送层次化、随机化的激励。

2,sequencer对sequence进行仲裁。

3,driver接受sequencer传递来的sequence(req)并按照时序激励发送到DUT,而后driver等待从端口返回信号和状态。

4,dirver给sequencer发送反馈信息(rsp)。

sequence的生命周期到此结束,完成一个完整的握手。

如果把sequence_item比作乘客的话,sequence类比为电梯调度中心的调度员,它决定了哪些乘客(sequence_item)进入电梯(driver),sequencer可以比作大楼的调度中心,它控制着哪些事务(transactions)何时被发送到driver。

UVM squence是一个参数化的类,属于uvm_object,不属于uvm树形结构中,它在验证平台中是有生命周期。

图3.14是sequence机制交互流程:

图3.14 sequence机制交互流程图

1,sequence中的流程为:

(1)产生sequence item(create_item)。

(2)sequence_item的随机化。

(3)指定sequencer发送这个sequence(start_item)。

(4)sequence_item送到REQ_FIFO(finish_item),如果有response,得到response(get_response(rsp)) 。

2,sequencer的流程为:

(1)对sequence进行仲裁。

3,driver的流程为:

(1)得到sequence_item(get_next_item(req))。

(2)发送给DUT。

(3)产生response。

这里会涉及到两个概念:sequence的执行和sequence的启动。

执行:sequence的执行是指sequence在sequencer中启动后,执行pre_start、body、post_body等函数,主要涉及到数据的生成和激励的发送。

启动:sequence的启动是指通过手动启动方式和自动启动的方式来激活和使用sequence,从而实现对硬件功能的准确、高效的测试。

一、 sequence中的执行

sequence的执行必须在task body中执行,task body是在task phase中自动调用的。

sequence的发送可以分为uvm_sequence_item类型的发送和uvm_sequence类型的发送。

1, sequence_item的发送

如果sequence发送的是uvm_sequence_item类型,那么发送的方法有以下几种:

(1)start_item 和finish_item

virtual task start_item(uvm_sequence_item item, int set_priority=-1,uvm_sequence_base sequence=null);

start_item()有三个参数,第一个是传入的sequence_item, 第二个是优先级,第三个是指定该sequence_item发送给哪一个sequencer。

这个task的作用可以理解为让数据包和sequencer建立联系。

virtual task finish_item(uvm_sequence_item item, int set_priority=-1);

finish_item()有二个参数,第一个是传入的sequence_item, 第二个是优先级。

这个task的作用可以理解为把数据包sequence_item发送给driver。

在实际的运用中的流程为:

1)实例化item 。

2)start_item 。

3)对item随机化。

4)结束finish_item。

5)如果需要rsp ,等到rsp返回后结束流程。

part1/sequence是对UVM sequence机制的实验, dadd_rand_test中对data_sequence_item进行随机,在dadd_rand_sequence的task body代码为:

cpp 复制代码
File:dadd_sequence.sv

Class:dadd_rand_sequence

`ifdef START_ITEM

    task body();

        if(starting_phase != null)

            starting_phase.raise_objection(this);

        repeat(20)

        begin

            item = new("item");

            start_item(item);

            item.randomize();

            finish_item(item);

        end



        if(starting_phase != null)

            starting_phase.drop_objection(this);

endtask : body

代码3.10 sequence机制中通过start_item和finish_item对sequence item进行发送

执行Makefile脚本:

make send_item_start_item

(2)`uvm_create(item),`uvm_send(item)

uvm还提供了`uvm_create或者`uvm_create_on,用于生成transaction的实例,然后结合`uvm_send宏将transaction发送出去。

`uvm_create为实例化,就是我们常用的new函数,还有`uvm_create_on(item,sqr)宏,这个宏可以指定发送的sequencer。

`uvm_send是把数据包sequence_item发送给driver,这个define实际就是封装了start_item和finish_item。

在实际的运用中的流程为:

1)`uvm_create(item) 。

2)对item随机化。

3)`uvm_send(item)。

4)如果需要rsp ,等到rsp返回后结束流程。

cpp 复制代码
File:dadd_sequence.sv

Class:dadd_rand_sequence

`elsif UVM_CREATE

    task body();

        if(starting_phase != null)

            starting_phase.raise_objection(this);

        repeat(20)

        begin

            `uvm_create(item);

            item.randomize();

            `uvm_send(item);

        end

        if(starting_phase != null)

            starting_phase.drop_objection(this);

endtask : body

代码3.11 sequence机制中通过uvm_create和uvm_send对sequence item进行发送

执行Makefile脚本:

make send_item_uvm_create

(3)`uvm_do系列宏

`uvm_do系列宏是最常用的方法,用于发送sequence_item或者是sequence,

相关的宏为:

`uvm_do(item_or_seq)

只有一个参数,可以是sequence_item或者sequence

`uvm_do_with(item_or_seq, {cons})

有两个参数,一个是传输的item或者seq,第二个参数为item或者seq的约束

`uvm_do_pri(item_or_seq, priority)

两个参数,一个是传输的item或者seq,第二个参数为item或者seq的优先级

`uvm_do_pri_with(item_or_seq, pri, {cons})

三个参数,一个是传输的item或者seq,第二个参数是item/seq的优先级,第三个参数是约束

`uvm_do_on(item_or_seq, sqr)

有两个参数,第二个参数为sqr的指针

`uvm_do_on_with(item_or_seq, sqr, {cons})

有三个参数,第二个为sqr,第三个为约束

`uvm_do_on_pri(item_or_seq, sqr, pri)

三个参数,第三个指定了优先级

`uvm_do_on_pri_with(item_or_seq, sqr, pri, {cons})

四个参数,第三个为优先级,第四个为约束

如果发送的是sequence_item 那么`uvm_do系列宏可以理解为封装了uvm_create,start_item,finish_item 。在实际的运用中的流程为:

1)`uvm_do(item)。

2)如果需要rsp ,等到rsp返回后结束流程。

cpp 复制代码
File:dadd_sequence.sv

Class:dadd_rand_sequence

`else//UVM_DO

    task body();

        if(starting_phase != null)

            starting_phase.raise_objection(this);

        repeat(20)

        begin

            `uvm_do(item)

        end

        if(starting_phase != null)

            starting_phase.drop_objection(this);

endtask : body

代码3.12 sequence机制中通过uvm_do对sequence item进行发送

执行Makefile脚本:

make send_item_uvm_do

2, sequence的发送

sequence中可以嵌套sequence,如果sequence发送的是子sequence,那么发送的方法为:

(1)task start函数

调用start函数启动。

virtual task start (uvm_sequencer_base sequencer, uvm_sequence_base parent_sequence = null,int this_priority = -1,bit call_pre_post = 1);

在实际的运用中的流程为:

1)sequence的实例化。

2)sequence随机化约束。

3)seq.start()。

在dadd的测试平台中dadd_en是随机,如果想让dadd_en约束为1,及连续的发送数据,就可以对dadd_rand_sequence进行约束。

在dadd_rand_sequence中声明一个random的变量data_en_rand,然后通过`uvm_do_on_with(item,sqr,{const})对sequence_item中的data_en进行约束。

代码为:

cpp 复制代码
File:dadd_sequence.sv

Class:dadd_rand_sequence

class dadd_rand_sequence extends uvm_sequence;

    `uvm_object_utils(dadd_rand_sequence)

    `uvm_declare_p_sequencer(dadd_sequencer)

    dadd_item item;



    rand bit data_en_rand;



    function new(string name = "dadd_rand_sequence");

        super.new(name);

    endfunction : new

    `ifdef SEND_SEQ

    task body();

        if(starting_phase != null)

            starting_phase.raise_objection(this);

        repeat(20)

        begin

            `uvm_do_on_with(item,p_sequencer,{

                item.data_en==  data_en_rand;

            })

        end

        if(starting_phase != null)

            starting_phase.drop_objection(this);

    endtask : body

代码3.13 sequence机制dadd_rand_sequence的代码

在dadd_fixen_sequence中实例化了dadd_rand_sequence并对data_en_rand约束为1。

cpp 复制代码
File:dadd_sequence.sv

Class:dadd_fixen_sequence

`ifdef SEND_SEQ

        `ifdef START

        task body();

            if(starting_phase != null)

                starting_phase.raise_objection(this);



            seq = dadd_rand_sequence :: type_id ::create("seq");

            seq.randomize() with {data_en_rand == 1;};



            seq.start(p_sequencer);



            if(starting_phase != null)

                starting_phase.drop_objection(this);

    endtask : body

代码3.14 sequence机制通过start发送sequence的代码

执行Makefile脚本:

make send_seq_start

(2)`uvm_create,`uvm_send

`uvm_create实际就是sequence的实例化,`uvm_send封装了start函数。流程为:

1)`uvm_create(seq) 。

2)sequence随机化约束。

3)`uvm_send(seq)。

在dadd_fixen_sequence中的代码为:

cpp 复制代码
File:dadd_sequence.sv

Class:dadd_fixen_sequence

`elsif UVM_CREATE

        task body();

            if(starting_phase != null)

                starting_phase.raise_objection(this);



            `uvm_create(seq)

            seq.randomize() with {data_en_rand == 1;};

            `uvm_send(seq)



            if(starting_phase != null)

                starting_phase.drop_objection(this);

        endtask : body

代码3.15 sequence机制通过uvm_create和uvm_send发送sequence的代码

执行Makefile脚本:

make send_seq_uvm_create

(3)`uvm_do系列宏

同上`uvm_do宏,如果发送的sequence那么`uvm_do系列宏可以理解为封装了`uvm_create, tast start()。

在实际的运用中的流程为:

1)`uvm_do_with(item,{const})

在dadd_fixen_sequence中的代码为:

cpp 复制代码
File:dadd_sequence.sv

Class:dadd_fixen_sequence

`else//UVM_DO

        task body();

            if(starting_phase != null)

                starting_phase.raise_objection(this);



            `uvm_do_with(seq,{data_en_rand == 1;})



            if(starting_phase != null)

                starting_phase.drop_objection(this);

        endtask : body

代码3.16 sequence机制通过uvm_do发送sequence的代码

执行Makefile脚本:

make send_seq_uvm_do

二、 sequence的启动

sequence的启动有两种方式一种是手动启动,另一种是自动启动。

1,手动启动start:通过例化sequence后挂载到sequencer上。

my_seq seq = ny_seq:type_id::create("seq");

seq.start(sequencer);

代码为:

cpp 复制代码
File:dadd_test.sv

Class:dadd_rand_test

task          dadd_rand_test :: main_phase(uvm_phase phase);

    super.main_phase(phase);

    `ifndef DEFAULT_SEQUENCE

    seq.starting_phase = phase;

    seq.start(env.iagt.sqr);

    `endif//SET_DEFAULT_SEQUENCE

endtask: main_phase

代码3.17 sequence机制通过start手动启动sequence的代码

执行Makefile脚本:

make rand

2,自动启动:通过default_sequence启动,通过调用config_db。

uvm_config_db#(uvm_object_wrapper)::set(this,"env.i_agt.sqr.main_phase","default_sequence",case_sequnce::type_id::get())

用到的是config_db的方法,在set中第一个参数是启动这个sequence的phase在UVM树形结构的路径,第二个为标识符,uvm规定为"default_sequence",第三个为这个sequence的实例化句柄。

cpp 复制代码
File:dadd_test.sv

Class:dadd_rand_test

function void dadd_rand_test :: build_phase(uvm_phase phase);

    seq = dadd_rand_sequence :: type_id :: create("seq");

    env = dadd_environment :: type_id :: create("env",this);

    `ifdef DEFAULT_SEQUENCE

    uvm_config_db #(uvm_object_wrapper) :: set(this,"env.iagt.sqr.main_phase","default_sequence",dadd_rand_sequence::type_id::get());

    `endif//SET_DEFAULT_SEQUENCE

endfunction : build_phase

代码3.18 sequence机制通过自动启动sequence的代码

执行Makefile脚本:

make default_seq_rand

本书(《UVM实验教程-从平台、脚本到方法学全代码解析-王建利》)及其实验代码已上传至GitHub 访问网址为: https://github.com/brentwang-lab/uvm_tb_gen

相关推荐
开发者每周简报2 小时前
微软的AI转型故事
人工智能·microsoft
唐 城2 小时前
微软致力于将非 OpenAI 模型添加到 365 Copilot 产品中
microsoft·copilot
阿7_QuQ2 小时前
微软远程桌面APP怎么用
microsoft
仰望大佬0073 小时前
Avalonia实例实战五:Carousel自动轮播图
数据库·microsoft·c#
吉大一菜鸡11 小时前
FPGA学习(基于小梅哥Xilinx FPGA)学习笔记
笔记·学习·fpga开发
9527华安16 小时前
FPGA实现MIPI转FPD-Link车载同轴视频传输方案,基于IMX327+FPD953架构,提供工程源码和技术支持
fpga开发·架构·mipi·imx327·fpd-link·fpd953
264玫瑰资源库16 小时前
从零开始C++棋牌游戏开发之第四篇:牌桌界面与交互实现
开发语言·c++·交互
温轻舟17 小时前
前端开发 之 12个鼠标交互特效上【附完整源码】
开发语言·前端·javascript·css·html·交互·温轻舟
热爱学习地派大星17 小时前
FPGA远程升级 -- FLASH控制
fpga开发
~央千澈~1 天前
优雅草央千澈-关于蓝湖如何快速的标注交互原型是如何使用的-如何使用蓝湖设计交互原型和整个软件项目的流程逻辑-实践项目详细说明
ui·交互·蓝湖