【总结】
- 该部分完成了寄存器模型的集成,在regacc的的sequence中完成对寄存器的读测试;
- 完成对apb_watchdog的集成测试,在integration_virt_seq中对进入和退出集成测试模式以后的int值及res值进行比较核对。
【思考】 对寄存器模型的集成倾向于顶层传递传递的方式,从Test层向下传递句柄,这样有利于整个环境的闭合性,后续在对寄存器进行不同配置的时候只要进行其他例化即可。
4.1 集成RGM
将使用Python生成的apb_watchdog_reg寄存器模型集成到apb_watchdog_reg中,对于python脚本自动生成寄存器模型不在此处赘述。
`ifndef APB_WATCHDOG_REG_SVH
`define APB_WATCHDOG_REG_SVH
`include "apb_watchdog_reg.sv"
`endif //APB_WATCHDOG_REG_SVH
4.1.1 添加adapter
一般来说,一个VIP中会自带一个adapter,如果没有的话可以在自己的环境中添加一个
touch apb_watchdog_adapter.sv
:::info
- 将adapter导入到apb_pkg中
:::
``verilog
ifndef APB_WATCHDOG_PKG_SV `define APB_WATCHDOG_PKG_SV
package apb_watchdog_pkg;
import uvm_pkg::; `include “uvm_macros.svh” import apb_pkg::;
include "apb_watchdog_config.svh"
include “apb_watchdog_reg.svh”
include "apb_watchdog_cov.svh"
include “apb_watchdog_adapter”
include "apb_watchdog_virtual_sequencer.sv"
include “apb_watchdog_env.sv”
include "apb_watchdog_seq_lib.svh"
include “apb_watchdog_tests.svh”
endpackage
`endif //apb_watchdog_pkg
:::info
2. **_编辑apb_watchdog_adapter_**
这个part可以复用UVM_advance2.3中的adapter
:::
```verilog
`ifndef APB_WATCHDOG_ADAPTER_SV
`define APB_WATCHDOG_ADAPTER_SV
class apb_watchdog_adapter extends uvm_reg_adapter;
`uvm_object_utils(apb_watchdog_adapter)
function new(string name = "apb_watchdog_adapter");
super.new(name);
provides_responses = 1;
endfunction
function uvm_sequence_item reg2bus(const ref uvm_reg_bus_op rw);
apb_transfer t = apb_transfer::type_id::create("t");
t.trans_kind = (rw.kind == UVM_WRITE) ? WRITE : READ;
t.addr = rw.addr;
t.data = rw.data;
t.idle_cycles = 1;
return t;
endfunction
function void bus2reg(uvm_sequence_item bus_item, ref uvm_reg_bus_op rw);
apb_transfer t;
if (!$cast(t, bus_item)) begin
`uvm_fatal("CASTFAIL","Provided bus_item is not of the correct type")
return;
end
rw.kind = (t.trans_kind == WRITE) ? UVM_WRITE : UVM_READ;
rw.addr = t.addr;
rw.data = t.data;
rw.status = t.trans_status == OK ? UVM_IS_OK : UVM_NOT_OK;
endfunction
endclass
`endif //APB_WATCHDOG_ADAPTER_SV
:::info
- 在env中声明
(1)在env中声明寄存器模型和adapter;
(2)以config的模式get寄存器模型,同时例化adapter;
:::
class apb_watchdog_env extends uvm_env;
apb_master_agent apb_mst;
apb_watchdog_config cfg;
apb_watchdog_virtual_sequencer virt_sqr;
apb_watchdog_rgm rgm;
apb_watchdog_adapter adapter;
uvm_reg_predictor predictor;
...
function void build_phase(uvm_phase phase);
super.build_phase(phase);
// Get configuration from test layer
if(!uvm_config_db#(apb_watchdog_config)::get(this,"","cfg", cfg)) begin
`uvm_fatal("GETCFG","cannot get config object from config DB")
end
uvm_config_db#(apb_watchdog_config)::set(this, "virt_sqr", "cfg", cfg);
uvm_config_db#(apb_config)::set(this, "apb_mst", "cfg", cfg.apb_cfg);
apb_mst = apb_master_agent::type_id::create("apb_mst", this);
virt_sqr = apb_watchdog_virtual_sequencer::type_id::create("virt_sqr", this);
if(!uvm_config_db#(apb_watchdog_rgm)::get(this,"","rgm", rgm)) begin
rgm = apb_watchdog_rgm::type_id::create("rgm", this);
rgm.build();
end
adapter = apb_watchdog_adapter::type_id::create("adapter", this);
predictor = uvm_reg_predictor#(apb_transfer)::type_id::create("predictor", this);
endfunction
...
endclass
4.1.2 传递rgm
(1)在apb_watchdog_config中添加声明rgm;
class apb_watchdog_config extends uvm_object;
...
apb_watchdog_rgm rgm;
...
endclass
(2)在test一层中将声明寄存器模型,将寄存器模型与config中的寄存器模型连接,之后将寄存器模型向下传递;
`ifndef APB_WATCHDOG_BASE_TEST_SV
`define APB_WATCHDOG_BASE_TEST_SV
virtual class apb_watchdog_base_test extends uvm_test;
apb_watchdog_config cfg;
apb_watchdog_env env;
apb_watchdog_rgm rgm;
function new(string name = "apb_watchdog_base_test", uvm_component parent);
super.new(name, parent);
endfunction
function void build_phase(uvm_phase phase);
super.build_phase(phase);
rgm = apb_watchdog_rgm::type_id::create("rgm");
rgm.build();
uvm_config_db#(apb_watchdog_rgm)::set(this, "env", "rgm", rgm);
cfg = apb_watchdog_config::type_id::create("cfg");
if(!uvm_config_db#(virtual apb_watchdog_if)::get(this,"","vif", cfg.vif)) begin
`uvm_fatal("GETCFG","cannot get virtual interface from config DB")
end
uvm_config_db#(apb_watchdog_config)::set(this, "env", "cfg", cfg);
env = apb_watchdog_env::type_id::create("env", this);
endfunction
function void connect_phase(uvm_phase phase);
cfg.rgm = rgm;
endfunction
...
endclass
`endif //APB_WATCHDOG_BASE_TEST
【总结】寄存器模型的传递逻辑是:
- 先在顶层创建rgm;然后将创建的rgm连接到config中声明的句柄上;
- 在创建了rgm以后,一定要注意rgm.build(),如果不build那么寄存器模型中的所有寄存器块和map都不会创建。
- 底层通过config来get寄存器模型,如果get不到就会自己创建一个。
4.1.3 集成rgm
class apb_watchdog_env extends uvm_env;
...
function void connect_phase(uvm_phase phase);
super.connect_phase(phase);
virt_sqr.apb_mst_sqr = apb_mst.sequencer;
rgm.map.set_sequencer(apb_mst.sequencer, adapter);
apb_mst.monitor.item_collected_port.connect(predictor.bus_in);
predictor.map = rgm.map;
predictor.adapter = adapter;
endfunction
...
endclass
4.1.4 给定测试序列
(1)编辑apb_watchdog_regacc_seq.sv
之前是通过寄存器总线(apb_transfer)对寄存器中的值进行访问,现在采用RGM对寄存器中的值进行访问;
(2)采用RGM进行访问,那么RGM如何导入到seq中呢?
- 在apb_watchodg_base_virt_seq(父类)中可以拿到config中的vif和RGM;
父类中有了rgm以后,子类apb_watchdog_regacc_seq就可以对寄存器中的值进行访问:
- 声明寄存器中的读写值和状态(父类中声明);
- 通过寄存器模型中寄存器的地址来访问值。
``verilog
ifndef APB_WATCHDOG_BASE_VIRT_SEQ_SV `define APB_WATCHDOG_BASE_VIRT_SEQ_SV
class apb_watchdog_base_virt_seq extends uvm_sequence;
apb_master_single_write_sequence apb_wr_seq; apb_master_single_read_sequence apb_rd_seq; apb_master_write_read_sequence apb_wr_rd_seq; apb_watchdog_config cfg;
uvm_object_utils(apb_watchdog_base_virt_seq)
uvm_declare_p_sequencer(apb_watchdog_virtual_sequencer)virtual apb_watchdog_if vif; apb_watchdog_rgm rgm;
bit [31:0] rd_val, wr_val; uvm_status_e status;
function new(string name = “apb_watchdog_base_virt_seq”);
super.new(name);
endfunction
virtual task body(); `uvm_info(“body”,”Entered…”,UVM_LOW)
//Get cfg from p_sequencer
cfg = p_sequencer.cfg;
vif = cfg.vif;
rgm = cfg.rgm;
`uvm_info(“body”,”Exiting…”,UVM_LOW) endtask
virtual function void compare_data(logic[31:0] val1, logic[31:0] val2);
cfg.seq_check_count++;
if(val1 === val2)
`uvm_info("CMPSUC", $sformatf("val1 'h%0x === val2 'h%0x", val1, val2), UVM_LOW)
else begin
cfg.seq_check_error++;
`uvm_error("CMPSUC", $sformatf("val1 'h%0x !== val2 'h%0x", val1, val2))
end endfunction
endclass
`endif //APB_WATCHDOG_BASE_VIRT_SEQ
```verilog
`ifndef APB_WATCHDOG_regacc_VIRT_SEQ_SV
`define APB_WATCHDOG_regacc_VIRT_SEQ_SV
class apb_watchdog_regacc_virt_seq extends apb_watchdog_base_virt_seq;
`uvm_object_utils(apb_watchdog_regacc_virt_seq)
function new(string name = "apb_watchdog_regacc_virt_seq");
super.new(name);
endfunction
virtual task body();
super.body();
`uvm_info("body","Entered...",UVM_LOW)
// Get value from rgm
//`uvm_do_on_with(apb_rd_seq, p_sequencer.apb_mst_sqr, {addr == 'hFE0;})
rgm.WDOGPERIPHID0.read(status, rd_val);
compare_data(rd_val, 'h24);
//`uvm_do_on_with(apb_rd_seq, p_sequencer.apb_mst_sqr, {addr == 'hFE4;})
//`uvm_do_on_with(apb_rd_seq, p_sequencer.apb_mst_sqr, {addr == 'hFE0;})
rgm.WDOGPERIPHID1.read(status, rd_val);
compare_data(rd_val.data, 'hB8);
//`uvm_do_on_with(apb_rd_seq, p_sequencer.apb_mst_sqr, {addr == 'hFE8;})
//`uvm_do_on_with(apb_rd_seq, p_sequencer.apb_mst_sqr, {addr == 'hFE0;})
rgm.WDOGPERIPHID2.read(status, rd_val);
compare_data(rd_val.data, 'h1B);
//`uvm_do_on_with(apb_rd_seq, p_sequencer.apb_mst_sqr, {addr == 'hFEc;})
//`uvm_do_on_with(apb_rd_seq, p_sequencer.apb_mst_sqr, {addr == 'hFE0;})
rgm.WDOGPERIPHID3.read(status, rd_val);
compare_data(rd_val.data, 'hB0);
`uvm_info("body","Exiting...",UVM_LOW)
endtask
endclass
`endif //APB_WATCHDOG_regacc_VIRT_SEQ_SV
(3)补充apb_watchdog_regacc_test.sv中的内容
`ifndef APB_WATCHDOG_REGACC_TEST_SV
`define APB_WATCHDOG_REGACC_TEST_SV
class apb_watchdog_regacc_test extends apb_watchdog_base_test;
`uvm_component_utils(apb_watchdog_regacc_test)
function new(string name = "apb_watchdog_regacc_test", uvm_component parent);
super.new(name, parent);
endfunction
function void build_phase(uvm_phase phase);
super.build_phase(phase);
endfunction
task run_phase(uvm_phase phase);
apb_watchdog_regacc_virt_seq seq = apb_watchdog_regacc_virt_seq::type_id::create("this");
super.run_phase(phase);
phase.raise_objection(this);
seq.start(env.virt_sqr);
phase.drop_objection(this);
endtask
endclass
`endif //APB_WATCHDOG_REGACC_TEST_SV
【调试及实验结果】
(1)调试
调试以后报错未能找到这个对象,debug方法:
- 在该位置设置断点,点击local查看局部变量,观察对象是否都有例化,也就是是否有艾特值。
- 经过查看以后是map没有例化
(2)实验结果
使用寄存器模型对寄存器中值访问的结果和在apb总线上访问的结果相同
4.2 集成测试模式
WDOGITCR寄存器控制了集成测试的开关。 当打开了集成测试的开关以后,WDOGINT和WDOGRES的值直接由WDOGITOP来决定。
4.2.1 编辑apb_watchdog_integration_virt_seq
做以下几个数值比较:
- 拉高enable信号之前,检查int和res的默认值是否为0;
- 拉高enable信号之后,拉高int和res,与1进行比较;
- 拉高enable信号之后,拉低int和res,与0进行比较;
- 拉高enable信号之后拉高int和res,与1进行比较,之后再拉低enable信号,观察对于int和res信号线是否有影响。
- 接下来使用前门访问方法update()来复位reset 寄存器;
- 需要检查的两个信号的数值可以在interface中已经定义,他们在tb中也连接到了对应的端口上,而vif也在base_virt_seq的body中做了连接,所以可以在integration_virt_seq中拿到接口上的信号;
注意设置的时候是对寄存器块中寄存器上的域的值进行配置,因此路径必须准确。
``verilog
ifndef APB_WATCHDOG_INTEGRATION_VIRT_SEQ_SV `define APB_WATCHDOG_INTEGRATION_VIRT_SEQ_SVclass apb_watchdog_integration_virt_seq extends apb_watchdog_base_virt_seq;
`uvm_object_utils(apb_watchdog_integration_virt_seq)
function new(string name = “apb_watchdog_integration_virt_seq”);
super.new();
endfunction
task body(); super.body(); `uvm_info(“body”, “Entered…”, UVM_LOW)
// Check WDOGINT & WDOGRES reset value
`uvm_info("INTGTEST","Check WDOGINT & WDOGRES reset value", UVM_LOW)
compare_data(vif.wdog_int, 1'b0);
compare_data(vif.wdog_res, 1'b0);
// Enable integration test mode
rgm.WDOGITCR.ITME.set(1'b1);
rgm.WDOGITCR.update(status);
// Check WDOGINT & WDOGRES test control value
`uvm_info("INTGTEST","Check WDOGINT & WDOGRES test control value", UVM_LOW)
rgm.WDOGITOP.WDOGINT.set(1'b1);
rgm.WDOGITOP.WDOGRES.set(1'b1);
rgm.WDOGITOP.update(status);
compare_data(vif.wdog_int, 1'b1);
compare_data(vif.wdog_res, 1'b1);
rgm.WDOGITOP.WDOGINT.set(1'b0);
rgm.WDOGITOP.WDOGRES.set(1'b0);
rgm.WDOGITOP.update(status);
compare_data(vif.wdog_int, 1'b0);
compare_data(vif.wdog_res, 1'b0);
// Check WDOGINT & WDOGRES test mode exit
`uvm_info("INTGTEST","Check WDOGINT & WDOGRES test mode exit value", UVM_LOW)
rgm.WDOGITOP.WDOGINT.set(1'b1);
rgm.WDOGITOP.WDOGRES.set(1'b1);
rgm.WDOGITOP.update(status);
compare_data(vif.wdog_int, 1'b1);
compare_data(vif.wdog_res, 1'b1);
rgm.WDOGITCR.ITME.set(1'b0);
rgm.WDOGITCR.update(status);
`uvm_info("SEQSTART","virtual sequence body started!", UVM_LOW)
#1us;
`uvm_info(“body”, “Exiting…”, UVM_LOW) endtask endclass
`endif //apb_watchdog_integration_virt_seq
【调试及结果】
在class中输入 integration找到apb_watchdog_integration_virt_seq并设置断点。
在拉起enable之前的int和res默认值都是0,第一个测试通过
在拉起enable进入集成测试模式以后,int和res的值分别是1和0,测试通过;
对于最后一个测试而言,在enable拉高的时候,res和int的值都是1无误,但是当enable拉低以后,对寄存器中的值产生了影响,值变成了0不再是1。
从波形上也可以看出,当penable拉低以后,int和res的值也变成0,也就是说变成了复位的默认值。
【分析】
当集成测试的配置功能enable拉低以后,int和res两个信号线就是由watchdog内部的功能决定而不是由寄存器来配置。具体可以在design的驱动逻辑中来查找:
通过点击DUT中的信号线可以追溯到信号线的设计逻辑,可以发现这是一个组合逻辑,当wdog_itcr为低的时候,watchdog信号线的逻辑由内部的功能逻辑驱动。
【附件】
至此完成了对apb_watchdog_v2环境的搭建