在本文中,我们将进一步实现monitor和coverage collector components,以便在仿真期间收集功能覆盖信息。
实现monitor
为了在验证环境中进行检查或覆盖率收集,我们首先需要完成monitor的实现。与前文driver代码的生成实现类似,我们使用template files指示uvm代码生成器包含我们的任务。
Filename include/clkndata_do_mon.sv task clkndata_monitor::do_mon(); forever @(posedge vif.clk) begin m_trans = data_tx::create("m_trans"); m_trans.data = vif.data; analysis_port.write(m_trans); end endtask
和driver一样,任务的命名需要以agent接口为前缀。do_mon任务应monitor DUT 接口,然后组装成一个事务m_trans,最后通过analysis_port发送出去。
Filename clkndata.tpl ... driver_inc = clkndata_do_drive.sv monitor_inc = clkndata_do_mon.sv ...
实现Covergroup
uvm代码生成器将生成一个subscriber component,该组件连接到monitor的analysis_port。默认情况下,此subscriber 将使用covergroup对任何接收到的事务值进行采样。自动生成的代码如下所示:
Filename clkndata_coverage.sv class clkndata_coverage extends uvm_subscriber #(data_tx); `uvm_component_utils(clkndata_coverage) bit m_is_covered; data_tx m_item; covergroup m_cov; option.per_instance = 1; cp_data: coverpoint m_item.data; endgroup extern function new(string name, uvm_component_parent); extern function void write(input data_tx t); endclass function clkndata_coverage::new(string name, uvm_component_parent); super.new(name, parent); m_is_covered = 0; m_cov = new; endfunction function void clkndata_coverage::write(input data_tx t); m_item = t; m_cov.sample(); if (m_cov.get_inst_coverage() >= 100) m_is_covered = 1; endfunction ...
为了完成覆盖模型,可以在include文件中提供一组用户定义的coverpoints,例如:
Filename include/clkndata_cover_inc.sv covergroup m_cov; option.per_instance = 1; cp_data: coverpoint m_item.data { bins zero = {0}; bins one = {1}; bins negative = { [-128:-1] }; bins positive = { [1:127] }; option.at_least = 16; } endgroup
同样,必须使用正确的命名约定。文件名前缀为agent interface,必须将covergroup 命名为 m_cov,并且引用输入事务的变量名称必须为m_item。
Filename clkndata.tpl ... driver_inc = clkndata_do_drive.sv monitor_inc = clkndata_do_mon.sv agent_cover_inc = clkndata_cover_inc.sv ...
生成的subscriber component现在包括刚刚提供的covergroup:
Filename clkndata_coverage.sv class clkndata_coverage extends uvm_subscriber #(data_tx); ... data_tx m_item; `include "clkndata_cover_inc.sv" ... extern function void write(input data_tx t); ... endclass
进一步扩展生成的代码
上述文件 clkndata_cover_inc.sv 仅包含一个covergroup。生成的代码实例化该covergroup,并包含一个用于对covergroup进行sample的write方法。但是,如果你需要subscriber 采取除sample covergroup之外或而不是采样的其他操作怎么办?答案是,不仅可以include covergroup,还可以从一组include文件中提取类的所有内容。如果要自己提供 new 和 write 方法,则还需要禁止自动生成它们。为此,你需要更改 interface template file,如下所示:
Filename clkndata.tpl ... #agent_cover_inc = clkndata_cover_inc.sv agent_cover_inc_inside_class = clkndata_cover_inc_inside.sv agent_cover_inc_after_class = clkndata_cover_inc_after.sv agent_cover_generate_methods_inside_class = no agent_cover_generate_methods_after_class = no ...
生成的subscriber 组件现在如下所示:
class clkndata_coverage extends uvm_subscriber #(data_tx); `uvm_component(clkndata_coverage) `include "clkndata_cover_inc_inside.sv" endclass `include "clkndata_cover_inc_after.sv"
然后,可以提供以下两个include文件:
Filename include/clkndata_cover_inc_inside.sv covergroup m_cov; option.per_instance = 1; cp_data: coverpoint m_item.data { bins zero = {0}; bins one = {1}; bins negative = { [-128:-1] }; bins positive = { [1:127] }; option.at_least = 16; } endgroup extern function new(string name, uvm_component_parent); extern function void write(input data_tx t); Filename include/clkndata_cover_inc_after.sv function clkndata_coverage::new(string name, uvm_component_parent); super.new(name, parent); m_cov = new; endfunction function void clkndata_coverage::write(input data_tx t); m_item = t; m_cov.sample(); endfunction: write
你现在可以灵活地在这两个include文件中提供任何代码。你可以让用户定义的代码插入到生成的代码中,而不是代码生成器写出 'include 指令,如下所示:
Filename clkndata.tpl ... agent_cover_inc_inside_class = clkndata_cover_inc_inside.sv inline agent_cover_inc_after_class = clkndata_cover_inc_after.sv inline ...
Override a Sequence
正如我们在前面的文章中看到的,生成的代码包含一个top-level virtual sequence:
文件名 top_seq_lib.sv
Filename top_seq_lib.sv ... task top_default_seq::body(); super.body(); ... clkndata_default_seq seq; seq = clkndata_default_seq::create("seq"); seq.randomize(); seq.start(m_clkndata_agent.m_sequencer, this); endtask ...
可以通过扩展创建和启动的任何default sequence,例如
Filename my_clkndata_seq.sv class my_clkndata_seq extends clkndata_default_seq; ... task body(); ... for (int i = 0; i < 16; i++) begin req = data_tx::create("req"); start_item(req); if ( !req.randomize() with { data == i; }) ... finish_item(req); end endtask endclass
然后,需要在interface template file中标识该文件,并将用户定义的sequence作为default sequence:
Filename clkndata.tpl ... agent_cover_inc = clkndata_cover_inc.sv agent_seq_inc = myclkndata_seq.sv agent_factory_set = clkndata_default_seq my_clkndata_seq
然后,uvm代码生成器会使用工厂机制覆盖整个default sequence:
Filename top_test.sv function void top_test::build_phase(uvm_phase phase); ... clkndata_default_seq::get_type()); ... endfunction
审核编辑:刘清
全部0条评论
快来发表一下你的评论吧 !