【总结】

  1. 使用config机制来完成对接口和全局变量的配置,提高环境复用性;
  2. 采用APB_VIP中的序列来完成对寄存器的测试;

3.1 config在环境中的搭建和传递

3.1.1 编辑config文件

:::info (1)在watchdog的层次中引入config机制,自顶向下的完成对验证环境的配置并方便底层组件对全局变量的调用。 :::

  1. `ifndef APB_WATCHDOG_CONFIG_SV
  2. `define APB_WATCHDOG_CONFIG_SV
  3. class apb_watchdog_config extends uvm_object;
  4. `uvm_object_utils(apb_watchdog_config)
  5. apb_config apb_cfg;
  6. // USER to specify the config items
  7. uvm_active_passive_enum is_active = UVM_ACTIVE;
  8. function new (string name = "apb_watchdog_config");
  9. super.new(name);
  10. apb_cfg = apb_config::type_id::create("apb_cfg");
  11. endfunction : new
  12. endclass
  13. `endif // APB_WATCHDOG_CONFIG_SV

3.1.2 Base_Test_layer

:::info (2)在test中声明并例化config,然后通过config_db参数类传递到底层,再通过vif或者其他接口向下传递。 :::

  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_env env;
  5. apb_watchdog_config cfg;//对config进行声明
  6. function new(string name = "apb_watchdog_base_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. cfg = apb_watchdog_config::type_id::create("cfg");//对config进行例化
  12. uvm_config_db#(apb_watchdog_config)::set(this,"env","cfg",cfg);
  13. env = apb_watchdog_env::type_id::create("env", this);
  14. endfunction
  15. task run_phase(uvm_phase phase);
  16. super.run_phase(phase);
  17. phase.raise_objection(this);
  18. do_init_clks();
  19. do_init_regs();
  20. phase.drop_objection(this);
  21. endtask
  22. `ifndef APB_WATCHDOG_BASE_TEST_SV
  23. `define APB_WATCHDOG_BASE_TEST_SV
  24. `endif //APB_WATCHDOG_BASE_TEST

3.1.3 Env_layer

:::info (3)使用if语句嵌套uvm_config_db来获取config;
将config向下传递; :::

  1. `ifndef APB_WATCHDOG_ENV_SV
  2. `define APB_WATCHDOG_ENV_SV
  3. class apb_watchdog_env extends uvm_env;
  4. apb_watchdog_config cfg;
  5. apb_master_agent apb_mst;
  6. apb_watchdog_virtual_sequencer virt_sqr;
  7. `uvm_component_utils(apb_watchdog_env)
  8. function new (string name = "apb_watchdog_env", uvm_component parent);
  9. super.new(name,parent);
  10. endfunction
  11. function void build_phase(uvm_phase phase);
  12. super.build_phase(phase);
  13. //Get configuration from test layer
  14. if(!uvm_config_db#(apb_watchdog_config)::get(this, "", "cfg",cfg)) begin
  15. `uvm_fatal("GETCFG", "cannnot get config object from test layer")
  16. end
  17. uvm_config_db#(apb_watchdog_config)::set(this, "virt_sqr", "cfg", cfg);
  18. uvm_config_db#(apb_config)::set(this, "apb_mst", "cfg",cfg.apb_cfg);
  19. apb_mst = apb_master_agent::type_id::create("apb_mst", this);
  20. virt_sqr = apb_watchdog_virtual_sequencer::type_id::create("virt_sqr", this);
  21. endfunction
  22. function void connect_phase(uvm_phase phase);
  23. virt_sqr.apb_mst_sqr = apb_mst.sequencer;
  24. endfunction
  25. endclass
  26. `endif

【注】

  • 由于之前在test一层中已经例化了apb_watchdog_config,因此env环境中只需要将这个config向下传递即可,那么就只需要声明句柄不需要创建对象来开辟空间,因此在build_phase中也没有create。但是apb_master_agent和virtual_sequencer都是初次在环境中声明的,因此也必须使用create进行创建。
  • 在env中将apb_cfg向底层set的时候,apb_watchdog_config中已经包含了apb_cfg。所以使用的是cfg.apb_cfg。

【调试及结果】

  1. make elab; make run GUI=1 &
  2. 在DVE命令中输入run 0来观察环境是否搭建好(build_phase是否顺利结束)
    1. 在uvm debug中可以看到phase卡到了build_phase的阶段;
    2. 同时在窗口中打印出env没办法拿到来自test的config。

image.png
c. 结果发现是env中拿取config的路径和test中set下来的路径不一样,更改路径以后,phase可以移动到了run_phase :::danger 【Tips】

  1. 如何查看config有无进行正常的传递呢?
    1. 设置断点;
    2. 在uvm_debug_resource中查看:
  • 在name中输入与config相关的名称cfg

X7oceAsLQB.png :::

可以看到cfg是在test的一层中set进来的,set进来的value就apb_watchdog_config;同时在下面也有env进行承接,在这里进行get。

同样的,可以类比apb_config有无进行有效地传递。

  • 但是apb_watchdog_config并没有传递到virt_sqr中,原因是它只有set但是virt_sqr并没有get。

一般来说set但不get是可以的,但get不set是不行的,因为get不到是会有返回值的,所以可以使用if条件语句来进行判断是否get到,如果没有get到就会返回0报fatal。

  • 或者可以点击set calls without get也可以过滤出来需要的信息。

    3.2 APB寄存器的直接访问

    APB寄存器的直接访问就是调用APB_VIP中的序列,将他们在对应的seq中挂载到env中与apb_mst_sqr连接的virt_sqr上来完成测试激励的发送

3.2.1 Test_layer

:::info (1)在Test_layer一层中将对应的seq挂载到env中的virt_sqr上 :::

  1. `ifndef APB_WATCHDOG_APBACC_TEST_SV
  2. `define APB_WATCHDOG_APBACC_TEST_SV
  3. class apb_watchdog_apbacc_test extends apb_watchdog_base_test;
  4. `uvm_component_utils(apb_watchdog_apbacc_test)
  5. function new(string name = "apb_watchdog_apbacc_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_apbacc_virt_seq seq = apb_watchdog_apbacc_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_APBACC_TEST_SV

【注】

  • apb_watchdog_base_test是一个虚类,不能做注册,但是apb_watchdog_apbacc_test是一个子类,必须注册以后才能继续使用;
  • 如果没有注册的话会导致在仿真的时候runtestname中找不到这个测试,run_test相当于uvm的后台从已经编译到工厂中的类中去寻找,如果没有注册是找不到的。

3.2.3 测试序列_layer

:::info (2) :::

  • 在搭好上述框架以后就可以开始写测试用例了,由于现在的接口只有apb,所以可以采用UVM项目实战中发送一些transfer;
  • 如果要写一些sequence,那么最好就是写到base_virtual_sequence中,因为其他的一些sequence可能需要复用这些sequence。 ``verilogifndef 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;

    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”);

    1. super.new(name);

    endfunction

    virtual task body();

    `uvm_info(“body”,”Entered…”,UVM_LOW)

    1. //Todo in sub_class

    `uvm_info(“body”,”Exiting…”,UVM_LOW) endtask

    endclass

`endif //APB_WATCHDOG_BASE_VIRT_SEQ

  1. ```verilog
  2. `ifndef APB_WATCHDOG_APBACC_VIRT_SEQ_SV
  3. `define APB_WATCHDOG_APBACC_VIRT_SEQ_SV
  4. class apb_watchdog_apbacc_virt_seq extends apb_watchdog_base_virt_seq;
  5. `uvm_object_utils(apb_watchdog_apbacc_virt_seq)
  6. function new(string name = "apb_watchdog_apbacc_virt_seq");
  7. super.new(name);
  8. endfunction
  9. virtual task body();
  10. `uvm_info("body","Entered...",UVM_LOW)
  11. // Todo in sub_class
  12. // Inline constraint with apb address, data
  13. `uvm_do_on_with(apb_rd_seq, p_sequencer.apb_mst_sqr, {addr == 'hFE0;})
  14. `uvm_do_on_with(apb_rd_seq, p_sequencer.apb_mst_sqr, {addr == 'hFE4;})
  15. `uvm_do_on_with(apb_rd_seq, p_sequencer.apb_mst_sqr, {addr == 'hFE8;})
  16. `uvm_do_on_with(apb_rd_seq, p_sequencer.apb_mst_sqr, {addr == 'hFEc;})
  17. `uvm_info("body","Exiting...",UVM_LOW)
  18. endtask
  19. endclass
  20. `endif //APB_WATCHDOG_APBACC_VIRT_SEQ_SV

【注】

  • test一层中将virtual_seq通过seq.start挂载到virtual_sequencer上的;
  • sequence一层中使用`uvm_do_on_with完成了对于seq的创建,挂载和随机化的过程,将seq挂载到了p_sequencer上,这里的p_sequencer指的就是env中的apb_watchdog_virtual_sequencer;
  • 给的约束就是addr,查阅arm提供的apb_watchdog手册中的ID:

image.png

3.3 验证结构图

到此为止,验证结构图的绘制如下(可放大查看):
3.1 APB寄存器直接访问 - 图4

【调试】

  1. 编译

    1. make elab
    2. make run GUI=1 TESTNAME=apb_watchdog_apbacc_test

    test发生了变化,所以在run_test的时候也需要对test的名称做出变化

  2. DVE中输入run 0先建立整个环境

image.png
此时信息提示停留在了app_watchdog_apbacc_virt_seq上,双击进去以后可以设置断点

  1. 在apb_watchdog_apbacc_virt_seq上设置断点

image.png
image.png

根据波形来看,有以下几个bug:

  1. PRESET的和PCLK不同步;
  2. 对于APB总线的读访问应该发生在reset复位以后,而不是reset拉高的时候。

首先解决第1个bug:

  1. 在对寄存器进行初始配置之前可以先等reset信号复位完成,所以在tb中对do_init_regs()编写,这个rstn复位信号是从接口中拿来的;
  2. 在config中定义这样的一个vif; ```verilog

ifndef APB_WATCHDOG_CONFIG_SVdefine APB_WATCHDOG_CONFIG_SV

class apb_watchdog_config extends uvm_object;

apb_config apb_cfg; virtual apb_watchdog_if vif;

`uvm_object_utils(apb_watchdog_config)

// USER to specify the config items

function new (string name = “apb_watchdog_config”); super.new(name); apb_cfg = apb_config::type_id::create(“apb_cfg”); endfunction : new

endclass `endif // apb_watchdog_CONFIG_SV

  1. > config中声明好vif,在tb一层中直接传递给底层的vif中。
  2. 3. **_base_test中通过config_dbget vif_**
  3. ```verilog
  4. `ifndef APB_WATCHDOG_BASE_TEST_SV
  5. `define APB_WATCHDOG_BASE_TEST_SV
  6. virtual class apb_watchdog_base_test extends uvm_test;
  7. apb_watchdog_config cfg;
  8. apb_watchdog_env env;
  9. function new(string name = "apb_watchdog_base_test", uvm_component parent);
  10. super.new(name, parent);
  11. endfunction
  12. function void build_phase(uvm_phase phase);
  13. super.build_phase(phase);
  14. cfg = apb_watchdog_config::type_id::create("cfg");
  15. if(!uvm_config_db#(virtual apb_watchdog_if)::get(this,"","vif", cfg.vif)) begin
  16. `uvm_fatal("GETCFG","cannot get virtual interface from config DB")
  17. end
  18. uvm_config_db#(apb_watchdog_config)::set(this, "env", "cfg", cfg);
  19. env = apb_watchdog_env::type_id::create("env", this);
  20. endfunction
  21. task run_phase(uvm_phase phase);
  22. super.run_phase(phase);
  23. phase.raise_objection(this);
  24. do_init_clks();
  25. do_init_regs();
  26. phase.drop_objection(this);
  27. endtask
  28. virtual task do_init_clks();
  29. endtask
  30. virtual task do_init_regs();
  31. // wait reset release
  32. //@(posedge cfg.vif.)
  33. endtask
  34. endclass
  35. `endif //APB_WATCHDOG_BASE_TEST

获取cfg中的vif并传递到test一层的vif中,需要注意顺序,先创建cfg以后才能拿到vif。

  1. 在apb_watchdog_if中声明reset信号,这个信号来自于tb ```verilog

interface apb_watchdog_if;

logic [3:0] ecorevnum = 4’b1011; logic wdog_int; logic wdog_res;

logic apb_clk; logic apb_rstn; logic wdg_clk; logic wdg_rstn;

endinterface

  1. 5. **_tb中将信号传递给接口并将接口通过config_db传递给底层(testvirtual sequencerenvapb_master_agent_**
  2. ```verilog
  3. module apb_watchdog_tb;
  4. import uvm_pkg::*;
  5. `include "uvm_macros.svh"
  6. import apb_watchdog_pkg::*;
  7. bit apb_clk;
  8. bit apb_rstn;
  9. bit wdg_clk;
  10. bit wdg_rstn;
  11. cmsdk_apb_watchdog dut(
  12. .PCLK(apb_clk), // APB clock
  13. .PRESETn(apb_rstn), // APB reset
  14. .PENABLE(apb_if_inst.penable), // APB enable
  15. .PSEL(apb_if_inst.psel), // APB periph select
  16. .PADDR(apb_if_inst.paddr[11:2]), // APB address bus
  17. .PWRITE(apb_if_inst.pwrite), // APB write
  18. .PWDATA(apb_if_inst.pwdata), // APB write data
  19. .WDOGCLK(wdg_clk), // Watchdog clock
  20. .WDOGCLKEN(1'b1), // Watchdog clock enable
  21. .WDOGRESn(wdg_rstn), // Watchdog clock reset
  22. .ECOREVNUM(apb_wdg_if_inst.ecorevnum), // ECO revision number
  23. .PRDATA(apb_if_inst.prdata), // APB read data
  24. .WDOGINT(apb_wdg_if_inst.wdog_int), // Watchdog interrupt
  25. .WDOGRES(apb_wdg_if_inst.wdog_res) // Watchdog timeout reset
  26. );
  27. apb_if apb_if_inst(apb_clk, apb_rstn);
  28. apb_watchdog_if apb_wdg_if_inst();
  29. assign apb_wdg_if_inst.apb_clk = apb_clk;
  30. assign apb_wdg_if_inst.apb_rstn = apb_rstn;
  31. assign apb_wdg_if_inst.wdg_clk = wdg_clk;
  32. assign apb_wdg_if_inst.wdg_rstn = wdg_rstn;
  33. initial begin: gen_clk
  34. fork
  35. forever #5ns apb_clk <= !apb_clk; //100MHz
  36. forever #25ns wdg_clk <= !wdg_clk; //20MHz
  37. join
  38. end
  39. initial begin: gen_rstn
  40. #2ns
  41. apb_rstn <= 1;
  42. #20ns
  43. apb_rstn <= 0;
  44. #20ns
  45. apb_rstn <= 1;
  46. end
  47. assign wdg_rstn = apb_rstn;
  48. initial begin: vif_assign
  49. uvm_config_db#(virtual apb_if)::set(uvm_root::get(), "uvm_test_top.env.apb_mst", "vif", apb_if_inst);
  50. uvm_config_db#(virtual apb_watchdog_if)::set(uvm_root::get(), "uvm_test_top", "vif", apb_wdg_if_inst);
  51. uvm_config_db#(virtual apb_watchdog_if)::set(uvm_root::get(), "uvm_test_top.env", "vif", apb_wdg_if_inst);
  52. uvm_config_db#(virtual apb_watchdog_if)::set(uvm_root::get(), "uvm_test_top.env.virt_sqr", "vif", apb_wdg_if_inst);
  53. run_test("");
  54. end
  55. endmodule

【注】 在initial begin过程块中使用config将内容传递给了下面的几个层次,但是需要注意以下这种使用通配符传递方式是不行的:

  1. initial begin: vif_assign
  2. uvm_config_db#(virtual apb_if)::set(uvm_root::get(), "uvm_test_top.env.apb_mst", "vif", apb_if_inst);
  3. uvm_config_db#(virtual apb_watchdog_if)::set(uvm_root::get(), "uvm_test_top*", "vif", apb_wdg_if_inst);
  4. run_test("");
  5. end

原因是直接传递给uvm_test_top这个层次中会将apb_master_agent中的vif覆盖掉。

  1. test中的寄存器如何等复位信号呢?
    1. 等一个下降沿再等一个上升沿;
    2. 等一个固定的时间。 ```verilog virtual task do_init_regs(); // wait reset release repeat(10) @(posedge cfg.vif.apb_clk); endtask
  1. 7. **_对总线读回来的数据进行检查(在apb_base_virtual_sequence中添加compare函数)_**
  2. ```verilog
  3. virtual function void compare_data(logic[31:0] val1 , logic[31:0] val2);
  4. if(val1 === val2)
  5. `uvm_info("COMPSUC",$sformatf("val1 'h%0x === val2 'h%0x", val1, val2), UVM_LOW)
  6. else
  7. `uvm_error("COMPSUC",$sformatf("val1 'h%0x !== val2 'h%0x", val1, val2))
  8. endfunction
  1. `uvm_do_on_with(apb_rd_seq, p_sequencer.apb_mst_sqr, {addr == 'hFE0;})
  2. compare_data(apb_rd_seq.data, 'h24);
  3. `uvm_do_on_with(apb_rd_seq, p_sequencer.apb_mst_sqr, {addr == 'hFE4;})
  4. compare_data(apb_rd_seq.data, 'hB8);
  5. `uvm_do_on_with(apb_rd_seq, p_sequencer.apb_mst_sqr, {addr == 'hFE8;})
  6. compare_data(apb_rd_seq.data, 'h1B);
  7. `uvm_do_on_with(apb_rd_seq, p_sequencer.apb_mst_sqr, {addr == 'hFEc;})
  8. compare_data(apb_rd_seq.data, 'hB0);
  9. `uvm_info("body","Exiting...",UVM_LOW)
  1. 设置比较次数的变量和比较错误的变量:
    • 将计数功能放在config中的好处就是可以做一个全局的掌控而不必在各自的phase中来解决这个问题;
    • 对于seq而言,它不是一个component,没有自己的report_phase,产生的计数如果放在pkg中,在调用每一个pkg的时候都需要对这个包中的函数进行调用;
    • 如果想要放在一个全局的环境中,那么最好使用的就是env,因为环境需要复用,放在report_phase中就可以复用到其他层次。 ```verilog int seq_check_count; int seq_check_error; int scb_check_count; int scb_check_error;

apb_config apb_cfg; virtual apb_watchdog_if vif;

  1. **_b. 由于base_virtual_seq是没办法直接拿到cfg的,但是seq挂载到了p_seqencer上,所以可以使用p_sequencer来获取cfg和其中的变量_**
  2. ```verilog
  3. virtual task body();
  4. `uvm_info("body","Entered...",UVM_LOW)
  5. //Todo in sub_class
  6. cfg = p_sequencer.cfg;
  7. `uvm_info("body","Exiting...",UVM_LOW)
  8. endtask
  9. virtual function void compare_data(logic[31:0] val1 , logic[31:0] val2);
  10. cfg.seq_check_count++;
  11. if(val1 === val2)
  12. `uvm_info("COMPSUC",$sformatf("val1 'h%0x === val2 'h%0x", val1, val2), UVM_LOW)
  13. else
  14. cfg.seq_check_error++;
  15. `uvm_error("COMPSUC",$sformatf("val1 'h%0x !== val2 'h%0x", val1, val2))
  16. endfunction

c. 最后需要在仿真的阶段加上report_phase

  1. function report_phase(uvm_phase phase);
  2. string report;
  3. super.report_phase(phase);
  4. reports = $sformatf("CURRENT TEST SUMMARY");
  5. reports = $sformatf("SEQUENCE CHECK COUNT : %0d", cfg.seq_check_count);
  6. reports = $sformatf("SEQUENCE CHECK ERROR : %0d", cfg.seq_check_error);
  7. reports = $sformatf("SCOREBOARD CHECK COUNT : %0d", cfg.scb_check_count);
  8. reports = $sformatf("SCOREBOARD CHECK COUNT : %0d", cfg.scb_check_error);
  9. endfunction

【附件】

至此完成了对apb_watchdog_v1环境的搭建

3.4 【补充】寄存器测试

3.4.1 寄存器读写测试

按照验证计划,对RW寄存器进行了single_write_read测试,测试过程中发现当寄存器上锁以后,任何读写值都是不确定的,因此对Lock寄存器的测试需在最后一位。

  1. `ifndef APB_WATCHDOG_APBACC_VIRT_SEQ_SV
  2. `define APB_WATCHDOG_APBACC_VIRT_SEQ_SV
  3. class apb_watchdog_apbacc_virt_seq extends apb_watchdog_base_virt_seq;
  4. `uvm_object_utils(apb_watchdog_apbacc_virt_seq)
  5. function new(string name = "apb_watchdog_apbacc_virt_seq");
  6. super.new(name);
  7. endfunction
  8. virtual task body();
  9. super.body();
  10. `uvm_info("body","Entered...",UVM_LOW)
  11. ...
  12. // Single write & single read seq
  13. `uvm_do_on_with(apb_wr_seq, p_sequencer.apb_mst_sqr, {addr == 'h00; data == 'hFF;})
  14. `uvm_do_on_with(apb_rd_seq, p_sequencer.apb_mst_sqr, {addr == 'h00;})
  15. compare_data(apb_rd_seq.data, apb_wr_seq.data);
  16. // Single read imediately after single write
  17. wr_val = $urandom_range('h0,'hFF);
  18. `uvm_do_on_with(apb_wr_rd_seq, p_sequencer.apb_mst_sqr, {addr == 'h00; data == wr_val;})
  19. rd_val = apb_wr_rd_seq.data;
  20. compare_data(rd_val, wr_val);
  21. wr_val = $urandom_range('b00,'b11);
  22. `uvm_do_on_with(apb_wr_rd_seq, p_sequencer.apb_mst_sqr, {addr == 'h08; data == wr_val;})
  23. rd_val = apb_wr_rd_seq.data;
  24. compare_data(rd_val, wr_val);
  25. //-- wr_val = $urandom_range('h00, 'hFFFFFFFF);
  26. //-- `uvm_do_on_with(apb_wr_rd_seq, p_sequencer.apb_mst_sqr, {addr == 'hC00; data == wr_val;})
  27. //-- rd_val = apb_wr_rd_seq.data;
  28. //-- compare_data(rd_val[31:1], wr_val[31:1]);
  29. wr_val = 'b1;
  30. `uvm_do_on_with(apb_wr_rd_seq, p_sequencer.apb_mst_sqr, {addr == 'hF00; data == wr_val;})
  31. rd_val = apb_wr_rd_seq.data;
  32. compare_data(rd_val, wr_val);
  33. `uvm_info("body","Exiting...",UVM_LOW)
  34. endtask
  35. endclass
  36. `endif //APB_WATCHDOG_APBACC_VIRT_SEQ_SV

3.4.2 寄存器稳定性测试

3.4.2.1 对非法地址进行读写测试

  1. `ifndef APB_WATCHDOG_ILLEGAL_ACC_VIRT_SEQ_SV
  2. `define APB_WATCHDOG_ILLEGAL_ACC_VIRT_SEQ_SV
  3. class apb_watchdog_illegal_acc_virt_seq extends apb_watchdog_base_virt_seq;
  4. `uvm_object_utils(apb_watchdog_illegal_acc_virt_seq)
  5. function new(string name = "apb_watchdog_illegal_acc_virt_seq");
  6. super.new(name);
  7. endfunction
  8. virtual task body();
  9. super.body();
  10. `uvm_info("body","Entered...",UVM_LOW)
  11. // illegal address register write $ read test
  12. wr_val = 'hFF;
  13. `uvm_do_on_with(apb_wr_seq, p_sequencer.apb_mst_sqr, {addr == 'h01; data == wr_val;})
  14. `uvm_do_on_with(apb_rd_seq, p_sequencer.apb_mst_sqr, {addr == 'h01;})
  15. compare_data(wr_val, apb_rd_seq.data);
  16. // RO register write reserved field and check
  17. wr_val = 'hFFFFFFFF;
  18. `uvm_do_on_with(apb_wr_seq, p_sequencer.apb_mst_sqr, {addr == 'h0C; data == wr_val;})
  19. `uvm_do_on_with(apb_rd_seq, p_sequencer.apb_mst_sqr, {addr == 'h0C;})
  20. diff_value(1, (wr_val & apb_rd_seq.data), "WDOGINTCLR_REG");
  21. `uvm_info("body","Exiting...",UVM_LOW)
  22. endtask
  23. endclass
  24. `endif //APB_WATCHDOG_illegal_acc_VIRT_SEQ_SV

image.png

对非法地址进行测试以后发现subscriber中没有办法在RGM中查找到对应的寄存器。

3.4.2.2 对读写寄存器的保留域进行测试

  1. `ifndef APB_WATCHDOG_ILLEGAL_ACC_VIRT_SEQ_SV
  2. `define APB_WATCHDOG_ILLEGAL_ACC_VIRT_SEQ_SV
  3. class apb_watchdog_illegal_acc_virt_seq extends apb_watchdog_base_virt_seq;
  4. `uvm_object_utils(apb_watchdog_illegal_acc_virt_seq)
  5. function new(string name = "apb_watchdog_illegal_acc_virt_seq");
  6. super.new(name);
  7. endfunction
  8. virtual task body();
  9. super.body();
  10. `uvm_info("body","Entered...",UVM_LOW)
  11. // illegal address register write $ read test
  12. wr_val = 'hFF;
  13. `uvm_do_on_with(apb_wr_seq, p_sequencer.apb_mst_sqr, {addr == 'h01; data == wr_val;})
  14. `uvm_do_on_with(apb_rd_seq, p_sequencer.apb_mst_sqr, {addr == 'h01;})
  15. compare_data(wr_val, apb_rd_seq.data);
  16. // RO register write reserved field and check
  17. //-- wr_val = 'hFFFFFFFF;
  18. //-- `uvm_do_on_with(apb_wr_seq, p_sequencer.apb_mst_sqr, {addr == 'h0C; data == wr_val;})
  19. //-- `uvm_do_on_with(apb_rd_seq, p_sequencer.apb_mst_sqr, {addr == 'h0C;})
  20. //-- diff_value(1, (wr_val & apb_rd_seq.data), "WDOGINTCLR_REG");
  21. // RW register reserved field check
  22. wr_val = 'hFF;
  23. `uvm_do_on_with(apb_wr_seq, p_sequencer.apb_mst_sqr, {addr == 'h08; data == wr_val << 2;})
  24. `uvm_do_on_with(apb_rd_seq, p_sequencer.apb_mst_sqr, {addr == 'h08;})
  25. compare_data(wr_val << 2, apb_rd_seq.data);
  26. `uvm_info("body","Exiting...",UVM_LOW)
  27. endtask
  28. endclass
  29. `endif //APB_WATCHDOG_illegal_acc_VIRT_SEQ_SV

image.png

写入的值是’h3fc,读到的值是默认值0,说明对寄存器的保留域无法修改

3.4.2.3 对只读寄存器进行写测试

  1. `ifndef APB_WATCHDOG_ILLEGAL_ACC_VIRT_SEQ_SV
  2. `define APB_WATCHDOG_ILLEGAL_ACC_VIRT_SEQ_SV
  3. class apb_watchdog_illegal_acc_virt_seq extends apb_watchdog_base_virt_seq;
  4. `uvm_object_utils(apb_watchdog_illegal_acc_virt_seq)
  5. function new(string name = "apb_watchdog_illegal_acc_virt_seq");
  6. super.new(name);
  7. endfunction
  8. virtual task body();
  9. super.body();
  10. `uvm_info("body","Entered...",UVM_LOW)
  11. // RO register write reserved field and check
  12. wr_val = 'hFFFFFFFF;
  13. `uvm_do_on_with(apb_wr_seq, p_sequencer.apb_mst_sqr, {addr == 'h0C; data == wr_val;})
  14. `uvm_do_on_with(apb_rd_seq, p_sequencer.apb_mst_sqr, {addr == 'h0C;})
  15. diff_value(1, (wr_val & apb_rd_seq.data), "WDOGINTCLR_REG");
  16. `uvm_info("body","Exiting...",UVM_LOW)
  17. endtask
  18. endclass
  19. `endif //APB_WATCHDOG_illegal_acc_VIRT_SEQ_SV

image.png

对只读寄存器进行写操作,结果发现无法写入,读取到的是默认值,和写入的值按位与以后不为1。