【总结】

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

image.png

回顾状态机可以发现在没有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文件 :::

  1. `ifndef APB_WATCHDOG_COUNTDOWN_TEST_SV
  2. `define APB_WATCHDOG_COUNTDOWN_TEST_SV
  3. class apb_watchdog_countdown_test extends apb_watchdog_base_test;
  4. `uvm_component_utils(apb_watchdog_countdown_test)
  5. function new(string name = "apb_watchdog_countdown_test", uvm_component parent);
  6. super.new(name, parent);
  7. endfunction
  8. function void build_phase(uvm_phase phase);
  9. super.build_phase(phase);
  10. endfunction
  11. task run_phase(uvm_phase phase);
  12. apb_watchdog_countdown_virt_seq seq = apb_watchdog_countdown_virt_seq::type_id::create("this");
  13. super.run_phase(phase);
  14. phase.raise_objection(this);
  15. seq.start(env.virt_sqr);
  16. phase.drop_objection(this);
  17. endtask
  18. endclass
  19. `endif //APB_WATCHDOG_COUNTDOWN_TEST_SV

image.png

当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

  1. <a name="NsJpr"></a>
  2. ## 【调试及结果】
  3. ```shell
  4. make elab
  5. make run GUI=1 TESTNAME=apb_watchdog_countdown_test &

image.png

WDOGLOAD和WDOGVALUE的值都是ff,对寄存器的配置成功但是递减的功能没有实现。

通过查看设计文件,发现是reg_count值没有发生变化,因此可以从硬件一侧查看驱动逻辑:
image.png

双击DUT-u_apb_watchdog_frc中的reg_count,进一步展开可以看到是由count_mux2驱动的。

image.png

计数器运行的两个条件:

  1. watchdog被使能且计数器没有停止;
  2. 一个新的值被加载。

本次测试中的wdog_int_en信号为0,也就是int没有被使能,因此前面的条件不满足,只能保持为reg_count这个值,所以count_mux2的值没有变化。
image.png

计数器真正完成递减的逻辑在count_mux1中。

image.png

重新查阅文档以后发现enable值需要设置为高才能使能计数和中断功能。


5.2 测试watchdog中断拉起功能

5.2.1 更新sequence一侧代码

:::info 对apb_watchdog_countdown_virt_seq.sv重新编辑,添加enable信号后再进行调试 :::

  1. `ifndef APB_WATCHDOG_COUNTDOWN_VIRT_SEQ_SV
  2. `define APB_WATCHDOG_COUNTDOWN_VIRT_SEQ_SV
  3. class apb_watchdog_countdown_virt_seq extends apb_watchdog_base_virt_seq;
  4. `uvm_object_utils(apb_watchdog_countdown_virt_seq)
  5. function new(string name = "apb_watchdog_countdown_virt_seq");
  6. super.new(name);
  7. endfunction
  8. virtual task body();
  9. super.body();
  10. `uvm_info("body","Entered...",UVM_LOW)
  11. // Enable apb_watchdog_reg and its interrupt generation
  12. rgm.WDOGCONTROL.INTEN.set(1'b1);
  13. rgm.WDOGCONTROL.update(status);
  14. rgm.WDOGLOAD.write(status, 'hFF);
  15. repeat(10) begin
  16. rgm.WDOGLOAD.read(status, rd_val);
  17. `uvm_info("REGVALUE", $sformatf("APB WDOGLOAD IS %0x", rd_val), UVM_LOW)
  18. rgm.WDOGVALUE.read(status, rd_val);
  19. `uvm_info("REGVALUE", $sformatf("APB WDOGVALUE IS %0x", rd_val), UVM_LOW)
  20. end
  21. #20ns;
  22. `uvm_info("body", "EXited...", UVM_LOW)
  23. endtask
  24. endclass
  25. `endif //APB_WATCHDOG_COUNTDOWN_VIRT_SEQ_SV

【注】对寄存器模型中寄存器的值进行修改

  1. 可以对寄存器模型中的某一个寄存器直接使用write方法对寄存器的值进行修改;
  2. 也可以使用set对寄存器中某一个域的值进行配置;
  3. 无论采用什么方法,都需要最后做寄存器的update()。

【调试及结果】

image.png
image.png

波形如上图所示

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

image.png

同时可以在WDOG的信号线上看到INT信号线也拉高了,这个中断信号不会自己拉低,除非重新进行配置。


5.3 element sequence创建(测试拉起INT和擦除功能)

5.3.1 中断的处理

:::warning 🔔【思考】

  1. 在之前已经完成了简单的计数递减的功能并在信号线上造成了一个INT信号,那么如何等待这个中断并对其擦除呢?我们选择在element_seqs中对其做进一步处理。
  2. 可以在哪里等待这个中断?

测试用例中等待,等待中断信号以后可以擦除。 :::

5.3.2 建立等待中断的目录element_seqs

:::info

  1. 在seq_lib中添加elem_seqs;
  2. 在elem_seqs中添加:
    1. apb_watchdog_element_base_seq.sv(继承uvm_sequence)
    2. apb_watchdog_reg_intr_wait_clear.sv (清除int信号)
    3. apb_watchdog_reg_enable_intr.sv (使能信号)
    4. apb_watchdog_reg_loadcount.sv (设置计数值)
  3. 在elem_seqs中添加apb_watchdog_element_sequences.svh
  4. 在.svh文件中导入所有的sv文件 ::: ``verilogifndef 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”

`endif //APB_WATCHDOG_ELEMENT_SEQUENCES_SVH

  1. :::info
  2. 5. 编辑apb_watchdog_element_base_seq.sv
  3. :::
  4. ```verilog
  5. `ifndef APB_WATCHDOG_ELEMENT_BASE_SEQ_SV
  6. `define APB_WATCHDOG_ELEMENT_BASE_SEQ_SV
  7. class apb_watchdog_element_base_seq extends uvm_sequence;
  8. apb_watchdog_config cfg;
  9. virtual apb_watchdog_if vif;
  10. apb_watchdog_rgm rgm;
  11. bit [31:0] rd_val, wr_val;
  12. uvm_status_e status;
  13. `uvm_object_utils(apb_watchdog_element_base_seq)
  14. `uvm_declare_p_sequencer(apb_watchdog_virtual_sequencer)
  15. function new(string name = "apb_watchdog_element_base_seq");
  16. super.new(name);
  17. endfunction
  18. virtual task body();
  19. `uvm_info("body","Entered...",UVM_LOW)
  20. //Get cfg from p_sequencer
  21. cfg = p_sequencer.cfg;
  22. vif = cfg.vif;
  23. rgm = cfg.rgm;
  24. `uvm_info("body","Exiting...",UVM_LOW)
  25. endtask
  26. virtual function void compare_data(logic[31:0] val1, logic[31:0] val2);
  27. cfg.seq_check_count++;
  28. if(val1 === val2)
  29. `uvm_info("CMPSUC", $sformatf("val1 'h%0x === val2 'h%0x", val1, val2), UVM_LOW)
  30. else begin
  31. cfg.seq_check_error++;
  32. `uvm_error("CMPSUC", $sformatf("val1 'h%0x !== val2 'h%0x", val1, val2))
  33. end
  34. endfunction
  35. endclass
  36. `endif //APB_WATCHDOG_ELEMENT_BASE_SEQ_SV

