在运行uvm代码生成器后,我们现在可以开始运行仿真。同样,我们将命令行放入脚本文件中:
Filename runius cd generated_tb/sim compile_ius.sh Filename runquesta cd generated_tb/sim vsim -c -do "do compile_questa.do; run -all" Filename runvcs cd generated_tb/sim compile_vcs.sh Filename runriviera cd generated_tb/sim vsimsa -do compile_riviera.do./sim目录包含运行Cadence,Mentor,Synopsys等仿真器的脚本。 生成的验证环境将运行仅生成单个transaction的sequence,因此在仿真日志中,应该会看到来自clkndata_driver的UVM_INFO消息,其中打印出transaction中数据字段的值,如下所示:
# UVM_INFO ../tb/clkndata/sv/clkndata_driver.sv(47) @ 0: uvm_test_top.m_env.m_clkndata_agent.m_driver [clkndata_driver] req item # vseq.seq.req # data = f4但是,你不会看到从 DUT 打印出此数据值($display(“mydut data = %h”, data);参考前文中DUT的代码),因为我们尚未提供driver的实现,因此尽管driver正在从sequencer接收事务,但它实际上并没有驱动DUT接口。
`ifndef CLKNDATA_DRIVER_SV `define CLKNDATA_DRIVER_SV // You can insert code here by setting driver_inc_before_class in file clkndata.tpl class clkndata_driver extends uvm_driver #(data_tx); `uvm_component_utils(clkndata_driver) virtual clkndata_if vif; clkndata_config m_config; extern function new(string name, uvm_component parent); // You can insert code here by setting driver_inc_inside_class in file clkndata.tpl endclass : clkndata_driver function clkndata_driver::new(string name, uvm_component parent); super.new(name, parent); endfunction : new // You can insert code here by setting driver_inc_after_class in file clkndata.tpl `endif // CLKNDATA_DRIVER_SV实现driver
Filename include/clkndata_do_drive.sv task clkndata_driver::do_drive(); vif.data <= req.data; @(posedge vif.clk); endtask在此任务中必须使用正确的命名约定。clkndata是interface template file中的agent名称,这需要作为任务和文件名的前缀。要让uvm代码生成器包含我们的任务,我们需要添加到interface template file。
Filename clkndata.tpl ... driver_inc = clkndata_do_drive.sv实现后的driver代码:
`ifndef CLKNDATA_DRIVER_SV
`define CLKNDATA_DRIVER_SV
// You can insert code here by setting driver_inc_before_class in file clkndata.tpl
class clkndata_driver extends uvm_driver #(data_tx);
`uvm_component_utils(clkndata_driver)
virtual clkndata_if vif;
clkndata_config m_config;
extern function new(string name, uvm_component parent);
// Methods run_phase and do_drive generated by setting driver_inc in file clkndata.tpl
extern task run_phase(uvm_phase phase);
extern task do_drive();
// You can insert code here by setting driver_inc_inside_class in file clkndata.tpl
endclass : clkndata_driver
function clkndata_driver::new(string name, uvm_component parent);
super.new(name, parent);
endfunction : new
task clkndata_driver::run_phase(uvm_phase phase);
`uvm_info(get_type_name(), "run_phase", UVM_HIGH)
forever
begin
seq_item_port.get_next_item(req);
`uvm_info(get_type_name(), {"req item
",req.sprint}, UVM_HIGH)
do_drive();
seq_item_port.item_done();
end
endtask : run_phase
// Start of inlined include file generated_tb/tb/include/clkndata_do_drive.sv
task clkndata_driver::do_drive();
vif.data <= req.data;
@(posedge vif.clk);
endtask
// End of inlined include file
// You can insert code here by setting driver_inc_after_class in file clkndata.tpl
`endif // CLKNDATA_DRIVER_SV
我们现在可以使用与以前相同的脚本简单地重新运行uvm代码生成器和仿真。 仿真器log说明DUT被正确地驱动了:
# mydata data = f4此消息表明,我们的DUT 现在正在通过 clkndata 接口接收事务。验证环境仍然只向 DUT 发送一个transaction,如何配置发送多个transaction?
Filename common.tpl dut_top = mydut top_default_seq_count = 10修改后再重新生成uvm代码。
`ifndef TOP_SEQ_LIB_SV
`define TOP_SEQ_LIB_SV
class top_default_seq extends uvm_sequence #(uvm_sequence_item);
`uvm_object_utils(top_default_seq)
top_config m_config;
clkndata_agent m_clkndata_agent;
// Number of times to repeat child sequences
int m_seq_count = 10;
extern function new(string name = "");
extern task body();
extern task pre_start();
extern task post_start();
`ifndef UVM_POST_VERSION_1_1
// Functions to support UVM 1.2 objection API in UVM 1.1
extern function uvm_phase get_starting_phase();
extern function void set_starting_phase(uvm_phase phase);
`endif
endclass : top_default_seq
function top_default_seq::new(string name = "");
super.new(name);
endfunction : new
task top_default_seq::body();
`uvm_info(get_type_name(), "Default sequence starting", UVM_HIGH)
repeat (m_seq_count)
begin
fork
if (m_clkndata_agent.m_config.is_active == UVM_ACTIVE)
begin
clkndata_default_seq seq;
seq = clkndata_default_seq::create("seq");
seq.set_item_context(this, m_clkndata_agent.m_sequencer);
if ( !seq.randomize() )
`uvm_error(get_type_name(), "Failed to randomize sequence")
seq.m_config = m_clkndata_agent.m_config;
seq.set_starting_phase( get_starting_phase() );
seq.start(m_clkndata_agent.m_sequencer, this);
end
join
end
`uvm_info(get_type_name(), "Default sequence completed", UVM_HIGH)
endtask : body
task top_default_seq::pre_start();
uvm_phase phase = get_starting_phase();
if (phase != null)
phase.raise_objection(this);
endtask: pre_start
task top_default_seq::post_start();
uvm_phase phase = get_starting_phase();
if (phase != null)
phase.drop_objection(this);
endtask: post_start
`ifndef UVM_POST_VERSION_1_1
function uvm_phase top_default_seq::get_starting_phase();
return starting_phase;
endfunction: get_starting_phase
function void top_default_seq::set_starting_phase(uvm_phase phase);
starting_phase = phase;
endfunction: set_starting_phase
`endif
// You can insert code here by setting top_seq_inc in file common.tpl
`endif // TOP_SEQ_LIB_SV
现在运行仿真脚本,将看到 DUT 接收 10 个transaction而不是1个transaction。 我们可以通过类似的方式实现driver、monitor、fcov收集。
审核编辑:刘清
全部0条评论
快来发表一下你的评论吧 !