6.1 计数和复位使能测试
在之前已经完成了INT信号拉起的测试序列,根据状态机,最后就是当计数器递减到0以后,如果RESEN信号被设置成1,那么复位,对这个状态编写测试序列。
:::info
在seq_lib中新建apb_watchdog_res_en_virt_seq.sv并编辑; :::
``verilog
ifndef APB_WATCHDOG_RES_EN_VIRT_SEQ_SV `define APB_WATCHDOG_RES_EN_VIRT_SEQ_SVclass apb_watchdog_res_en_virt_seq extends apb_watchdog_base_virt_seq;
`uvm_object_utils(apb_watchdog_res_en_virt_seq)
function new(string name = “apb_watchdog_res_en_virt_seq”); super.new(name); endfunction
virtual task body(); super.body(); `uvm_info(“body”,”Entered…”,UVM_LOW)
// Enable apb_watchdog_reg and its interrupt generation
`uvm_do(reg_en_intr)
`uvm_do(reg_en_res)
// Get load_val
`uvm_do_with(reg_loadcount, {load_val == 'hFF;})
// Get clear signal
//`uvm_do_with(reg_intr_wait_clear, {intval == 50; delay == 1;})
fork
@(posedge vif.wdog_res);
@(posedge vif.wdog_int);
join
#100us;
`uvm_info("body", "EXited...", UVM_LOW)
endtask
endclass
`endif //APB_WATCHDOG_RES_EN_VIRT_SEQ_SV
> fork join的作用是等待一个reset和int中断信号的拉高信号;
> 拉高以后再等100us。观察在这一段时间以内int和res的信号是否还有发生其他变化。
:::info
2. 在test中建立对应的测试文件并编辑;
:::
```verilog
`ifndef APB_WATCHDOG_RES_EN_TEST_SV
`define APB_WATCHDOG_RES_EN_TEST_SV
class apb_watchdog_res_en_test extends apb_watchdog_base_test;
`uvm_component_utils(apb_watchdog_res_en_test)
function new(string name = "apb_watchdog_res_en_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_res_en_virt_seq seq = apb_watchdog_res_en_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_RES_EN_TEST_SV
:::info
在element_seqs.svh文件中导入上一个seq; :::
``verilog
ifndef APB_WATCHDOG_REG_ENABLE_RESET_SV `define APB_WATCHDOG_REG_ENABLE_RESET_SVclass apb_watchdog_reg_enable_reset extends apb_watchdog_element_base_seq;
`uvm_object_utils(apb_watchdog_reg_enable_reset)
function new(string name = “apb_watchdog_reg_enable_reset”); super.new(name); endfunction
task body(); super.body();
uvm_info("body", "Entered...", UVM_LOW) rgm.WDOGCONTROL.RESEN.set(1'b1); rgm.WDOGCONTROL.update(status);
uvm_info(“body”, “Exiting…”, UVM_LOW) endtaskendclass
`endif //APB_WATCHDOG_REG_ENABLE_RESET
:::info
4. 在apb_watchdog_base_virt_seq中导入这个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_reg_enable_intr reg_en_intr;
apb_watchdog_reg_intr_wait_clear reg_intr_wait_clear;
apb_watchdog_reg_loadcount reg_loadcount;
apb_watchdog_reg_enable_reset reg_en_res;
...
endclass
`endif //APB_WATCHDOG_BASE_VIRT_SEQ
:::info
- 在seq_lib中导入apb_watchdog_reset_en_virt_seq.sv;
- 在tests.svh中导入apb_watchdog_reset_enable_test.sv
:::
【调试及结果】
在class中查找res_en,在源代码中分别设置断点。 将DUT中寄存器上的reg_count信号添加到波形窗口中,将该波形的sim.do文件重新保存
根据波形: 当load的值是FF时,开始从FF向下递减,当递减到0的时候,INT信号拉高,由于没有重新编程,因此会重新loadFF值开始向下递减直到0。 当reset信号拉高以后,计数停止。
6.1.2 修改测试用例中的等待信号
:::info 在res_en_virt_seq中我们使用了@(posedge vif.xxx)的方法来等待watchdog寄存器上的INT和RES信号,为了对这些信号能够进行复用,将这些信号定义到base_virt_seq中的task中。 :::
`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_reg_enable_intr reg_en_intr;
apb_watchdog_reg_intr_wait_clear reg_intr_wait_clear;
apb_watchdog_reg_loadcount reg_loadcount;
apb_watchdog_reg_enable_reset reg_en_res;
apb_watchdog_config cfg;
virtual apb_watchdog_if vif;
apb_watchdog_rgm rgm;
bit [31:0] rd_val, wr_val;
uvm_status_e status;
`uvm_object_utils(apb_watchdog_base_virt_seq)
`uvm_declare_p_sequencer(apb_watchdog_virtual_sequencer)
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
task wait_int_asserted();
@(posedge vif.wdog_int);
endtask
task wait_int_released();
@(negedge vif.wdog_int);
endtask
task wait_reset_asserted();
@(posedge vif.wdog_res);
endtask
task wait_reset_released();
@(negedge vif.wdog_res);
endtask
endclass
`endif //APB_WATCHDOG_BASE_VIRT_SEQ
6.2 中断功能关闭测试
【思考】 INT拉高以后,在还没有将INT信号擦除的情况下直接对CONTROL寄存器进行配置将INT信号使能中断:
- 计数功能是否还会正常运行;
- Raw status寄存器是怎样的?
:::info 环境搭建与之前一致:
- 在element_seqs中添加apb_watchdog_reg_disable_intr.sv并将enable信号设置为低;
在element_sequences.svh中导入上个seq; :::
``verilog
ifndef APB_WATCHDOG_REG_DISABLE_INTR_SV `define APB_WATCHDOG_REG_DISABLE_INTR_SVclass apb_watchdog_reg_disable_intr extends apb_watchdog_element_base_seq;
`uvm_object_utils(apb_watchdog_reg_disable_intr)
function new(string name = “apb_watchdog_reg_disable_intr”); super.new(name); endfunction
task body(); super.body();
uvm_info("body", "Entered...", UVM_LOW) rgm.WDOGCONTROL.INTEN.set(1'b0); rgm.WDOGCONTROL.update(status);
uvm_info(“body”, “Exiting…”, UVM_LOW) endtaskendclass
`endif //APB_WATCHDOG_REG_DISABLE_INTR
```verilog
`ifndef APB_WATCHDOG_ELEMENT_SEQUENCES_SVH
`define APB_WATCHDOG_ELEMENT_SEQUENCES_SVH
`include "apb_watchdog_element_base_seq.sv"
`include "apb_watchdog_reg_enable_intr.sv"
`include "apb_watchdog_reg_loadcount.sv"
`include "apb_watchdog_reg_intr_wait_clear.sv"
`include "apb_watchdog_reg_enable_reset.sv"
`include "apb_watchdog_reg_disable_intr.sv"
`endif //APB_WATCHDOG_ELEMENT_SEQUENCES_SVH
:::info
- 在seq_lib目录下创建并编辑apb_watchdog_disable_intr_virt_seq.sv;
在seq_lib中的seq_lib.svh文件中导入上一个seq; :::
``verilog
ifndef APB_WATCHDOG_DISABLE_INTR_VIRT_SEQ_SV `define APB_WATCHDOG_DISABLE_INTR_VIRT_SEQ_SVclass apb_watchdog_disable_intr_virt_seq extends apb_watchdog_base_virt_seq;
`uvm_object_utils(apb_watchdog_disable_intr_virt_seq)
function new(string name = “apb_watchdog_disable_intr_virt_seq”); super.new(name); endfunction
virtual task body(); super.body(); `uvm_info(“body”,”Entered…”,UVM_LOW)
// Enable apb_watchdog_reg and its interrupt generation
`uvm_do(reg_en_intr)
`uvm_do(reg_en_res)
// Get load_val
`uvm_do_with(reg_loadcount, {load_val == 'hFF;})
// Get clear signal
//`uvm_do_with(reg_intr_wait_clear, {intval == 50; delay == 1;})
#10us;
`uvm_do(reg_dis)
fork
wait_int_asserted();
wait_reset_released();
join
#20us;
`uvm_info("body", "EXited...", UVM_LOW)
endtask
endclass
`endif //APB_WATCHDOG_DISABLE_INTR_VIRT_SEQ_SV
> 第一轮等待了Int信号拉高,第二轮等待了reset信号拉高。
```verilog
`ifndef APB_WATCHDOG_SEQ_LIB_SVH
`define APB_WATCHDOG_SEQ_LIB_SVH
`include "apb_watchdog_element_sequences.svh"
`include "apb_watchdog_base_virt_seq.sv"
`include "apb_watchdog_integration_virt_seq.sv"
`include "apb_watchdog_regacc_virt_seq.sv"
`include "apb_watchdog_apbacc_virt_seq.sv"
`include "apb_watchdog_countdown_virt_seq.sv"
`include "apb_watchdog_res_en_virt_seq.sv"
`include "apb_watchdog_disable_intr_virt_seq.sv"
`endif //APB_WATCHDOG_SEQ_LIB.SVH
:::info
- 在test目录下创建并编辑apb_watchdog_disable_intr_test.sv
在tests.svh中导入上一个测试文件 :::
``verilog
ifndef APB_WATCHDOG_TESTS_SVH `define APB_WATCHDOG_TESTS_SVHinclude "apb_watchdog_base_test.sv"
include “apb_watchdog_apbacc_test.sv”include "apb_watchdog_integration_test.sv"
include “apb_watchdog_regacc_test.sv”include "apb_watchdog_countdown_test.sv"
include “apb_watchdog_res_en_test.sv” `include “apb_watchdog_disable_intr_test.sv”
`endif //APB_WATCHDOG_TESTS_SVH
:::info
❗编辑apb_watchdog_disable_intr_virt_seq.sv
:::
```verilog
`ifndef APB_WATCHDOG_DISABLE_INTR_VIRT_SEQ_SV
`define APB_WATCHDOG_DISABLE_INTR_VIRT_SEQ_SV
class apb_watchdog_disable_intr_virt_seq extends apb_watchdog_base_virt_seq;
`uvm_object_utils(apb_watchdog_disable_intr_virt_seq)
function new(string name = "apb_watchdog_disable_intr_virt_seq");
super.new(name);
endfunction
virtual task body();
super.body();
`uvm_info("body","Entered...",UVM_LOW)
// Enable apb_watchdog_reg and its interrupt generation
`uvm_do(reg_en_intr)
// Get load_val
`uvm_do_with(reg_loadcount, {load_val == 'hFF;})
wait_int_asserted();// wait interrupt signal high
check_reg_ris_mis(1'b1, 1'b1);
repeat(20) @(posedge vif.wdg_clk);
fork
`uvm_do(reg_dis_intr) // disable reg_dis_intr
wait_int_released(); // wait interrupt signal released
join
check_reg_ris_mis(1'b1, 1'b0);
#1us; // idle time monitoring count
`uvm_info("body", "EXited...", UVM_LOW)
endtask
task check_reg_ris_mis(input ris, input mis);
rgm.WDOGRIS.mirror(status);
compare_data(ris, rgm.WDOGRIS.RAWINT.get());
rgm.WDOGMIS.mirror(status);
compare_data(mis, rgm.WDOGMIS.INT.get());
endtask
endclass
`endif //APB_WATCHDOG_DISABLE_INTR_VIRT_SEQ_SV
WDOGRIS是INT寄存器的原始状态(RAW status); WDOGMIS是INT寄存器与INTEN使能信号与之后的状态。虽然将ENABLE信号拉低了,但是原始状态仍然为高,这里需要区分清除。
【调试及结果】
在class中输入dis并设置断点
波形图如上,等到了INT信号拉高并进行比较,两次结果相等; 不清除INT信号直接将使能信号中断,计数功能停止。Raw状态(后台状态,没有被清除的状态下仍然为高),但是软件状态一侧读取到的值为低,也就是MIS status。
6.3 中断功能关闭再使能测试
【思考】 将INTEN信号拉低以后,INT在后台状态仍然是拉高的,只是被mask掉了,那么思考: 将INTEN信号再次拉高以后,INT信号是否立刻为高呢?为此再进行以下测试:
:::info 在apb_watchdog_disable_intr_virt_seq.sv添加拉高INTEN的语句 :::
`ifndef APB_WATCHDOG_DISABLE_INTR_VIRT_SEQ_SV
`define APB_WATCHDOG_DISABLE_INTR_VIRT_SEQ_SV
class apb_watchdog_disable_intr_virt_seq extends apb_watchdog_base_virt_seq;
`uvm_object_utils(apb_watchdog_disable_intr_virt_seq)
function new(string name = "apb_watchdog_disable_intr_virt_seq");
super.new(name);
endfunction
virtual task body();
super.body();
`uvm_info("body","Entered...",UVM_LOW)
// Enable apb_watchdog_reg and its interrupt generation
`uvm_do(reg_en_intr)
// Get load_val
`uvm_do_with(reg_loadcount, {load_val == 'hFF;})
wait_int_asserted();// wait interrupt signal high
check_reg_ris_mis(1'b1, 1'b1);
repeat(20) @(posedge vif.wdg_clk);
fork
`uvm_do(reg_dis_intr) // disable reg_dis_intr
wait_int_released(); // wait interrupt signal released
join
check_reg_ris_mis(1'b1, 1'b0);
// Enable interrupt signal again
`uvm_do(reg_en_intr)
// Check INT signal imediately
compare_data(vif.wdog_int, 1'b1);
check_reg_ris_mis(1'b1, 1'b1);
#1us; // idle time monitoring count
`uvm_info("body", "EXited...", UVM_LOW)
endtask
task check_reg_ris_mis(input ris, input mis);
rgm.WDOGRIS.mirror(status);
compare_data(ris, rgm.WDOGRIS.RAWINT.get());
rgm.WDOGMIS.mirror(status);
compare_data(mis, rgm.WDOGMIS.INT.get());
endtask
endclass
`endif //APB_WATCHDOG_DISABLE_INTR_VIRT_SEQ_SV
根据结果来看,INTEN重新使能以后,INT信号是立即拉高的,INT的两个status的值也都是1。