:::info

  1. 在seq_lib.svh中导入elem_seqs.svh文件;
  2. 修改makefile(原因是在seq_lib中添加了elem_seqs.svh文件,需要修改文件的路径来进行查找); ::: ``verilogifndef 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”

`endif //APB_WATCHDOG_SEQ_LIB.SVH

  1. > 注意apb_watchdog_elemanet_sequences.svh必须在apb_watchdog_base_virt_seq.sv前面,因为后者是一个virtual sequence,协调了顶层的测试场景,将element_seq也包含在内,所以必须先编译element_sequence
  2. ![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)
  3. > 在需要查找的目录中添加elem_seqs文件夹
  4. <a name="PSRc7"></a>
  5. ## 5.3.3 编辑中断序列&加载寄存器序列&清除中断序列
  6. :::info
  7. 1. 编辑apb_watchdog_reg_enable_intr.sv并给定enable信号的设置和更新
  8. :::
  9. ```verilog
  10. `ifndef APB_WATCHDOG_REG_ENABLE_INTR_SV
  11. `define APB_WATCHDOG_REG_ENABLE_INTR_SV
  12. class apb_watchdog_reg_enable_intr extends apb_watchdog_element_base_seq;
  13. `uvm_object_utils(apb_watchdog_reg_enable_intr)
  14. function new(string name = "apb_watchdog_reg_enable_intr");
  15. super.new(name);
  16. endfunction
  17. task body();
  18. super.body();
  19. `uvm_info("body", "Entered...", UVM_LOW)
  20. rgm.WDOGCONTROL.INTEN.set(1'b1);
  21. rgm.WDOGCONTROL.update(status);
  22. `uvm_info("body", "Exiting...", UVM_LOW)
  23. endtask
  24. endclass
  25. `endif //APB_WATCHDOG_REG_ENABLE_INTR

:::info

  1. 编辑apb_watchdog_reg_loadcount.sv文件并给定load值的区间(以软约束的形式) ::: ``verilogifndef APB_WATCHDOG_REG_LOADCOUNT_SV `define APB_WATCHDOG_REG_LOADCOUNT_SV

    class 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

  1. :::info
  2. 3. 编辑apb_watchdog_reg_intr_wait_clear.sv(擦除intr信号)
  3. 1. 添加delay,在等到delay的若干拍以后对int信号进行擦除;
  4. 1. 添加intval这样一个信号的间隔期;
  5. 1. 等待int的办法:
  6. 1. signalint
  7. 1. interrupt status寄存器中的int
  8. :::
  9. ```verilog
  10. `ifndef APB_WATCHDOG_REG_INTR_WAIT_CLEAR_SV
  11. `define APB_WATCHDOG_REG_INTR_WAIT_CLEAR_SV
  12. class apb_watchdog_reg_intr_wait_clear extends apb_watchdog_element_base_seq;
  13. rand int delay;//注意这里是int类型
  14. rand int intval;
  15. constraint load_cstr {
  16. soft intval inside {[10:100]};
  17. soft delay inside {[1:10]};
  18. }
  19. `uvm_object_utils(apb_watchdog_reg_intr_wait_clear)
  20. function new(string name = "apb_watchdog_reg_intr_wait_clear");
  21. super.new(name);
  22. endfunction
  23. task body();
  24. super.body();
  25. `uvm_info("body", "Entered...", UVM_LOW)
  26. // Wait for apb_watchdog_reg_int triggerd
  27. forever begin
  28. rgm.WDOGMIS.mirror(status);
  29. if(rgm.WDOGMIS.INT.get()) break;
  30. repeat(intval) @(posedge vif.apb_clk);
  31. end
  32. repeat(delay) @(posedge vif.apb_clk);
  33. rgm.WDOGINTCLR.INTCLR.set('h1);//擦除INT信号
  34. rgm.WDOGINTCLR.update(status);
  35. `uvm_info("body", "Exiting...", UVM_LOW)
  36. endtask
  37. endclass
  38. `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中

  1. `ifndef APB_WATCHDOG_BASE_VIRT_SEQ_SV
  2. `define APB_WATCHDOG_BASE_VIRT_SEQ_SV
  3. class apb_watchdog_base_virt_seq extends uvm_sequence;
  4. apb_master_single_write_sequence apb_wr_seq;
  5. apb_master_single_read_sequence apb_rd_seq;
  6. apb_master_write_read_sequence apb_wr_rd_seq;
  7. apb_watchdog_reg_enable_intr reg_en_intr;
  8. apb_watchdog_reg_intr_wait_clear reg_intr_wait_clear;
  9. apb_watchdog_reg_loadcount reg_loadcount;
  10. apb_watchdog_config cfg;
  11. virtual apb_watchdog_if vif;
  12. apb_watchdog_rgm rgm;
  13. bit [31:0] rd_val, wr_val;
  14. uvm_status_e status;
  15. `uvm_object_utils(apb_watchdog_base_virt_seq)
  16. `uvm_declare_p_sequencer(apb_watchdog_virtual_sequencer)
  17. function new(string name = "apb_watchdog_base_virt_seq");
  18. super.new(name);
  19. endfunction
  20. virtual task body();
  21. `uvm_info("body","Entered...",UVM_LOW)
  22. //Get cfg from p_sequencer
  23. cfg = p_sequencer.cfg;
  24. vif = cfg.vif;
  25. rgm = cfg.rgm;
  26. `uvm_info("body","Exiting...",UVM_LOW)
  27. endtask
  28. virtual function void compare_data(logic[31:0] val1, logic[31:0] val2);
  29. cfg.seq_check_count++;
  30. if(val1 === val2)
  31. `uvm_info("CMPSUC", $sformatf("val1 'h%0x === val2 'h%0x", val1, val2), UVM_LOW)
  32. else begin
  33. cfg.seq_check_error++;
  34. `uvm_error("CMPSUC", $sformatf("val1 'h%0x !== val2 'h%0x", val1, val2))
  35. end
  36. endfunction
  37. endclass
  38. `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_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”);

    1. super.new(name);

    endfunction

    virtual task body();

    1. super.body();
    2. `uvm_info("body","Entered...",UVM_LOW)
    3. // Enable apb_watchdog_reg and its interrupt generation
    4. `uvm_do(apb_wdg_reg_en_intr)
    5. // Get load_val
    6. `uvm_do_with(apb_wdg_reg_loadcount, {load_val == 'hFF;})
    7. // Get clear signal
    8. `uvm_do_with(apb_wdg_reg_intr_wait_clear, {intval == 50; delay == 1;})
    9. //--rgm.WDOGCONTROL.INTEN.set(1'b1);
    10. //--rgm.WDOGCONTROL.update(status);
    11. //--rgm.WDOGLOAD.write(status, 'hFF);
    12. //repeat(10) begin
    13. // rgm.WDOGLOAD.read(status, rd_val);
    14. // `uvm_info("REGVALUE", $sformatf("APB WDOGLOAD IS %0x", rd_val), UVM_LOW)
    15. // rgm.WDOGVALUE.read(status, rd_val);
    16. // `uvm_info("REGVALUE", $sformatf("APB WDOGVALUE IS %0x", rd_val), UVM_LOW)
    17. //end
    18. // #20us;
    19. `uvm_info("body", "EXited...", UVM_LOW)

    endtask

    endclass

`endif //APB_WATCHDOG_COUNTDOWN_VIRT_SEQ_SV

  1. > apb_watchdog_countdown_virt_seq继承于父类apb_watchdog_element_base_seq,所以它的句柄也是挂载到了virt_sqr上,因此可以使用`uvm_do。
  2. <a name="zuiPQ"></a>
  3. # 【验证结构框图】
  4. ![](https://cdn.nlark.com/yuque/0/2022/jpeg/22348254/1653661296044-181995cd-f038-4dc5-9ea7-6669a08b1173.jpeg)
  5. <a name="LDkKh"></a>
  6. ## 【调试及结果】
  7. ![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)
  8. > 与5.2节中的实验结果相同,在12.975ns时INT信号拉高。
  9. ---
  10. <a name="LCZ2v"></a>
  11. # 5.4 中断功能关闭测试
  12. > 【思考1】
  13. > watchdog load到value以后会开始进行技术递减,当递减到0以后INT信号会拉高,重新load值并进行递减,如果对INT信号不进行擦除的话是一个什么样的过程呢?
  14. :::info
  15. 修改测试激励apb_watchdog_countdown_virt_seq.sv,不再擦除INT信号。
  16. :::
  17. ![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值并向下开始计数。
  18. ---
  19. <a name="qYWQI"></a>
  20. # 5.5 测试对CLR值任意写入的功能
  21. ![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)
  22. > 【思考2】
  23. > 功能描述文档中提到对WDOGINTCLR中写入任意一个数值都会导致watchdog重新读取数据并开始递减,随机在任意时刻写入CLR来清楚INT信号,观察计数是否是不断擦掉然后重新开始计数
  24. :::info
  25. 编辑apb_watchdog_countdown_virt_seq.sv
  26. :::
  27. ```verilog
  28. `ifndef APB_WATCHDOG_COUNTDOWN_VIRT_SEQ_SV
  29. `define APB_WATCHDOG_COUNTDOWN_VIRT_SEQ_SV
  30. class apb_watchdog_countdown_virt_seq extends apb_watchdog_base_virt_seq;
  31. `uvm_object_utils(apb_watchdog_countdown_virt_seq)
  32. function new(string name = "apb_watchdog_countdown_virt_seq");
  33. super.new(name);
  34. endfunction
  35. virtual task body();
  36. super.body();
  37. `uvm_info("body","Entered...",UVM_LOW)
  38. // Enable apb_watchdog_reg and its interrupt generation
  39. `uvm_do(reg_en_intr)
  40. // Get load_val
  41. `uvm_do_with(reg_loadcount, {load_val == 'hFF;})
  42. // Get clear signal
  43. `uvm_do_with(reg_intr_wait_clear, {intval == 50; delay inside {30, 40};})
  44. //--rgm.WDOGCONTROL.INTEN.set(1'b1);
  45. //--rgm.WDOGCONTROL.update(status);
  46. //--rgm.WDOGLOAD.write(status, 'hFF);
  47. //repeat(10) begin
  48. // rgm.WDOGLOAD.read(status, rd_val);
  49. // `uvm_info("REGVALUE", $sformatf("APB WDOGLOAD IS %0x", rd_val), UVM_LOW)
  50. // rgm.WDOGVALUE.read(status, rd_val);
  51. // `uvm_info("REGVALUE", $sformatf("APB WDOGVALUE IS %0x", rd_val), UVM_LOW)
  52. //end
  53. #20us;
  54. `uvm_info("body", "EXited...", UVM_LOW)
  55. endtask
  56. endclass
  57. `endif //APB_WATCHDOG_COUNTDOWN_VIRT_SEQ_SV

:::info 修正apb_watchdog_reg_intr_wait_clr.sv中的clk信号 :::

  1. `ifndef APB_WATCHDOG_REG_INTR_WAIT_CLEAR_SV
  2. `define APB_WATCHDOG_REG_INTR_WAIT_CLEAR_SV
  3. class apb_watchdog_reg_intr_wait_clear extends apb_watchdog_element_base_seq;
  4. rand int delay;
  5. rand int intval;
  6. constraint load_cstr {
  7. soft intval inside {[10:100]};
  8. soft delay inside {[1:10]};
  9. }
  10. `uvm_object_utils(apb_watchdog_reg_intr_wait_clear)
  11. function new(string name = "apb_watchdog_reg_intr_wait_clear");
  12. super.new(name);
  13. endfunction
  14. task body();
  15. super.body();
  16. `uvm_info("body", "Entered...", UVM_LOW)
  17. // Wait for apb_watchdog_reg_int triggerd
  18. forever begin
  19. rgm.WDOGMIS.mirror(status);
  20. if(rgm.WDOGMIS.INT.get()) break;
  21. repeat(intval) @(posedge vif.apb_clk);
  22. end
  23. repeat(delay) @(posedge vif.wdg_clk);
  24. rgm.WDOGINTCLR.INTCLR.set('h1);
  25. rgm.WDOGINTCLR.update(status);
  26. `uvm_info("body", "Exiting...", UVM_LOW)
  27. endtask
  28. endclass
  29. `endif //APB_WATCHDOG_REG_INTR_WAIT_CLEAR

擦除INT信号必须在INT信号拉高以后的若干拍进行,所以时钟必须是wdg_clk而不是apb_clk。

image.png

根据波形可以看到在INT拉高的若干拍以后被CLR重新设置为0,计数器reload并从FF重新开始向下计数。

5.6 两次CLR测试

  1. `ifndef APB_WATCHDOG_COUNTDOWN_VIRT_SEQ_SV
  2. `define APB_WATCHDOG_COUNTDOWN_VIRT_SEQ_SV
  3. class apb_watchdog_countdown_virt_seq extends apb_watchdog_base_virt_seq;
  4. `uvm_object_utils(apb_watchdog_countdown_virt_seq)
  5. function new(string name = "apb_watchdog_countdown_virt_seq");
  6. super.new(name);
  7. endfunction
  8. virtual task body();
  9. super.body();
  10. `uvm_info("body","Entered...",UVM_LOW)
  11. // Enable apb_watchdog_reg and its interrupt generation
  12. `uvm_do(reg_en_intr)
  13. // Get load_val
  14. `uvm_do_with(reg_loadcount, {load_val == 'hFF;})
  15. // Get clear signal
  16. repeat(2) `uvm_do_with(reg_intr_wait_clear, {intval == 50; delay inside {30, 40};})
  17. wait_int_released();
  18. #10us;
  19. `uvm_info("body", "EXited...", UVM_LOW)
  20. endtask
  21. endclass
  22. `endif //APB_WATCHDOG_COUNTDOWN_VIRT_SEQ_SV

对INT信号进行时两次擦除,并在第二次擦除以后的1us停止采样。

仿真结束后再跑1us停止结束可以在test一层中使用其他的函数来实现

  1. `ifndef APB_WATCHDOG_BASE_TEST_SV
  2. `define APB_WATCHDOG_BASE_TEST_SV
  3. virtual class apb_watchdog_base_test extends uvm_test;
  4. apb_watchdog_config cfg;
  5. apb_watchdog_env env;
  6. apb_watchdog_rgm rgm;
  7. function new(string name = "apb_watchdog_base_test", uvm_component parent);
  8. super.new(name, parent);
  9. endfunction
  10. ...
  11. task run_phase(uvm_phase phase);
  12. super.run_phase(phase);
  13. phase.phase_done.set_drain_time(this, 1us);
  14. phase.raise_objection(this);
  15. do_init_clks();
  16. do_init_regs();
  17. phase.drop_objection(this);
  18. endtask
  19. ...
  20. endclass
  21. `endif //APB_WATCHDOG_BASE_TEST

在test层的run_phase中可以使用set_drain_time来实现添加仿真结束后延迟的作用。

【调试及结果】

image.png

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

image.png
在apb_watchdog_countdown_virt_seq中设置断点,结果在第一次,寄存器已经将CLR信号配置为1,通过update(status)更新以后寄存器中的设计值已经默认1,没有拉低再拉高的信号出现。因此必须使用write来修改寄存器的实际值。 :::danger 【思考】

  1. 对于RO和WO这种寄存器而言,必须读回来然后再写入需要的数据;
  2. 对于配置寄存器(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_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.write(status, 1'b1);uvm_info(“body”, “Exiting…”, UVM_LOW) endtask endclass

`endif //APB_WATCHDOG_REG_INTR_WAIT_CLEAR

  1. ![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=)
  2. > 波形图如上,可以看到完成了两次完整的清除INT信号的动作
  3. ![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)
  4. <a name="sQZKi"></a>
  5. ## 5.6.1 测试激励修改
  6. 在清除CLR信号以后,此时等待INT信号拉低已经来不及了,需要采用fork_joinseq进行修改:
  7. ```verilog
  8. `ifndef APB_WATCHDOG_COUNTDOWN_VIRT_SEQ_SV
  9. `define APB_WATCHDOG_COUNTDOWN_VIRT_SEQ_SV
  10. class apb_watchdog_countdown_virt_seq extends apb_watchdog_base_virt_seq;
  11. `uvm_object_utils(apb_watchdog_countdown_virt_seq)
  12. function new(string name = "apb_watchdog_countdown_virt_seq");
  13. super.new(name);
  14. endfunction
  15. virtual task body();
  16. super.body();
  17. `uvm_info("body","Entered...",UVM_LOW)
  18. // Enable apb_watchdog_reg and its interrupt generation
  19. `uvm_do(reg_en_intr)
  20. // Get load_val
  21. `uvm_do_with(reg_loadcount, {load_val == 'hFF;})
  22. // Get clear signal
  23. repeat(2) begin
  24. fork
  25. `uvm_do_with(reg_intr_wait_clear, {intval == 50; delay inside {30, 40};})
  26. wait_int_released();
  27. join
  28. end
  29. `uvm_info("body", "EXited...", UVM_LOW)
  30. endtask
  31. endclass
  32. `endif //APB_WATCHDOG_COUNTDOWN_VIRT_SEQ_SV

image.png

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

image.png

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