• 在countdown_virt_seq中做了两次对INT信号清除的动作,但是scoreboard只完成了一次计数递减的功能,所以检查的不够充分;
  • 另外,对INT信号清除以后也会开始重新计数,因此需要将这部分也考虑在scoreboard以内;

    7.1 中断清除以后的scoreboard

    7.1.1 事件触发器一侧代码

    ``verilogifndef APB_WATCHDOG_SUBSCRIBER_SV `define APB_WATCHDOG_SUBSCRIBER_SV

`uvm_analysis_imp_decl(_apb)

class apb_watchdog_subscriber extends uvm_component;

// analysis import uvm_analysis_imp_apb #(apb_transfer, apb_watchdog_subscriber) apb_trans_observed_imp;

// Declare events uvm_event wdg_regacc_fd_e; uvm_event wdg_regacc_bd_e; uvm_event wdg_reg_inten_e; uvm_event wdg_reg_resen_e; uvm_event wdg_reg_load_e; uvm_event wdg_reg_intr_assert_e; uvm_event wdg_intrclr_e;

local uvm_event_pool _ep;

apb_watchdog_config cfg; apb_watchdog_rgm rgm; virtual apb_watchdog_if vif;

bit enable;

function void build_phase(uvm_phase phase); super.build_phase(phase); apb_trans_observed_imp = new(“apb_trans_observed_imp”, this); // Get configuration from test layer if(!uvm_config_db#(apb_watchdog_config)::get(this, “”, “cfg”, cfg)) begin `uvm_fatal(“GETCFG”, “cannot get conifg object from config db”) end vif = cfg.vif; rgm = cfg.rgm; // Local event pool and events creation _ep = new (“_ep”); wdg_regacc_fd_e = _ep.get(“wdg_regacc_fd_e”); wdg_regacc_bd_e = _ep.get(“wdg_regacc_bd_e”); wdg_reg_inten_e = _ep.get(“wdg_reg_inten_e”); wdg_reg_resen_e = _ep.get(“wdg_reg_resen_e”); wdg_reg_load_e = _ep.get(“wdg_reg_load_e”); wdg_reg_intr_assert_e = _ep.get(“wdg_reg_intr_assert_e”); wdg_intrclr_e = _ep.get(“wdg_intrclr_e”); endfunction

