45.sequence的启动方式
my_sequence my_seq; my_seq = my_sequence::type_id::create("my_seq"); my_seq.start(sequencer);
第一个参数是sequencer;
第二个参数是parent sequence,可以设置为null;
第三个参数是优先级,
uvm_config_db#(uvm_object_wrapper)::set(this, "env.i_agt.sqr.main_phase", "default_sequence", case0_sequence::type_id::get());
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
两者的区别在于
46.
除了body还会自动调用sequence的与
47.sequence的仲裁机制
SEQ_ARB_WEIGHTED 加权仲裁SEQ_ARB_RANDOM 完全随机选择SEQ_ARB_USER 用户自定义
48.sequence的有效性
sqr仲裁时会检查seq的is_relevant返回结果;
49.uvm_do系列宏
`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)
tr = new("tr"); start_item(tr); assert(tr.randomize() with {tr.pload.size == 200;}); finish_item(tr);
如果要指定优先级,则start和finish都要加入;
start_item(tr, 100); finish_item(tr, 100);
50.uvm_do的灵活性
为了增加uvm_do系列宏的功能, UVM提供了三个接口:与
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) /
pre_do start_item最后一行代码
mid_do finish_item最开始
post_do finish_item最后一行代码
51. m_sequencer和p_sequencer
是每个sequence中都有的默认成员变量,它的类型是,它是指向当前sequence的sequencer句柄; 需要使用声明,类型是(my_sequencer是自定义的类,继承于uvm_sequencer);
直接使用m_sequencer会报错,因为m_sequencer是uvm_sequencer_base类型,必须转换为my_sequencer类型才行。这时候引入了p_sequencer。 通过宏声明my_sequencer类型的名为p_sequencer句柄,将m_sequencer类型转为p_sequencer,可以直接调用p_sequencer实现seq访问component类
52.virtual sequence
实现sequence之间同步的最好方式就是使用virtual sequence,为了使用virtual sequence,一般需要一个virtual sequencer。
53.sequence library
一.从 uvm_sequence 派生时要指明此 sequence library 所产生的 transaction类型;二.在其 new 函数中要调用 init_sequence_library ,否则内部的候选 sequence 队列就是空的;三.要调用 uvm_sequence_library_utils注册。
54.寄存器模型
指的是通过模拟cpu在上发出读指令,进行读写操作。在这个过程中,仿真时间($time函数得到的时间)是一直往前走的
不通过总线进行读写操作,直接通过来改变寄存器的值
广义上说,所有而对DUT内部的寄存器或者存储器进行存取的操作都是后门访问操作
后门访问操作能够更好地完成前门访问操作所做的事情(不耗时)
后门访问操作能够完成前门访问操作不能完成的事情(例如更改某些只读寄存器的值)
但是后门访问操作无法在波形文件中找到操作痕迹,
56.前门访问
无论是读或写,寄存器模型都会,此变量中存储着操作类型(读还是写)和操作的地址,如果是写操作,还会有要写入的数据。此变量中的信息要由bus_driver实现最终的前门访问读写操作。
寄存器模型的前门访问操作最终都将由完成,因此在中,
adapter中将sequence产生的变量与DUT能接收的类型相互转换
同时支持前门访问和后门访问方式。
在操作时会模仿DUT的行为。
只支持后门访问
58.寄存器模型操作流程
由于uvm_reg类是object类型,不会自动执行,需要手动调用;
除此之外,还要调用field的对各个域进行详细配置;
2.
reg_block中的build函数,在其中要调用函数完成的实例化;
除此之外,还要调用对寄存器完成配置(访问路径、指定block等)
最后,还要通过把每个寄存器加入到中。
一般在中创建顶层,及和
寄存器模型的前门访问操作最终都将由完成,因此在中,
59.镜像值和期望值
镜像值是表示当前硬件的已知状态值。
往往由模型预测给出,即在前门访问时通过观察总线或者在后门访问时通过自动预测等方式来给出镜像值
期望值是先利用寄存器模型修改软件对象值,而后利用该值更新硬件值;
60. 显示预测和自动预测
没有在环境中集成,而是利用寄存器的操作来,并在的话,这种方式称之为自动预测;
自动预测简单有效,但是如果一些seq跳过寄存器级别的R/W对寄存器进行操作,或者通过其他总线来访问寄存器,则都无法得到正确的值