sequence基础
目录
- sequence的启动与执行
- 仲裁机制
- 在同一sequencer上启动多个sequence
- lock操作与grab操作
- lock
- grab
- sequence的有效性
- 相关宏及其实现
sequence的启动与执行
- 完成sequence的定义后,使用start将其启动:
my_sequence my_seq;
my_seq = my_sequence::type_id::create("my_seq");
my_seq.start(sequencer);
- 除了直接启动之外,还可以使用default_sequence启动,有两种调用方式:
uvm_config_db#(uvm_object_wrapper)::set(this,"env.i_agt.sqr.main_phase","default_sequence",case0_sequence::type_id::get());
另外一种方式是先实例化要启动的sequence,再通过default_sequence启动:
function void my_case0::build_phase(uvm_phase phase);case0_sequence cseq;super.build_phase(phase);cseq = new("cseq");uvm_config_db#(uvm_sequence_base)::set(this,"env.i_agt.sqr.main_phase","default_sequence",cseq);
endfunction
当一个sequence启动后会自动执行其body task,也就是具体定义激励产生的位置。
仲裁机制
在同一sequencer上启动多个sequence
当在同一sequencer上启动多个sequence时,便涉及到了sequence的优先级问题,可以通过uvm_do_pri及uvm_do_pri_with改变sequence所产生的transaction的优先级:
class sequence0 extends uvm_sequence #(my_transaction);
…virtual task body();
…repeat (5) begin`uvm_do_pri(m_trans, 100)`uvm_info("sequence0", "send one transaction", UVM_MEDIUM)end#100;
…endtask
…
endclassclass sequence1 extends uvm_sequence #(my_transaction);
…virtual task body();
…repeat (5) begin`uvm_do_pri_with(m_trans, 200, {m_trans.pload.size < 500;})`uvm_info("sequence1", "send one transaction", UVM_MEDIUM)end
…endtask
…
endclass
uvm_do_pri与uvm_do_pri_with的第二个参数是优先级,这个数值必须是一个大于等于-1的整数。数字越大,优先级越高。
sequencer的仲裁算法以下几种:
- SEQ_ARB_FIFO:它会严格遵循先入先出的顺序,而不会考虑优先级,这也是sequencer的默认仲裁算法。
- SEQ_ARB_WEIGHTED是加权的仲裁。
- SEQ_ARB_RANDOM是完全随机选择。
- SEQ_ARB_STRICT_FIFO是严格按照优先级的。当有多个同一优先级的sequence时,按照先入先出的顺序选择。
- SEQ_ARB_STRICT_RANDOM是严格按照优先级的,当有多个同一优先级的sequence时,随机从最高优先级中选择。
- SEQ_ARB_USER则是用户可以自定义一种新的仲裁算法。
若想使上述两个sequence的优先级起作用,应该设置仲裁算法为SEQ_ARB_STRICT_FIFO或者SEQ_ARB_STRICT_RANDOM:
task my_case0::main_phase(uvm_phase phase);
…env.i_agt.sqr.set_arbitration(SEQ_ARB_STRICT_FIFO);forkseq0.start(env.i_agt.sqr);seq1.start(env.i_agt.sqr);join
endtask
除transaction有优先级外,sequence也有优先级的概念。可以在sequence启动时指定其优先级:
task my_case0::main_phase(uvm_phase phase);
…env.i_agt.sqr.set_arbitration(SEQ_ARB_STRICT_FIFO);forkseq0.start(env.i_agt.sqr, null, 100);seq1.start(env.i_agt.sqr, null, 200);join
endtask
start任务的第一个参数是sequencer,第二个参数是parent sequence,可以设置为null,第三个参数是优先级,如果不指定则此值为-1,它同样不能设置为一个小于-1的数字。
即使不使用uvm_do_pri与uvm_do_pri_with宏中指定transaction的优先级,直接运行上述代码也可以达到目的,所以,对sequence设置优先级的本质即设置其内产生的transaction的优先级。
lock操作与grab操作
lock
sequence向sequencer发送一个请求,这个请求与其他sequence发送transaction的请求一同被放入sequencer的仲裁队列中。当其前面的所有请求被处理完毕后,sequencer就开始响应这个lock请求,此后sequencer会一直连续发送此sequence的transaction,直到unlock操作被调用。
一个使用lock操作的sequence为:
class sequence1 extends uvm_sequence #(my_transaction);
…virtual task body();
…repeat (3) begin`uvm_do_with(m_trans, {m_trans.pload.size < 500;})`uvm_info("sequence1", "send one transaction", UVM_MEDIUM)endlock();`uvm_info("sequence1", "locked the sequencer ", UVM_MEDIUM)repeat (4) begin`uvm_do_with(m_trans, {m_trans.pload.size < 500;})`uvm_info("sequence1", "send one transaction", UVM_MEDIUM)end`uvm_info("sequence1", "unlocked the sequencer ", UVM_MEDIUM)unlock();repeat (3) begin`uvm_do_with(m_trans, {m_trans.pload.size < 500;})`uvm_info("sequence1", "send one transaction", UVM_MEDIUM)end
…endtask
…
endclass
将此sequence1与其他sequence在env.i_agt.sqr上启动,会发现在lock语句前,其它sequence和seuquence1交替产生transaction;在lock语句后,一直发送sequence1的transaction,直到unlock语句被调用后,其他sequence和seuquence1又开始交替产生transaction。
如果两个sequence都试图使用lock任务来获取sequencer的所有权则,则先获得所有权的sequence在执行完毕后才会将所有权交还给另外一个sequence。
grab
与lock操作一样,grab操作也用于暂时拥有sequencer的所有权,只是grab操作比lock操作优先级更高。lock请求是被插入sequencer仲裁队列的最后面,等到它时,它前面的仲裁请求都已经结束了。grab请求则被放入sequencer仲裁队列的最前面,它几乎是一发出就拥有了sequencer的所有权:
class sequence1 extends uvm_sequence #(my_transaction);
…virtual task body();
…repeat (3) begin`uvm_do_with(m_trans, {m_trans.pload.size < 500;})`uvm_info("sequence1", "send one transaction", UVM_MEDIUM)endgrab();`uvm_info("sequence1", "grab the sequencer ", UVM_MEDIUM)repeat (4) begin`uvm_do_with(m_trans, {m_trans.pload.size < 500;})`uvm_info("sequence1", "send one transaction", UVM_MEDIUM)end`uvm_info("sequence1", "ungrab the sequencer ", UVM_MEDIUM)ungrab();repeat (3) begin`uvm_do_with(m_trans, {m_trans.pload.size < 500;})`uvm_info("sequence1", "send one transaction", UVM_MEDIUM)end
…endtask`uvm_object_utils(sequence1)
endclass
- 如果两个sequence同时试图使用grab任务获取sequencer的所有权,则在先获得所有权的sequence执行完毕后才会将所有权交还给另外一个试图所有权的sequence。
- 如果一个sequence在使用grab任务获取sequencer的所有权前,另外一个sequence已经使用lock任务获得了sequencer的所有权,grab任务则会一直等待lock的释放。
sequence的有效性
通过lock任务和grab任务,sequence可以独占sequencer,强行使sequencer发送自己产生的transaction。同样的,UVM也提供措施使sequence可以在一定时间内不参与仲裁,即令此sequence失效。
- sequencer在仲裁时,会查看sequence的is_relevant函数的返回结果。如果为1,说明此sequence有效,否则无效。因此可以通过重载is_relevant函数来使sequence失效:
class sequence0 extends uvm_sequence #(my_transaction);my_transaction m_trans;int num;bit has_delayed;
…virtual function bit is_relevant();if((num >= 3)&&(!has_delayed)) return 0;else return 1;endfunctionvirtual task body();forkrepeat (10) beginnum++;`uvm_do(m_trans)`uvm_info("sequence0", "send one transaction", UVM_MEDIUM)endwhile(1) beginif(!has_delayed) beginif(num >= 3) begin`uvm_info("sequence0", "begin to delay", UVM_MEDIUM)#500000;has_delayed = 1'b1;`uvm_info("sequence0", "end delay", UVM_MEDIUM)break;endelse#1000;endendjoin
…endtask
…
endclass
通过设置is_relevant,可以使sequence主动放弃sequencer的使用权,而grab任务和lock任务则强占sequencer的所有权。
- 除了is_relevant外,sequence中还有一个任务wait_for_relevant也与sequence的有效性相关:
class sequence0 extends uvm_sequence #(my_transaction);
…virtual function bit is_relevant();if((num >= 3)&&(!has_delayed)) return 0;else return 1;endfunctionvirtual task wait_for_relevant();#10000;has_delayed = 1;endtaskvirtual task body();
…repeat (10) beginnum++;`uvm_do(m_trans)`uvm_info("sequence0", "send one transaction", UVM_MEDIUM)end
…endtask
…
endclass
当sequencer发现在其上启动的所有sequence都无效时,此时会调用wait_for_relevant并等待sequence变有效。
is_relevant与wait_for_relevant一般应成对重载,不能只重载其中的一个。
相关宏及其实现
- uvm_do系列宏
uvm_do_on:用于显式地指定使用哪个sequencer发送此transaction。它有两个参数,第一个是transaction的指针,第二个是sequencer的指针。当在sequence中使用uvm_do等宏时,其默认的sequencer就是此sequence启动时为其指定的sequencer,sequence将这个sequencer的指针放在其成员变量m_sequencer中。事实上,uvm_do等价于:
`uvm_do_on(tr, this.m_sequencer)
uvm_do_on_pri:它有三个参数,第一个参数是transaction的指针,第二个是sequencer的指针,第三个是优先级:
`uvm_do_on(tr, this, 100)
uvm_do_on_with:它有三个参数,第一个参数是transaction的指针,第二个是sequencer的指针,第三个是约束:
`uvm_do_on_with(tr, this, {tr.pload.size == 100;})
uvm_do_on_pri_with:它有四个参数,是所有uvm_do宏中参数最多的一个。第一个参数是transaction的指针,第二个是sequencer的指针,第三个是优先级,第四个是约束:
`uvm_do_on_pri_with(tr, this, 100, {tr.pload.size == 100;})
uvm_do系列的其他七个宏其实都是用uvm_do_on_pri_with宏来实现的。如uvm_do宏:
`define uvm_do(SEQ_OR_ITEM) \`uvm_do_on_pri_with(SEQ_OR_ITEM, m_sequencer, -1, {})
- uvm_create与uvm_send
除了使用uvm_do宏产生transaction,还可以使用uvm_create宏与uvm_send宏来产生:
class case0_sequence extends uvm_sequence #(my_transaction);
…virtual task body();int num = 0;int p_sz;
…repeat (10) beginnum++;`uvm_create(m_trans)assert(m_trans.randomize());p_sz = m_trans.pload.size();{m_trans.pload[p_sz - 4],m_trans.pload[p_sz - 3],m_trans.pload[p_sz - 2],m_trans.pload[p_sz - 1]}= num;`uvm_send(m_trans)end
…endtask
…
endclass
uvm_create宏的作用是实例化transaction。当一个transaction被实例化后,可以对其做更多的处理,处理完毕后使用uvm_send宏发送出去。这种使用方式比uvm_do系列宏更加灵活。如在上例中,就将pload的最后4个byte替换为此transaction的序号。
也可以使用uvm_send_pri宏将transaction交给sequencer时设定优先级:
virtual task body();
…m_trans = new("m_trans");assert(m_trans.randomize());p_sz = m_trans.pload.size();{m_trans.pload[p_sz - 4],m_trans.pload[p_sz - 3],m_trans.pload[p_sz - 2],m_trans.pload[p_sz - 1]}= num;`uvm_send_pri(m_trans, 200)
…
endtask
- uvm_rand_send系列宏
uvm_rand_send宏与uvm_send宏类似,唯一的区别是它会对transaction进行随机化。这个宏使用的前提是transaction已经被分配了空间,换言之,即已经实例化了:
m_trans = new("m_trans");
`uvm_rand_send(m_trans)
uvm_rand_send_pri宏:用于指定transaction的优先级。它有两个参数,第一个是transaction的指针,第二个是优先级:
m_trans = new("m_trans");
`uvm_rand_send_pri(m_trans, 100)
uvm_rand_send_with宏:用于指定使用随机化时的约束,它有两个参数,第一个是transaction的指针,第二个是约束:
m_trans = new("m_trans");
`uvm_rand_send_with(m_trans, {m_trans.pload.size == 100;})
uvm_rand_send_pri_with宏:用于指定优先级和约束,它有三个参数,第一个是transaction的指针,第二个是优先级,第三个是约束:
m_trans = new("m_trans");
`uvm_rand_send_pri_with(m_trans, 100, {m_trans.pload.size == 100;})
uvm_rand_send系列宏及uvm_send系列宏的意义主要在于,如果一个transaction占用的内存比较大,那么很可能希望前后两次发送的transaction都使用同一块内存,只是其中的内容可以不同,这样比较节省内存。
- start_item与finish_item
在使用宏来产生transaction时,实际上是隐藏了start_item和finish_item这两个task, uvm_do系列宏其实是将下述动作封装在了一个宏中:
virtual task body();
…tr = new("tr");start_item(tr);assert(tr.randomize() with {tr.pload.size() == 200;});finish_item(tr);
…
endtask
- pre_do、mid_do与post_do
uvm_do宏封装了从transaction实例化到发送的一系列操作,封装的越多,则其灵活性越差。为了增加uvm_do系列宏的功能,UVM提供了三个接口:pre_do、mid_do与post_do。- pre_do是一个task,在start_item中被调用,它是start_item返回前执行的最后一行代码,在它执行完毕后才对transaction进行随机化。
- mid_do是一个function,位于finish_item的最开始。在执行完此函数后,finish_item才进行其他操作。
- post_do也是一个function,也位于finish_item中,它是finish_item返回前执行的最后一行代码。它们的执行顺序大致为:
sequencer.wait_for_grant(prior) (task) \ start_item \
parent_seq.pre_do(1) (task) / \`uvm_do* macros
parent_seq.mid_do(item) (func) \ /
sequencer.send_request(item) (func) \finish_item /
sequencer.wait_for_item_done() (task) /
parent_seq.post_do(item) (func) /
这三个接口function/task的使用示例如下:
class case0_sequence extends uvm_sequence #(my_transaction);my_transaction m_trans;int num;
…virtual task pre_do(bit is_item);#100;`uvm_info("sequence0", "this is pre_do", UVM_MEDIUM)endtaskvirtual function void mid_do(uvm_sequence_item this_item);my_transaction tr;int p_sz;`uvm_info("sequence0", "this is mid_do", UVM_MEDIUM)void'($cast(tr, this_item));p_sz = tr.pload.size();{tr.pload[p_sz - 4],tr.pload[p_sz - 3],tr.pload[p_sz - 2],tr.pload[p_sz - 1]} = num;tr.crc = tr.calc_crc();tr.print();endfunctionvirtual function void post_do(uvm_sequence_item this_item);`uvm_info("sequence0", "this is post_do", UVM_MEDIUM)endfunctionvirtual task body();repeat (10) beginnum++;`uvm_do(m_trans)end
…endtask
…
endclass
pre_do有一个参数,此参数用于表明uvm_do宏是在对一个transaction还是在对一个sequence进行操作。mid_do和post_do的两个参数是正在操作的sequence或者item的指针,但是其类型是uvm_sequence_item类型。通过cast可以转换成目标类型(示例中为my_transaction)。
sequence基础相关推荐
- mysql怎么用sequence_mysql实现sequence功能的代码
mysql实现sequence功能 1.建立sequence记录表 CREATE TABLE `sys_sequence` ( `seq_name` varchar(50) CHARACTER SET ...
- UVM中的sequence
sequence基础 1. 如果将激励放在driver的main_phase中,是可行的,但是如果要对激励作修改,那么扩展性较差,所以我们将激励改为放在sequence中去写. driver就负责驱动 ...
- 2020-12-11 keras通过model.fit_generator训练模型(节省内存)
keras通过model.fit_generator训练模型(节省内存) 前言 前段时间在训练模型的时候,发现当训练集的数量过大,并且输入的图片维度过大时,很容易就超内存了,举个简单例子,如果我们有2 ...
- Swift 里集合类型协议的关系
  Sequence A type that provides sequential, iterated access to its elements. 是最基础的协议,可以通过迭代来获取它的元素 ...
- 自然语言处理--keras实现一维卷积网络对IMDB 电影评论数据集构建情感分类器
为什么在 NLP 分类任务中选择 CNN 呢? 1.CNN神经网络可以像处理图像一样处理文本并"理解"它们 2.主要好处是高效率 3.在许多方面,由于池化层和卷积核大小所造成的限制 ...
- 电商的1000+篇文章总结
电商的1000+篇文章总结 本文收集和总结了有关电商的1000+篇文章,由于篇幅有限只能总结近期的内容,想了解更多内容可以访问:http://www.ai2news.com/, 其分享了有关AI的论文 ...
- POJ题目分类(按初级\中级\高级等分类,有助于大家根据个人情况学习)
本文来自:http://www.cppblog.com/snowshine09/archive/2011/08/02/152272.spx 多版本的POJ分类 流传最广的一种分类: 初期: 一.基本算 ...
- UE4 Sequence添加基础动画效果 (03-主序列的使用)
在上一篇的基础上添加一些摄像头的跟拍效果 效果: 步骤: 1.鼠标右键新建 Animation->关卡序列 命名为主序列 2.双击打开主序列 3.点击 窗口->内容浏览器->内容浏览 ...
- UVM基础-Sequence、Sequencer(二)
目录 sequence和sequencer 将sequence挂载到sequencer 将item挂载到sequencer 宏定义使用实例 sequencer仲裁特性 实例 sequencer的锁定机 ...
最新文章
- android 固定底部导航,Android如何实现底部菜单固定到底部
- Java实现数据序列化工具Avro的例子
- 上元节的灯会(灭)-区间dp
- Java扫描仪toString()方法及示例
- 关于Zookeeper的几个问题
- JavaScript逻辑运算符“”和“||”短路原则的应用
- 漫画让你秒懂5G黑科技....
- 什么是 Stack Overflow,什么情况下会造成 Stack Overflow
- TechWeb祝大家新年快乐!愿你心有光亮 自予光芒!
- combox数据过滤 wpf_- - WPF:筛选ItemCollection的ComboBox也会筛选绑定到同一ComboBoxes的其他ItemsSource_c#_酷徒编程知识库...
- SharePoint And Ajax Technology(2):Ajax Control Toolkit学习
- linux批量分区,Linux磁盘批量分区格式化和挂载脚本
- idea使用jrebel热部署插件
- 最常见的12道计算机基础面试题
- cat /proc/cpuinfo命令详解
- linux网络电视软件sopcast的安装
- 32位qt程序, 利用32位mysql驱动,连接64位mysql8.0
- 前端工程师如何提升能力 提高效率有哪些方法
- Ray-分布式的SGD
- GMSSL :SM2椭圆曲线公钥密码算法-密钥交换协议
热门文章
- 设备管理 设备管理概述
- 第58届日本红白歌会印象记
- mysql bitmap位图索引_Oracle位图索引(Bitmap Index)
- 解决:You have 18 unapplied migration(s). Your project may not work properly until you apply
- 【Linux】Linux根目录下各个目录的含义
- FastJson 配置
- 关于H.264 x264 h264 AVC1之间的那些事
- string substitution
- Java 校验EMAIL格式方法,真为正确
- bug解决-Vue中img图片加载失败解决方案