【总结】
- 本节中对apb_watchdog的递减计数功能:通过在seq中对寄存器模型的值进行配置来实现;
- 实现了对中断信号INT的复位功能,在中断测试中嵌套seq来等到中断信号;这些被嵌套的sequence放在了element_sequence中。
- base_virt_sequence和element_sequence是协调与被协调测试场景的关系,两者没有继承关系,但是将一些底层硬件信号线的修改放到element_sequence中可以方便之后对环境的复用;
- 中断的seq和base_virt_seq之间具有继承关系。
- 通过一些定向的测试来理解硬件的行为,然后再写scoreboard。

回顾状态机可以发现在没有reprogram的情况下计数器会不断减小直至0,如果enable信号为高,那么int信号会被拉起,否则就开始新一轮的重新计数。
5.1 测试watchdog计数递减功能
5.1.1 sequence&test一侧代码
:::info
(1)在test中添加apb_watchdog_countdown_test.sv;
(2)在seq_lib中添加apb_watchdog_countdown_virt_seq.sv;
(3)在seq_lib.svh中导入virt_seq文件;
(4)同样,在tests.svh中导入test.sv文件
:::
`ifndef APB_WATCHDOG_COUNTDOWN_TEST_SV`define APB_WATCHDOG_COUNTDOWN_TEST_SVclass apb_watchdog_countdown_test extends apb_watchdog_base_test;`uvm_component_utils(apb_watchdog_countdown_test)function new(string name = "apb_watchdog_countdown_test", uvm_component parent);super.new(name, parent);endfunctionfunction void build_phase(uvm_phase phase);super.build_phase(phase);endfunctiontask run_phase(uvm_phase phase);apb_watchdog_countdown_virt_seq seq = apb_watchdog_countdown_virt_seq::type_id::create("this");super.run_phase(phase);phase.raise_objection(this);seq.start(env.virt_sqr);phase.drop_objection(this);endtaskendclass`endif //APB_WATCHDOG_COUNTDOWN_TEST_SV

