creating and using sequence
序列由多个数据项组成,这些数据项可能构成有趣的测试场景。例如,您可以创建对设计内所有寄存器执行读写操作的序列、执行复位的序列,或向被测设备施加激励的另一个序列。最终您会拥有多个执行不同任务的序列,用于验证设计的各个方面。请注意:序列项指代数据包,而序列只是数据项/子序列排列的容器。
现在,你有几个选择:
使用现有序列单独驱动DUT的激励;
组合现有序列创建新序列——例如先执行复位序列,再进行寄存器读写序列,最后执行FSM状态转换序列;
从序列库中随机抽取序列并在DUT上执行;
序列可以对序列项执行操作,或启动新的子序列:
通过序列的start()
方法或uvm_do
宏来执行;
通过start_item/finish_item
或uvm_do
宏来执行序列项;
uvm_do
宏会判断参数是序列还是序列项,并相应调用start()
或start_item()
方法;
在本页面中,我们将尝试通过start_item/finish_item任务来执行一个序列项。要创建用户自定义序列:
从指定数据对象类型的uvm_sequence基类派生;
使用uvm_object_utils
向工厂注册该序列;
设置应执行此序列的默认sequencer;
在body()任务中编写主要激励代码;
Let's look at an example next.
class base_sequence extends uvm_sequence #(my_data);`uvm_object_utils (base_sequence)`uvm_declare_p_sequencer (my_sequencer)my_data data_obj;int unsigned n_times = 1;function new (string name = "base_sequence");super.new (name);endfunctionvirtual task pre_body ();`uvm_info ("BASE_SEQ", $sformatf ("Optional code can be placed here in pre_body()"), UVM_MEDIUM)if (starting_phase != null)starting_phase.raise_objection (this);endtaskvirtual task body ();`uvm_info ("BASE_SEQ", $sformatf ("Starting body of %s", this.get_name()), UVM_MEDIUM)data_obj = my_data::type_id::create ("data_obj");repeat (n_times) beginstart_item (data_obj);assert (data_obj.randomize ());finish_item (data_obj);end`uvm_info (get_type_name (), $sformatf ("Sequence %s is over", this.get_name()), UVM_MEDIUM)endtaskvirtual task post_body ();`uvm_info ("BASE_SEQ", $sformatf ("Optional code can be placed here in post_body()"), UVM_MEDIUM)if (starting_phase != null)starting_phase.drop_objection (this);endtask
endclass
请注意上述示例中的要点:
base_sequence
继承自uvm_sequence
,其数据对象类型为my_data
- 该序列通过宏
uvm_declare_p_sequencer
指定使用my_sequencer
执行(类似sequence 不绑定sequencer ,使用config_db#()::set default sequence 实现 ??? ) - 主要任务
body()
包含向驱动器发送激励的代码 - 可包含(非必须)两个额外任务
pre_body()
和post_body()
,分别在执行body()
前后执行特定操作 - 序列启动时务必置位标志位/提出异议(objection),通知测试平台其仍在运行。该标志位应在序列结束时清除,以便测试平台能优雅结束仿真。若未置位标志,可能导致测试平台其他组件调用仿真退出,致使序列异常终止。该操作也可置于
body()
任务中 - 数据对象将通过随机化后,经由
start_item
和finish_item
发送至驱动器
让我们创建一个简单的序列器来执行上述序列。
class my_sequencer extends uvm_sequencer #(my_data);`uvm_component_utils (my_sequencer)function new (string name, uvm_component parent);super.new (name, parent);endfunctionendclass
记得将默认序列设为基础序列。
class base_test extends uvm_test;...function void start_of_simulation_phase (uvm_phase phase);super.start_of_simulation_phase (phase);uvm_config_db#(uvm_object_wrapper)::set(this,"m_top_env.m_seqr0.main_phase","default_sequence", base_sequence::type_id::get());endfunction...
endclass
Alternatives
Use uvm_sequencer
如果您不想创建一个新的sequencer类,而更倾向于使用uvm_sequencer,您可以通过替换相应的代码行来实现。这样将创建一个类型为uvm_sequencer的sequencer,它可以操作my_data类型的数据,而不是上面示例中用户定义的自定义sequencer。
class base_sequence extends uvm_sequence #(my_data);...`uvm_declare_p_sequencer (uvm_sequencer #(my_data))...
endclassclass my_env extends uvm_env;...uvm_sequencer #(my_data) m_seqr0;...virtual function void build_phase (uvm_phase phase);...m_seqr0 = uvm_sequencer#(my_data)::type_id::create ("m_seqr0", this);endfunction
endclass
Use uvm_sequence_utils
另一种实现相同任务的方法是:在向工厂注册时,对序列使用宏uvm_sequence_utils
,对序列器使用宏uvm_sequencer_utils
。记得调用uvm_update_sequence_lib_and_item
宏来更新数据库。该宏未来可能会被弃用。
class my_sequencer extends uvm_sequencer #(my_data);function new (string name, uvm_component parent);super.new (name, parent);`uvm_update_sequence_lib_and_item (my_data)endfunction`uvm_sequencer_utils (my_sequencer)
endclassclass base_sequence extends uvm_sequence #(my_data);`uvm_sequence_utils (base_sequence, my_sequencer)...
endclass
Simulation Log
----------------------------------------------------------------
CDNS-UVM-1.1d (14.10-s013)
(C) 2007-2013 Mentor Graphics Corporation
(C) 2007-2013 Cadence Design Systems, Inc.
(C) 2006-2013 Synopsys, Inc.
(C) 2011-2013 Cypress Semiconductor Corp.
----------------------------------------------------------------
UVM_INFO @ 0: reporter [RNTST] Running test base_test...
UVM_INFO @ 0: reporter [UVMTOP] UVM testbench topology:
------------------------------------------------------------
Name Type Size Value
------------------------------------------------------------
uvm_test_top base_test - @2631m_top_env my_env - @208m_drv0 my_driver - @202rsp_port uvm_analysis_port - @2830seq_item_port uvm_seq_item_pull_port - @2779m_seqr0 my_sequencer - @2730rsp_export uvm_analysis_export - @2920seq_item_export uvm_seq_item_pull_imp - @3468arbitration_queue array 0 -lock_queue array 0 -num_last_reqs integral 32 'd1num_last_rsps integral 32 'd1
------------------------------------------------------------UVM_INFO ./tb/my_pkg.sv(98) @ 0: uvm_test_top.m_top_env.m_drv0 [my_driver] Applying initial reset
UVM_INFO ./tb/my_pkg.sv(102) @ 390000: uvm_test_top.m_top_env.m_drv0 [my_driver] DUT is now out of reset
UVM_INFO ./tb/my_pkg.sv(109) @ 390000: uvm_test_top.m_top_env.m_drv0 [my_driver] Waiting for data from sequencer
UVM_INFO ./tb/my_pkg.sv(149) @ 390000: uvm_test_top.m_top_env.m_seqr0@@base_sequence [BASE_SEQ] Optional code can be placed here in pre_body()
UVM_INFO ./tb/my_pkg.sv(155) @ 390000: uvm_test_top.m_top_env.m_seqr0@@base_sequence [BASE_SEQ] Starting body of base_sequence
UVM_INFO ./tb/my_pkg.sv(122) @ 410000: uvm_test_top.m_top_env.m_drv0 [DRV] Driving data item across DUT interface
data_obj: (my_data@3581) {data: 'hedaddr: 'h5begin_time: 390000depth: 'd2parent sequence (name): base_sequenceparent sequence (full name): uvm_test_top.m_top_env.m_seqr0.base_sequencesequencer: uvm_test_top.m_top_env.m_seqr0
}
UVM_INFO ./tb/my_pkg.sv(109) @ 410000: uvm_test_top.m_top_env.m_drv0 [my_driver] Waiting for data from sequencer
UVM_INFO ./tb/my_pkg.sv(163) @ 410000: uvm_test_top.m_top_env.m_seqr0@@base_sequence [base_sequence] Sequence base_sequence is over
UVM_INFO ./tb/my_pkg.sv(168) @ 410000: uvm_test_top.m_top_env.m_seqr0@@base_sequence [BASE_SEQ] Optional code can be placed here in post_body()
UVM_INFO ./tb/my_pkg.sv(128) @ 410000: uvm_test_top.m_top_env.m_drv0 [my_driver] Finished DUT simulation--- UVM Report catcher Summary ---
summary:
seuqnece 是弹夹,可以在body内使用uvm_do marco,也可以使用start_item,randomize,finish_item 2 种方式发送数据;
sequence 和sequencer的绑定,使用start (). 或者使用default sequence;
uvm_do_on支持item、sequence和 sequencer的绑定,至少需要raise objection 一次;