- 在countdown_virt_seq中做了两次对INT信号清除的动作,但是scoreboard只完成了一次计数递减的功能,所以检查的不够充分;
- 另外,对INT信号清除以后也会开始重新计数,因此需要将这部分也考虑在scoreboard以内;
7.1 中断清除以后的scoreboard
7.1.1 事件触发器一侧代码
``verilog
ifndef 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));
#1ps;
if(r.get_name() == "WDOGCONTROL") begin
if(rgm.WDOGCONTROL.INTEN.get() == 1'b1) wdg_reg_inten_e.trigger();
if(rgm.WDOGCONTROL.RESEN.get() == 1'b1) wdg_reg_resen_e.trigger();
end
else if(r.get_name() == "WDOGLOAD") begin
if(rgm.WDOGLOAD.LOADVAL.get() != 0) wdg_reg_load_e.trigger();
end
else if(r.get_name() == "WDOGINTCLR") begin
if(rgm.WDOGINTCLR.INTCLR.get() == 1) wdg_intrclr_e.trigger();
end
end
join_none
endtask
endclass
`endif // APB_WATCHDOG_subscriber_SV
> 在擦除拉高的INT信号会重新开始计数,所以需要添加擦除INT这个事件
<a name="BFoMH"></a>
## 7.1.2 scoreboard一侧代码
```verilog
`ifndef 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;
`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_countdown_check();
endtask
virtual task do_countdown_check();
fork
forever begin : wait_wdogen_tread
fork
wdg_reg_inten_e.wait_trigger();
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
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_check_enable);
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
endclass
`endif // APB_WATCHDOG_SCOREBOARD_SV
do_count_down_check()中的线程之间都是并行的
【调试及结果】
第一次是INT信号还没有拉高的时候,这时候完成了一次do_loadcounter_check_thread; 随后INT拉高,事件触发,终止了上一个loadcounter_check_thread并开始新的递减计数线程; 第二个计数线程还未结束就被CLR信号拉高清除掉,触发该事件后终止第二个计数线程开始第三个计数线程。 所以最终完成了两次计数功能。
7.2 reload数据以后的scoreboard
:::danger
【思考】
之前考虑了INT信号拉高再清除以后的countdown_test;
- 还需要考虑在INT信号拉高并清除以后重新加载新的值;
- 另外还需要考虑在一些测试环境下需要将countdown关闭的问题,(通过在config中配置来实现) ::: :::info
添加apb_watchdog_reload_virt_seq.sv和对应的test文件 :::
``verilog
ifndef APB_WATCHDOG_RELOAD_VIRT_SEQ_SV `define APB_WATCHDOG_RELOAD_VIRT_SEQ_SVclass 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)
// 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_do_with(reg_loadcount, {load_val inside {[‘hA0:’hFF]};})
`uvm_info("body", "EXited...", UVM_LOW)
endtask
endclass
`endif //APB_WATCHDOG_RELOAD_VIRT_SEQ_SV
```verilog
`ifndef APB_WATCHDOG_RELOAD_TEST_SV
`define APB_WATCHDOG_RELOAD_TEST_SV
class apb_watchdog_reload_test extends apb_watchdog_base_test;
`uvm_component_utils(apb_watchdog_reload_test)
function new(string name = "apb_watchdog_reload_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_reload_virt_seq seq = apb_watchdog_reload_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_RELOAD_TEST_SV
:::info
- 修改scoreboard
:::
``verilog
ifndef 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
<a name="cIAaH"></a>
## 【调试及结果】
![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)
> 在编译的时候提示没有办法找到do_loadcounter_check_thread从而进行关闭,原因是不在一个域中没有办法进行查找,我们不能将他们放在一起的原因是那样违背了解耦合的思想。在其他的一些测试中可能要listen其他的事件,所以不能放在一起。
:::info
3. 不能将两个域放在一起,那么线程之间的通信方式就是event,因此在scoreboard中添加事件对关闭线程的功能进行改造
:::
```verilog
`ifndef APB_WATCHDOG_SCOREBOARD_SV
`define APB_WATCHDOG_SCOREBOARD_SV
class apb_watchdog_scoreboard extends apb_watchdog_subscriber;
bit wdg_inten = 0;
bit [31:0] cur_load;
bit [31:0] cur_count;
typedef enum {CHECK_COUNTEREN} check_type_e;
uvm_event disable_loadcounter_check;
`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;
disable_loadcounter_check = _ep.get("disable_loadcounter_check");
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
wdg_reg_inten_e.wait_trigger();
wdg_inten = 1;
end
forever begin : wait_wdog_load_tread
wdg_reg_load_e.wait_trigger();
disable_loadcounter_check.trigger();
cfg.do_counter_check_en = 1;
end
forever begin : wait_intr_clr_tread
wdg_intrclr_e.wait_trigger();
disable_loadcounter_check.trigger();
cfg.do_counter_check_en = 1;
end
join_none
endtask
virtual task do_countdown_check();
fork
forever begin
disable_loadcounter_check.wait_trigger();
disable do_loadcounter_check_thread;
end
forever begin
begin : do_loadcounter_check_thread
do_loadcounter_check();
end
end
join_none
endtask
virtual task do_loadcounter_check();
bit loadcounter_enable = do_loadcounter_en(CHECK_COUNTEREN);
forever begin
@(posedge vif.wdg_clk iff loadcounter_enable);
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(check_type_e typ);
case(typ)
CHECK_COUNTEREN: return cfg.do_counter_check_en && wdg_inten;
default: return 0;
endcase
endfunction
endclass
`endif // APB_WATCHDOG_SCOREBOARD_SV
在14500的时候做了第一次的load,也就是FF,这是一次完整的计数; 第一次擦除,擦除以后又触发了计数事件;但此时做了第二次load的动作,F2;进行了第二次完整的计数; 第二次擦除,擦除以后又做了reload。
所以最后一共进行了两次完整的计数比较功能。