【总结】
- 本节中对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_SV
class 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);
endfunction
function void build_phase(uvm_phase phase);
super.build_phase(phase);
endfunction
task 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);
endtask
endclass
`endif //APB_WATCHDOG_COUNTDOWN_TEST_SV
当Load寄存器拿到一个新的数值以后,会立刻开始递减。
:::info (5)编辑apb_watchdog_countdown_virt_seq:
- 向WDOGLOAD寄存器中写入数据,随后将它读出来;
- 将WDOGVALUE寄存器中的数据也读出来,
:::
``verilog
ifndef 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>
## 【调试及结果】
```shell
make elab
make 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_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)
// Enable apb_watchdog_reg and its interrupt generation
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
#20ns;
`uvm_info("body", "EXited...", UVM_LOW)
endtask
endclass
`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文件 :::
``verilog
ifndef 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
:::info
5. 编辑apb_watchdog_element_base_seq.sv
:::
```verilog
`ifndef APB_WATCHDOG_ELEMENT_BASE_SEQ_SV
`define APB_WATCHDOG_ELEMENT_BASE_SEQ_SV
class 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);
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_ELEMENT_BASE_SEQ_SV
:::info
- 在seq_lib.svh中导入elem_seqs.svh文件;
修改makefile(原因是在seq_lib中添加了elem_seqs.svh文件,需要修改文件的路径来进行查找); :::
``verilog
ifndef 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。
![image.png](https://cdn.nlark.com/yuque/0/2022/png/22348254/1653567567274-47293c5a-b503-4e03-8886-7d0c096eac4b.png#clientId=u967f55f0-4ec5-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=61&id=ue5245e9f&margin=%5Bobject%20Object%5D&name=image.png&originHeight=114&originWidth=1925&originalType=binary&ratio=1&rotation=0&showTitle=false&size=44693&status=done&style=none&taskId=u7496675c-56ad-494b-90aa-cb2164676b6&title=&width=1026.6666666666667)
> 在需要查找的目录中添加elem_seqs文件夹
<a name="PSRc7"></a>
## 5.3.3 编辑中断序列&加载寄存器序列&清除中断序列
:::info
1. 编辑apb_watchdog_reg_enable_intr.sv并给定enable信号的设置和更新
:::
```verilog
`ifndef APB_WATCHDOG_REG_ENABLE_INTR_SV
`define APB_WATCHDOG_REG_ENABLE_INTR_SV
class 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);
endfunction
task 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)
endtask
endclass
`endif //APB_WATCHDOG_REG_ENABLE_INTR
:::info
编辑apb_watchdog_reg_loadcount.sv文件并给定load值的区间(以软约束的形式) :::
``verilog
ifndef 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
:::info
3. 编辑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_SV
class 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);
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.apb_clk);
rgm.WDOGINTCLR.INTCLR.set('h1);//擦除INT信号
rgm.WDOGINTCLR.update(status);
`uvm_info("body", "Exiting...", UVM_LOW)
endtask
endclass
`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_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_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
endclass
`endif //APB_WATCHDOG_BASE_VIRT_SEQ
5.3.5 编辑apb_watchdog_countdown_virt_seq中的body部分
:::info
- 更改原来对寄存器模型中寄存器域的值配置的方式;
在body()部分中改用宏来发送序列 :::
``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);
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>
# 【验证结构框图】
![](https://cdn.nlark.com/yuque/0/2022/jpeg/22348254/1653661296044-181995cd-f038-4dc5-9ea7-6669a08b1173.jpeg)
<a name="LDkKh"></a>
## 【调试及结果】
![image.png](https://cdn.nlark.com/yuque/0/2022/png/22348254/1653658062605-1a259e2f-7ad9-451b-b966-3983dcaa671c.png#clientId=ubddadbd5-0db7-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=1024&id=u1fc39003&margin=%5Bobject%20Object%5D&name=image.png&originHeight=1920&originWidth=3638&originalType=binary&ratio=1&rotation=0&showTitle=false&size=462239&status=done&style=none&taskId=u9c9ad2bc-a01b-4efe-89de-c6303d4168b&title=&width=1940.2666666666667)
> 与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信号。
:::
![image.png](https://cdn.nlark.com/yuque/0/2022/png/22348254/1653727682384-9259ecb0-f752-4b5a-ad5a-acee278b6ca9.png#clientId=u1d30581c-a821-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=968&id=ubf96d791&margin=%5Bobject%20Object%5D&name=image.png&originHeight=1815&originWidth=3450&originalType=binary&ratio=1&rotation=0&showTitle=false&size=291787&status=done&style=none&taskId=ue02582df-6bd0-42b2-805a-43c041a2a6e&title=&width=1840)<br />对波形进行查看,再不进行INT信号复位的时候,Watchdog会重新load value值并向下开始计数。
---
<a name="qYWQI"></a>
# 5.5 测试对CLR值任意写入的功能
![image.png](https://cdn.nlark.com/yuque/0/2022/png/22348254/1653732452411-d43815c7-3bc4-4e5c-a91f-a685056ccb34.png#clientId=uc0931169-7bcb-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=140&id=uaf7b41d2&margin=%5Bobject%20Object%5D&name=image.png&originHeight=262&originWidth=2037&originalType=binary&ratio=1&rotation=0&showTitle=false&size=46863&status=done&style=none&taskId=u88487a71-3cb7-4bb3-ade2-5ce88b93bfe&title=&width=1086.4)
> 【思考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_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)
// 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)
endtask
endclass
`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_SV
class 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.INTCLR.set('h1);
rgm.WDOGINTCLR.update(status);
`uvm_info("body", "Exiting...", UVM_LOW)
endtask
endclass
`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_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)
// 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
repeat(2) `uvm_do_with(reg_intr_wait_clear, {intval == 50; delay inside {30, 40};})
wait_int_released();
#10us;
`uvm_info("body", "EXited...", UVM_LOW)
endtask
endclass
`endif //APB_WATCHDOG_COUNTDOWN_VIRT_SEQ_SV
对INT信号进行时两次擦除,并在第二次擦除以后的1us停止采样。
仿真结束后再跑1us停止结束可以在test一层中使用其他的函数来实现
`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
...
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 :::
``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; 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
![vmware_QhdVSiQewh.png](https://cdn.nlark.com/yuque/0/2022/png/22348254/1653987582223-3d142ed5-0c59-4fa5-b5a4-0411fa50f02c.png#clientId=u1d8ab3cd-68e4-4&crop=0&crop=0&crop=1&crop=1&from=drop&id=ufbcc215d&margin=%5Bobject%20Object%5D&name=vmware_QhdVSiQewh.png&originHeight=855&originWidth=3450&originalType=binary&ratio=1&rotation=0&showTitle=false&size=203968&status=done&style=none&taskId=ufc5c24b8-5a40-4eaf-a1af-04a04764c34&title=)
> 波形图如上,可以看到完成了两次完整的清除INT信号的动作
![image.png](https://cdn.nlark.com/yuque/0/2022/png/22348254/1653987409481-1d4f77d0-f0bc-4bd8-af42-da296d868ed0.png#clientId=u1d8ab3cd-68e4-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=465&id=ue9ca2679&margin=%5Bobject%20Object%5D&name=image.png&originHeight=872&originWidth=3456&originalType=binary&ratio=1&rotation=0&showTitle=false&size=258980&status=done&style=none&taskId=u3eb302ec-ca99-4862-83b4-f8c58ed3eb6&title=&width=1843.2)
<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_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)
// 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
repeat(2) begin
fork
`uvm_do_with(reg_intr_wait_clear, {intval == 50; delay inside {30, 40};})
wait_int_released();
join
end
`uvm_info("body", "EXited...", UVM_LOW)
endtask
endclass
`endif //APB_WATCHDOG_COUNTDOWN_VIRT_SEQ_SV
此时已经正常能进行两次对INT的CLR操作,且能等到CLR拉低的信号出现。
在29us的时候就已经等到了第二个INT拉低的信号,由于在test中还添加了一个drain time,所以是在30us的时候退出了测试。