当Load寄存器拿到一个新的数值以后,会立刻开始递减。
:::info (5)编辑apb_watchdog_countdown_virt_seq:
- 向WDOGLOAD寄存器中写入数据,随后将它读出来;
- 将WDOGVALUE寄存器中的数据也读出来,
:::
``verilogifndef APB_WATCHDOG_COUNTDOWN_VIRT_SEQ_SV `define APB_WATCHDOG_COUNTDOWN_VIRT_SEQ_SV
class apb_watchdog_countdown_virt_seq extends apb_watchdog_base_virt_seq;
`uvm_object_utils(apb_watchdog_countdown_virt_seq)
function new(string name = “apb_watchdog_countdown_virt_seq”); super.new(name); endfunction
virtual task body();
super.body();
uvm_info("body","Entered...",UVM_LOW)
rgm.WDOGLOAD.write(status, 'hFF);
repeat(10) begin
rgm.WDOGLOAD.read(status, rd_val);uvm_info(“REGVALUE”, $sformatf(“APB WDOGLOAD IS %0x”, rd_val), UVM_LOW)
rgm.WDOGVALUE.read(status, rd_val);
`uvm_info(“REGVALUE”, $sformatf(“APB WDOGVALUE IS %0x”, rd_val), UVM_LOW)
end
endtask
endclass
`endif //APB_WATCHDOG_COUNTDOWN_VIRT_SEQ_SV
<a name="NsJpr"></a>## 【调试及结果】```shellmake elabmake run GUI=1 TESTNAME=apb_watchdog_countdown_test &

WDOGLOAD和WDOGVALUE的值都是ff,对寄存器的配置成功但是递减的功能没有实现。
通过查看设计文件,发现是reg_count值没有发生变化,因此可以从硬件一侧查看驱动逻辑:
双击DUT-u_apb_watchdog_frc中的reg_count,进一步展开可以看到是由count_mux2驱动的。

计数器运行的两个条件:
- watchdog被使能且计数器没有停止;
- 一个新的值被加载。
本次测试中的wdog_int_en信号为0,也就是int没有被使能,因此前面的条件不满足,只能保持为reg_count这个值,所以count_mux2的值没有变化。
计数器真正完成递减的逻辑在count_mux1中。

重新查阅文档以后发现enable值需要设置为高才能使能计数和中断功能。
5.2 测试watchdog中断拉起功能
5.2.1 更新sequence一侧代码
:::info 对apb_watchdog_countdown_virt_seq.sv重新编辑,添加enable信号后再进行调试 :::
`ifndef APB_WATCHDOG_COUNTDOWN_VIRT_SEQ_SV`define APB_WATCHDOG_COUNTDOWN_VIRT_SEQ_SVclass apb_watchdog_countdown_virt_seq extends apb_watchdog_base_virt_seq;`uvm_object_utils(apb_watchdog_countdown_virt_seq)function new(string name = "apb_watchdog_countdown_virt_seq");super.new(name);endfunctionvirtual task body();super.body();`uvm_info("body","Entered...",UVM_LOW)// Enable apb_watchdog_reg and its interrupt generationrgm.WDOGCONTROL.INTEN.set(1'b1);rgm.WDOGCONTROL.update(status);rgm.WDOGLOAD.write(status, 'hFF);repeat(10) beginrgm.WDOGLOAD.read(status, rd_val);`uvm_info("REGVALUE", $sformatf("APB WDOGLOAD IS %0x", rd_val), UVM_LOW)rgm.WDOGVALUE.read(status, rd_val);`uvm_info("REGVALUE", $sformatf("APB WDOGVALUE IS %0x", rd_val), UVM_LOW)end#20ns;`uvm_info("body", "EXited...", UVM_LOW)endtaskendclass`endif //APB_WATCHDOG_COUNTDOWN_VIRT_SEQ_SV
【注】对寄存器模型中寄存器的值进行修改
- 可以对寄存器模型中的某一个寄存器直接使用write方法对寄存器的值进行修改;
- 也可以使用set对寄存器中某一个域的值进行配置;
- 无论采用什么方法,都需要最后做寄存器的update()。
【调试及结果】


波形如上图所示
- 可以看到在count_mux2信号中,一个信号的完整发送需要50ns,1us可以发送20周期的数据;
- 配置的WDOGLOAD的值是’FF也就是255,如果要将所有的数据发送完毕需要不到12.75ns。
- 因此在12.75ns的位置有一个carry_msb的信号的拉高;
- 同时在该位置寄存器当前读取的值减小为0并重新从FF开始向下递减。

同时可以在WDOG的信号线上看到INT信号线也拉高了,这个中断信号不会自己拉低,除非重新进行配置。
5.3 element sequence创建(测试拉起INT和擦除功能)
5.3.1 中断的处理
:::warning 🔔【思考】
- 在之前已经完成了简单的计数递减的功能并在信号线上造成了一个INT信号,那么如何等待这个中断并对其擦除呢?我们选择在element_seqs中对其做进一步处理。
- 可以在哪里等待这个中断?
5.3.2 建立等待中断的目录element_seqs
:::info
- 在seq_lib中添加elem_seqs;
- 在elem_seqs中添加:
- apb_watchdog_element_base_seq.sv(继承uvm_sequence)
- apb_watchdog_reg_intr_wait_clear.sv (清除int信号)
- apb_watchdog_reg_enable_intr.sv (使能信号)
- apb_watchdog_reg_loadcount.sv (设置计数值)
- 在elem_seqs中添加apb_watchdog_element_sequences.svh
在.svh文件中导入所有的sv文件 :::
``verilogifndef APB_WATCHDOG_ELEMENT_SEQUENCES_SVH `define APB_WATCHDOG_ELEMENT_SEQUENCES_SVHinclude "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”
`endif //APB_WATCHDOG_ELEMENT_SEQUENCES_SVH
:::info5. 编辑apb_watchdog_element_base_seq.sv:::```verilog`ifndef APB_WATCHDOG_ELEMENT_BASE_SEQ_SV`define APB_WATCHDOG_ELEMENT_BASE_SEQ_SVclass apb_watchdog_element_base_seq extends uvm_sequence;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_element_base_seq)`uvm_declare_p_sequencer(apb_watchdog_virtual_sequencer)function new(string name = "apb_watchdog_element_base_seq");super.new(name);endfunctionvirtual task body();`uvm_info("body","Entered...",UVM_LOW)//Get cfg from p_sequencercfg = p_sequencer.cfg;vif = cfg.vif;rgm = cfg.rgm;`uvm_info("body","Exiting...",UVM_LOW)endtaskvirtual 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 begincfg.seq_check_error++;`uvm_error("CMPSUC", $sformatf("val1 'h%0x !== val2 'h%0x", val1, val2))endendfunctionendclass`endif //APB_WATCHDOG_ELEMENT_BASE_SEQ_SV
:::info
- 在seq_lib.svh中导入elem_seqs.svh文件;
修改makefile(原因是在seq_lib中添加了elem_seqs.svh文件,需要修改文件的路径来进行查找); :::
``verilogifndef APB_WATCHDOG_SEQ_LIB_SVH `define APB_WATCHDOG_SEQ_LIB_SVHinclude "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”
`endif //APB_WATCHDOG_SEQ_LIB.SVH
> 注意apb_watchdog_elemanet_sequences.svh必须在apb_watchdog_base_virt_seq.sv前面,因为后者是一个virtual sequence,协调了顶层的测试场景,将element_seq也包含在内,所以必须先编译element_sequence。> 在需要查找的目录中添加elem_seqs文件夹<a name="PSRc7"></a>## 5.3.3 编辑中断序列&加载寄存器序列&清除中断序列:::info1. 编辑apb_watchdog_reg_enable_intr.sv并给定enable信号的设置和更新:::```verilog`ifndef APB_WATCHDOG_REG_ENABLE_INTR_SV`define APB_WATCHDOG_REG_ENABLE_INTR_SVclass apb_watchdog_reg_enable_intr extends apb_watchdog_element_base_seq;`uvm_object_utils(apb_watchdog_reg_enable_intr)function new(string name = "apb_watchdog_reg_enable_intr");super.new(name);endfunctiontask body();super.body();`uvm_info("body", "Entered...", UVM_LOW)rgm.WDOGCONTROL.INTEN.set(1'b1);rgm.WDOGCONTROL.update(status);`uvm_info("body", "Exiting...", UVM_LOW)endtaskendclass`endif //APB_WATCHDOG_REG_ENABLE_INTR
:::info
编辑apb_watchdog_reg_loadcount.sv文件并给定load值的区间(以软约束的形式) :::
``verilogifndef APB_WATCHDOG_REG_LOADCOUNT_SV `define APB_WATCHDOG_REG_LOADCOUNT_SVclass apb_watchdog_reg_loadcount extends apb_watchdog_element_base_seq;
rand bit[31:0] load_val; constraint load_cstr{ soft load_val inside {[‘h1:’hFFFF]}; }
`uvm_object_utils(apb_watchdog_reg_loadcount)
function new(string name = “apb_watchdog_reg_loadcount”); super.new(name); endfunction
task body(); super.body();
uvm_info("body", "Entered...", UVM_LOW) rgm.WDOGLOAD.write(status, load_val);uvm_info(“body”, “Exiting…”, UVM_LOW) endtask endclass
`endif //APB_WATCHDOG_REG_LOADCOUNT
:::info3. 编辑apb_watchdog_reg_intr_wait_clear.sv(擦除intr信号)1. 添加delay,在等到delay的若干拍以后对int信号进行擦除;1. 添加intval这样一个信号的间隔期;1. 等待int的办法:1. signal的int;1. interrupt status寄存器中的int:::```verilog`ifndef APB_WATCHDOG_REG_INTR_WAIT_CLEAR_SV`define APB_WATCHDOG_REG_INTR_WAIT_CLEAR_SVclass apb_watchdog_reg_intr_wait_clear extends apb_watchdog_element_base_seq;rand int delay;//注意这里是int类型rand int intval;constraint load_cstr {soft intval inside {[10:100]};soft delay inside {[1:10]};}`uvm_object_utils(apb_watchdog_reg_intr_wait_clear)function new(string name = "apb_watchdog_reg_intr_wait_clear");super.new(name);endfunctiontask body();super.body();`uvm_info("body", "Entered...", UVM_LOW)// Wait for apb_watchdog_reg_int triggerdforever beginrgm.WDOGMIS.mirror(status);if(rgm.WDOGMIS.INT.get()) break;repeat(intval) @(posedge vif.apb_clk);endrepeat(delay) @(posedge vif.apb_clk);rgm.WDOGINTCLR.INTCLR.set('h1);//擦除INT信号rgm.WDOGINTCLR.update(status);`uvm_info("body", "Exiting...", UVM_LOW)endtaskendclass`endif //APB_WATCHDOG_REG_INTR_WAIT_CLEAR
等待interrupt:
- 如果等到了,break即可;
- 如果没有等到,那么在intval的时间段以内要继续等。
由于reg_intr_wait_clear继承于base_virt_seq,它可以通过p_sequencer获取到vif,因此可以等待apb_clk时钟。
5.3.4 将测试序列的句柄集中到base_virt_seq中
`ifndef APB_WATCHDOG_BASE_VIRT_SEQ_SV`define APB_WATCHDOG_BASE_VIRT_SEQ_SVclass 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_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);endfunctionvirtual task body();`uvm_info("body","Entered...",UVM_LOW)//Get cfg from p_sequencercfg = p_sequencer.cfg;vif = cfg.vif;rgm = cfg.rgm;`uvm_info("body","Exiting...",UVM_LOW)endtaskvirtual 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 begincfg.seq_check_error++;`uvm_error("CMPSUC", $sformatf("val1 'h%0x !== val2 'h%0x", val1, val2))endendfunctionendclass`endif //APB_WATCHDOG_BASE_VIRT_SEQ
5.3.5 编辑apb_watchdog_countdown_virt_seq中的body部分
:::info
- 更改原来对寄存器模型中寄存器域的值配置的方式;
在body()部分中改用宏来发送序列 :::
``verilogifndef APB_WATCHDOG_COUNTDOWN_VIRT_SEQ_SV `define APB_WATCHDOG_COUNTDOWN_VIRT_SEQ_SVclass apb_watchdog_countdown_virt_seq extends apb_watchdog_base_virt_seq;
`uvm_object_utils(apb_watchdog_countdown_virt_seq)
function new(string name = “apb_watchdog_countdown_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(apb_wdg_reg_en_intr)// Get load_val`uvm_do_with(apb_wdg_reg_loadcount, {load_val == 'hFF;})// Get clear signal`uvm_do_with(apb_wdg_reg_intr_wait_clear, {intval == 50; delay == 1;})//--rgm.WDOGCONTROL.INTEN.set(1'b1);//--rgm.WDOGCONTROL.update(status);//--rgm.WDOGLOAD.write(status, 'hFF);//repeat(10) begin// rgm.WDOGLOAD.read(status, rd_val);// `uvm_info("REGVALUE", $sformatf("APB WDOGLOAD IS %0x", rd_val), UVM_LOW)// rgm.WDOGVALUE.read(status, rd_val);// `uvm_info("REGVALUE", $sformatf("APB WDOGVALUE IS %0x", rd_val), UVM_LOW)//end// #20us;`uvm_info("body", "EXited...", UVM_LOW)
endtask
endclass
`endif //APB_WATCHDOG_COUNTDOWN_VIRT_SEQ_SV
> apb_watchdog_countdown_virt_seq继承于父类apb_watchdog_element_base_seq,所以它的句柄也是挂载到了virt_sqr上,因此可以使用`uvm_do。<a name="zuiPQ"></a># 【验证结构框图】<a name="LDkKh"></a>## 【调试及结果】> 与5.2节中的实验结果相同,在12.975ns时INT信号拉高。---<a name="LCZ2v"></a># 5.4 中断功能关闭测试> 【思考1】> watchdog load到value以后会开始进行技术递减,当递减到0以后INT信号会拉高,重新load值并进行递减,如果对INT信号不进行擦除的话是一个什么样的过程呢?:::info修改测试激励apb_watchdog_countdown_virt_seq.sv,不再擦除INT信号。:::<br />对波形进行查看,再不进行INT信号复位的时候,Watchdog会重新load value值并向下开始计数。---<a name="qYWQI"></a># 5.5 测试对CLR值任意写入的功能> 【思考2】> 功能描述文档中提到对WDOGINTCLR中写入任意一个数值都会导致watchdog重新读取数据并开始递减,随机在任意时刻写入CLR来清楚INT信号,观察计数是否是不断擦掉然后重新开始计数:::info编辑apb_watchdog_countdown_virt_seq.sv:::```verilog`ifndef APB_WATCHDOG_COUNTDOWN_VIRT_SEQ_SV`define APB_WATCHDOG_COUNTDOWN_VIRT_SEQ_SVclass apb_watchdog_countdown_virt_seq extends apb_watchdog_base_virt_seq;`uvm_object_utils(apb_watchdog_countdown_virt_seq)function new(string name = "apb_watchdog_countdown_virt_seq");super.new(name);endfunctionvirtual 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;})// Get clear signal`uvm_do_with(reg_intr_wait_clear, {intval == 50; delay inside {30, 40};})//--rgm.WDOGCONTROL.INTEN.set(1'b1);//--rgm.WDOGCONTROL.update(status);//--rgm.WDOGLOAD.write(status, 'hFF);//repeat(10) begin// rgm.WDOGLOAD.read(status, rd_val);// `uvm_info("REGVALUE", $sformatf("APB WDOGLOAD IS %0x", rd_val), UVM_LOW)// rgm.WDOGVALUE.read(status, rd_val);// `uvm_info("REGVALUE", $sformatf("APB WDOGVALUE IS %0x", rd_val), UVM_LOW)//end#20us;`uvm_info("body", "EXited...", UVM_LOW)endtaskendclass`endif //APB_WATCHDOG_COUNTDOWN_VIRT_SEQ_SV
:::info 修正apb_watchdog_reg_intr_wait_clr.sv中的clk信号 :::
`ifndef APB_WATCHDOG_REG_INTR_WAIT_CLEAR_SV`define APB_WATCHDOG_REG_INTR_WAIT_CLEAR_SVclass apb_watchdog_reg_intr_wait_clear extends apb_watchdog_element_base_seq;rand int delay;rand int intval;constraint load_cstr {soft intval inside {[10:100]};soft delay inside {[1:10]};}`uvm_object_utils(apb_watchdog_reg_intr_wait_clear)function new(string name = "apb_watchdog_reg_intr_wait_clear");super.new(name);endfunctiontask body();super.body();`uvm_info("body", "Entered...", UVM_LOW)// Wait for apb_watchdog_reg_int triggerdforever beginrgm.WDOGMIS.mirror(status);if(rgm.WDOGMIS.INT.get()) break;repeat(intval) @(posedge vif.apb_clk);endrepeat(delay) @(posedge vif.wdg_clk);rgm.WDOGINTCLR.INTCLR.set('h1);rgm.WDOGINTCLR.update(status);`uvm_info("body", "Exiting...", UVM_LOW)endtaskendclass`endif //APB_WATCHDOG_REG_INTR_WAIT_CLEAR
擦除INT信号必须在INT信号拉高以后的若干拍进行,所以时钟必须是wdg_clk而不是apb_clk。

根据波形可以看到在INT拉高的若干拍以后被CLR重新设置为0,计数器reload并从FF重新开始向下计数。
5.6 两次CLR测试
`ifndef APB_WATCHDOG_COUNTDOWN_VIRT_SEQ_SV`define APB_WATCHDOG_COUNTDOWN_VIRT_SEQ_SVclass apb_watchdog_countdown_virt_seq extends apb_watchdog_base_virt_seq;`uvm_object_utils(apb_watchdog_countdown_virt_seq)function new(string name = "apb_watchdog_countdown_virt_seq");super.new(name);endfunctionvirtual 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;})// Get clear signalrepeat(2) `uvm_do_with(reg_intr_wait_clear, {intval == 50; delay inside {30, 40};})wait_int_released();#10us;`uvm_info("body", "EXited...", UVM_LOW)endtaskendclass`endif //APB_WATCHDOG_COUNTDOWN_VIRT_SEQ_SV
对INT信号进行时两次擦除,并在第二次擦除以后的1us停止采样。
仿真结束后再跑1us停止结束可以在test一层中使用其他的函数来实现
`ifndef APB_WATCHDOG_BASE_TEST_SV`define APB_WATCHDOG_BASE_TEST_SVvirtual 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...task run_phase(uvm_phase phase);super.run_phase(phase);phase.phase_done.set_drain_time(this, 1us);phase.raise_objection(this);do_init_clks();do_init_regs();phase.drop_objection(this);endtask...endclass`endif //APB_WATCHDOG_BASE_TEST
在test层的run_phase中可以使用set_drain_time来实现添加仿真结束后延迟的作用。
【调试及结果】

波形图可以看出,还没有等到第二次的CLR信号就已经采样结束了。

在apb_watchdog_countdown_virt_seq中设置断点,结果在第一次,寄存器已经将CLR信号配置为1,通过update(status)更新以后寄存器中的设计值已经默认1,没有拉低再拉高的信号出现。因此必须使用write来修改寄存器的实际值。
:::danger
【思考】
- 对于RO和WO这种寄存器而言,必须读回来然后再写入需要的数据;
对于配置寄存器(configuration)而言,可以使用update的形式来进行配置。 ::: :::info 修改apb_watchdog_reg_intr_wait_clear.sv :::
``verilogifndef APB_WATCHDOG_REG_INTR_WAIT_CLEAR_SV `define APB_WATCHDOG_REG_INTR_WAIT_CLEAR_SVclass apb_watchdog_reg_intr_wait_clear extends apb_watchdog_element_base_seq;
rand int delay; rand int intval; constraint load_cstr { soft intval inside {[10:100]}; soft delay inside {[1:10]}; } `uvm_object_utils(apb_watchdog_reg_intr_wait_clear)
function new(string name = “apb_watchdog_reg_intr_wait_clear”); super.new(name); endfunction
task body(); super.body();
uvm_info("body", "Entered...", UVM_LOW) // Wait for apb_watchdog_reg_int triggerd forever begin rgm.WDOGMIS.mirror(status); if(rgm.WDOGMIS.INT.get()) break; repeat(intval) @(posedge vif.apb_clk); end repeat(delay) @(posedge vif.wdg_clk); rgm.WDOGINTCLR.write(status, 1'b1);uvm_info(“body”, “Exiting…”, UVM_LOW) endtask endclass
`endif //APB_WATCHDOG_REG_INTR_WAIT_CLEAR
> 波形图如上,可以看到完成了两次完整的清除INT信号的动作<a name="sQZKi"></a>## 5.6.1 测试激励修改在清除CLR信号以后,此时等待INT信号拉低已经来不及了,需要采用fork_join对seq进行修改:```verilog`ifndef APB_WATCHDOG_COUNTDOWN_VIRT_SEQ_SV`define APB_WATCHDOG_COUNTDOWN_VIRT_SEQ_SVclass apb_watchdog_countdown_virt_seq extends apb_watchdog_base_virt_seq;`uvm_object_utils(apb_watchdog_countdown_virt_seq)function new(string name = "apb_watchdog_countdown_virt_seq");super.new(name);endfunctionvirtual 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;})// Get clear signalrepeat(2) beginfork`uvm_do_with(reg_intr_wait_clear, {intval == 50; delay inside {30, 40};})wait_int_released();joinend`uvm_info("body", "EXited...", UVM_LOW)endtaskendclass`endif //APB_WATCHDOG_COUNTDOWN_VIRT_SEQ_SV

此时已经正常能进行两次对INT的CLR操作,且能等到CLR拉低的信号出现。

在29us的时候就已经等到了第二个INT拉低的信号,由于在test中还添加了一个drain time,所以是在30us的时候退出了测试。