virtual task do_events_trigger(); uvm_object tmp; uvm_reg r; fork forever begin fork wdg_regacc_fd_e.wait_trigger_data(tmp); wdg_regacc_bd_e.wait_trigger_data(tmp); join_any disable fork; void’($cast(r, tmp));

  1. #1ps;
  2. if(r.get_name() == "WDOGCONTROL") begin
  3. if(rgm.WDOGCONTROL.INTEN.get() == 1'b1) wdg_reg_inten_e.trigger();
  4. if(rgm.WDOGCONTROL.RESEN.get() == 1'b1) wdg_reg_resen_e.trigger();
  5. end
  6. else if(r.get_name() == "WDOGLOAD") begin
  7. if(rgm.WDOGLOAD.LOADVAL.get() != 0) wdg_reg_load_e.trigger();
  8. end
  9. else if(r.get_name() == "WDOGINTCLR") begin
  10. if(rgm.WDOGINTCLR.INTCLR.get() == 1) wdg_intrclr_e.trigger();
  11. end
  12. end
  13. join_none

endtask

endclass

`endif // APB_WATCHDOG_subscriber_SV

  1. > 在擦除拉高的INT信号会重新开始计数,所以需要添加擦除INT这个事件
  2. <a name="BFoMH"></a>
  3. ## 7.1.2 scoreboard一侧代码
  4. ```verilog
  5. `ifndef APB_WATCHDOG_SCOREBOARD_SV
  6. `define APB_WATCHDOG_SCOREBOARD_SV
  7. class apb_watchdog_scoreboard extends apb_watchdog_subscriber;
  8. bit do_loadcounter_check_enable = 0;
  9. bit [31:0] cur_load;
  10. bit [31:0] cur_count;
  11. `uvm_component_utils(apb_watchdog_scoreboard)
  12. function new (string name = "apb_watchdog_scoreboard", uvm_component parent);
  13. super.new(name, parent);
  14. endfunction
  15. function void build_phase(uvm_phase phase);
  16. super.build_phase(phase);
  17. enable = cfg.scb_enable;
  18. endfunction
  19. task run_phase(uvm_phase phase);
  20. super.run_phase(phase);
  21. do_countdown_check();
  22. endtask
  23. virtual task do_countdown_check();
  24. fork
  25. forever begin : wait_wdogen_tread
  26. fork
  27. wdg_reg_inten_e.wait_trigger();
  28. wdg_reg_load_e.wait_trigger();
  29. join
  30. disable do_loadcounter_check_thread;
  31. do_loadcounter_check_enable = 1'b1;
  32. end
  33. forever begin : wait_intr_clr_tread
  34. wdg_intrclr_e.wait_trigger();
  35. disable do_loadcounter_check_thread;
  36. do_loadcounter_check_enable = 1'b1;
  37. end
  38. forever begin : do_loadcounter_check_thread
  39. do_loadcounter_check();
  40. end
  41. join_none
  42. endtask
  43. virtual task do_loadcounter_check();
  44. forever begin
  45. @(posedge vif.wdg_clk iff do_loadcounter_check_enable);
  46. cur_load = rgm.WDOGLOAD.LOADVAL.get();
  47. cur_count = cur_load;
  48. do begin
  49. @(posedge vif.wdg_clk);
  50. cur_count--;
  51. end while(cur_count != 0);
  52. wdg_reg_intr_assert_e.trigger();
  53. repeat(2) @(negedge vif.wdg_clk);
  54. // From logic timing after count reach zero
  55. if(vif.wdog_int != 1'b1) begin
  56. cfg.scb_check_error++;
  57. `uvm_error("COUNTDOWN_CHECK", "Wdog interrupt signal should be asserted!")
  58. end
  59. cfg.scb_check_count++;
  60. end
  61. endtask
  62. endclass
  63. `endif // APB_WATCHDOG_SCOREBOARD_SV

do_count_down_check()中的线程之间都是并行的

【调试及结果】

image.png

第一次是INT信号还没有拉高的时候,这时候完成了一次do_loadcounter_check_thread; 随后INT拉高,事件触发,终止了上一个loadcounter_check_thread并开始新的递减计数线程; 第二个计数线程还未结束就被CLR信号拉高清除掉,触发该事件后终止第二个计数线程开始第三个计数线程。 所以最终完成了两次计数功能。

image.png


7.2 reload数据以后的scoreboard

:::danger 【思考】
之前考虑了INT信号拉高再清除以后的countdown_test;

  • 还需要考虑在INT信号拉高并清除以后重新加载新的值;
  • 另外还需要考虑在一些测试环境下需要将countdown关闭的问题,(通过在config中配置来实现) ::: :::info
  1. 添加apb_watchdog_reload_virt_seq.sv和对应的test文件 ::: ``verilogifndef APB_WATCHDOG_RELOAD_VIRT_SEQ_SV `define APB_WATCHDOG_RELOAD_VIRT_SEQ_SV

    class apb_watchdog_reload_virt_seq extends apb_watchdog_base_virt_seq;

    `uvm_object_utils(apb_watchdog_reload_virt_seq)

    function new(string name = “apb_watchdog_reload_virt_seq”); super.new(name); endfunction

    virtual task body(); super.body(); `uvm_info(“body”,”Entered…”,UVM_LOW)

    1. // Enable apb_watchdog_reg and its interrupt generation
    2. `uvm_do(reg_en_intr)
    3. // Get load_val
    4. `uvm_do_with(reg_loadcount, {load_val == 'hFF;})
    5. // Get clear signal
    6. repeat(2) begin
    7. fork
    8. `uvm_do_with(reg_intr_wait_clear, {intval == 50; delay inside {[30:40]};})
    9. wait_int_released();
    10. join
    11. end

    `uvm_do_with(reg_loadcount, {load_val inside {[‘hA0:’hFF]};})

    1. `uvm_info("body", "EXited...", UVM_LOW)

    endtask

    endclass

`endif //APB_WATCHDOG_RELOAD_VIRT_SEQ_SV

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

:::info

  1. 修改scoreboard ::: ``verilogifndef APB_WATCHDOG_SCOREBOARD_SV `define APB_WATCHDOG_SCOREBOARD_SV

class apb_watchdog_scoreboard extends apb_watchdog_subscriber;

bit do_loadcounter_check_enable = 0; bit [31:0] cur_load; bit [31:0] cur_count; bit wdg_inten = 0; typedef enum {CHECK_COUNTEREN} type_def_e;

`uvm_component_utils(apb_watchdog_scoreboard)

function new (string name = “apb_watchdog_scoreboard”, uvm_component parent); super.new(name, parent); endfunction

function void build_phase(uvm_phase phase); super.build_phase(phase); enable = cfg.scb_enable; endfunction

task run_phase(uvm_phase phase); super.run_phase(phase); do_listen_events(); do_countdown_check(); endtask

virtual task do_listen_events(); fork forever begin : wait_wdogen_tread fork wdg_reg_inten_e.wait_trigger(); wdg_inten = 1; join end forever begin : wait_reload_tread fork wdg_reg_load_e.wait_trigger();
join disable do_loadcounter_check_thread; do_loadcounter_check_enable = 1’b1; end forever begin : wait_intr_clr_tread wdg_intrclr_e.wait_trigger();
disable do_loadcounter_check_thread; do_loadcounter_check_enable = 1’b1; end join_none endtask

virtual task do_countdown_check(); fork forever begin : do_loadcounter_check_thread do_loadcounter_check(); end join_none endtask

virtual task do_loadcounter_check(); forever begin @(posedge vif.wdg_clk iff do_loadcounter_en(CHECK_COUNTEREN)); cur_load = rgm.WDOGLOAD.LOADVAL.get(); cur_count = cur_load; do begin @(posedge vif.wdg_clk); cur_count—; end while(cur_count != 0); wdg_reg_intr_assert_e.trigger(); repeat(2) @(negedge vif.wdg_clk); // From logic timing after count reach zero if(vif.wdog_int != 1’b1) begin cfg.scb_check_error++; `uvm_error(“COUNTDOWN_CHECK”, “Wdog interrupt signal should be asserted!”) end cfg.scb_check_count++; end endtask

virtual function bit do_loadcounter_en(type_def_e tyd); case(tyd) CHECK_COUNTEREN: return cfg.do_counter_check_en && wdog_int_en; default: return 0; endcase endfunction endclass

`endif // APB_WATCHDOG_SCOREBOARD_SV

  1. <a name="cIAaH"></a>
  2. ## 【调试及结果】
  3. ![image.png](https://cdn.nlark.com/yuque/0/2022/png/22348254/1654251957132-f5622bde-b60a-4f20-bee4-898309f7ade2.png#clientId=uf0e127d2-5801-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=319&id=u0868a061&margin=%5Bobject%20Object%5D&name=image.png&originHeight=598&originWidth=1098&originalType=binary&ratio=1&rotation=0&showTitle=false&size=104396&status=done&style=none&taskId=u6213c6b7-5b70-4d3a-9b2d-a4cf777803a&title=&width=585.6)
  4. > 在编译的时候提示没有办法找到do_loadcounter_check_thread从而进行关闭,原因是不在一个域中没有办法进行查找,我们不能将他们放在一起的原因是那样违背了解耦合的思想。在其他的一些测试中可能要listen其他的事件,所以不能放在一起。
  5. :::info
  6. 3. 不能将两个域放在一起,那么线程之间的通信方式就是event,因此在scoreboard中添加事件对关闭线程的功能进行改造
  7. :::
  8. ```verilog
  9. `ifndef APB_WATCHDOG_SCOREBOARD_SV
  10. `define APB_WATCHDOG_SCOREBOARD_SV
  11. class apb_watchdog_scoreboard extends apb_watchdog_subscriber;
  12. bit wdg_inten = 0;
  13. bit [31:0] cur_load;
  14. bit [31:0] cur_count;
  15. typedef enum {CHECK_COUNTEREN} check_type_e;
  16. uvm_event disable_loadcounter_check;
  17. `uvm_component_utils(apb_watchdog_scoreboard)
  18. function new (string name = "apb_watchdog_scoreboard", uvm_component parent);
  19. super.new(name, parent);
  20. endfunction
  21. function void build_phase(uvm_phase phase);
  22. super.build_phase(phase);
  23. enable = cfg.scb_enable;
  24. disable_loadcounter_check = _ep.get("disable_loadcounter_check");
  25. endfunction
  26. task run_phase(uvm_phase phase);
  27. super.run_phase(phase);
  28. do_listen_events();
  29. do_countdown_check();
  30. endtask
  31. virtual task do_listen_events();
  32. fork
  33. forever begin : wait_wdogen_tread
  34. wdg_reg_inten_e.wait_trigger();
  35. wdg_inten = 1;
  36. end
  37. forever begin : wait_wdog_load_tread
  38. wdg_reg_load_e.wait_trigger();
  39. disable_loadcounter_check.trigger();
  40. cfg.do_counter_check_en = 1;
  41. end
  42. forever begin : wait_intr_clr_tread
  43. wdg_intrclr_e.wait_trigger();
  44. disable_loadcounter_check.trigger();
  45. cfg.do_counter_check_en = 1;
  46. end
  47. join_none
  48. endtask
  49. virtual task do_countdown_check();
  50. fork
  51. forever begin
  52. disable_loadcounter_check.wait_trigger();
  53. disable do_loadcounter_check_thread;
  54. end
  55. forever begin
  56. begin : do_loadcounter_check_thread
  57. do_loadcounter_check();
  58. end
  59. end
  60. join_none
  61. endtask
  62. virtual task do_loadcounter_check();
  63. bit loadcounter_enable = do_loadcounter_en(CHECK_COUNTEREN);
  64. forever begin
  65. @(posedge vif.wdg_clk iff loadcounter_enable);
  66. cur_load = rgm.WDOGLOAD.LOADVAL.get();
  67. cur_count = cur_load;
  68. do begin
  69. @(posedge vif.wdg_clk);
  70. cur_count--;
  71. end while(cur_count != 0);
  72. wdg_reg_intr_assert_e.trigger();
  73. repeat(2) @(negedge vif.wdg_clk);
  74. // From logic timing after count reach zero
  75. if(vif.wdog_int != 1'b1) begin
  76. cfg.scb_check_error++;
  77. `uvm_error("COUNTDOWN_CHECK", "Wdog interrupt signal should be asserted!")
  78. end
  79. cfg.scb_check_count++;
  80. end
  81. endtask
  82. virtual function bit do_loadcounter_en(check_type_e typ);
  83. case(typ)
  84. CHECK_COUNTEREN: return cfg.do_counter_check_en && wdg_inten;
  85. default: return 0;
  86. endcase
  87. endfunction
  88. endclass
  89. `endif // APB_WATCHDOG_SCOREBOARD_SV

image.png

在14500的时候做了第一次的load,也就是FF,这是一次完整的计数; 第一次擦除,擦除以后又触发了计数事件;但此时做了第二次load的动作,F2;进行了第二次完整的计数; 第二次擦除,擦除以后又做了reload。

image.png
所以最后一共进行了两次完整的计数比较功能。