【总结】

  1. 该部分完成了寄存器模型的集成,在regacc的的sequence中完成对寄存器的读测试;
  2. 完成对apb_watchdog的集成测试,在integration_virt_seq中对进入和退出集成测试模式以后的int值及res值进行比较核对。

【思考】 对寄存器模型的集成倾向于顶层传递传递的方式,从Test层向下传递句柄,这样有利于整个环境的闭合性,后续在对寄存器进行不同配置的时候只要进行其他例化即可。

4.1 集成RGM

将使用Python生成的apb_watchdog_reg寄存器模型集成到apb_watchdog_reg中,对于python脚本自动生成寄存器模型不在此处赘述。

  1. `ifndef APB_WATCHDOG_REG_SVH
  2. `define APB_WATCHDOG_REG_SVH
  3. `include "apb_watchdog_reg.sv"
  4. `endif //APB_WATCHDOG_REG_SVH

4.1.1 添加adapter

一般来说,一个VIP中会自带一个adapter,如果没有的话可以在自己的环境中添加一个

  1. touch apb_watchdog_adapter.sv

:::info

  1. 将adapter导入到apb_pkg中 ::: ``verilogifndef APB_WATCHDOG_PKG_SV `define APB_WATCHDOG_PKG_SV

package apb_watchdog_pkg;

import uvm_pkg::; `include “uvm_macros.svh” import apb_pkg::;

include "apb_watchdog_config.svh"include “apb_watchdog_reg.svh” include "apb_watchdog_cov.svh"include “apb_watchdog_adapter”

include "apb_watchdog_virtual_sequencer.sv"include “apb_watchdog_env.sv”

include "apb_watchdog_seq_lib.svh"include “apb_watchdog_tests.svh”

endpackage

`endif //apb_watchdog_pkg

  1. :::info
  2. 2. **_编辑apb_watchdog_adapter_**
  3. 这个part可以复用UVM_advance2.3中的adapter
  4. :::
  5. ```verilog
  6. `ifndef APB_WATCHDOG_ADAPTER_SV
  7. `define APB_WATCHDOG_ADAPTER_SV
  8. class apb_watchdog_adapter extends uvm_reg_adapter;
  9. `uvm_object_utils(apb_watchdog_adapter)
  10. function new(string name = "apb_watchdog_adapter");
  11. super.new(name);
  12. provides_responses = 1;
  13. endfunction
  14. function uvm_sequence_item reg2bus(const ref uvm_reg_bus_op rw);
  15. apb_transfer t = apb_transfer::type_id::create("t");
  16. t.trans_kind = (rw.kind == UVM_WRITE) ? WRITE : READ;
  17. t.addr = rw.addr;
  18. t.data = rw.data;
  19. t.idle_cycles = 1;
  20. return t;
  21. endfunction
  22. function void bus2reg(uvm_sequence_item bus_item, ref uvm_reg_bus_op rw);
  23. apb_transfer t;
  24. if (!$cast(t, bus_item)) begin
  25. `uvm_fatal("CASTFAIL","Provided bus_item is not of the correct type")
  26. return;
  27. end
  28. rw.kind = (t.trans_kind == WRITE) ? UVM_WRITE : UVM_READ;
  29. rw.addr = t.addr;
  30. rw.data = t.data;
  31. rw.status = t.trans_status == OK ? UVM_IS_OK : UVM_NOT_OK;
  32. endfunction
  33. endclass
  34. `endif //APB_WATCHDOG_ADAPTER_SV

:::info

  1. 在env中声明

(1)在env中声明寄存器模型和adapter;
(2)以config的模式get寄存器模型,同时例化adapter; :::

  1. class apb_watchdog_env extends uvm_env;
  2. apb_master_agent apb_mst;
  3. apb_watchdog_config cfg;
  4. apb_watchdog_virtual_sequencer virt_sqr;
  5. apb_watchdog_rgm rgm;
  6. apb_watchdog_adapter adapter;
  7. uvm_reg_predictor predictor;
  8. ...
  9. function void build_phase(uvm_phase phase);
  10. super.build_phase(phase);
  11. // Get configuration from test layer
  12. if(!uvm_config_db#(apb_watchdog_config)::get(this,"","cfg", cfg)) begin
  13. `uvm_fatal("GETCFG","cannot get config object from config DB")
  14. end
  15. uvm_config_db#(apb_watchdog_config)::set(this, "virt_sqr", "cfg", cfg);
  16. uvm_config_db#(apb_config)::set(this, "apb_mst", "cfg", cfg.apb_cfg);
  17. apb_mst = apb_master_agent::type_id::create("apb_mst", this);
  18. virt_sqr = apb_watchdog_virtual_sequencer::type_id::create("virt_sqr", this);
  19. if(!uvm_config_db#(apb_watchdog_rgm)::get(this,"","rgm", rgm)) begin
  20. rgm = apb_watchdog_rgm::type_id::create("rgm", this);
  21. rgm.build();
  22. end
  23. adapter = apb_watchdog_adapter::type_id::create("adapter", this);
  24. predictor = uvm_reg_predictor#(apb_transfer)::type_id::create("predictor", this);
  25. endfunction
  26. ...
  27. endclass

4.1.2 传递rgm

(1)在apb_watchdog_config中添加声明rgm;

  1. class apb_watchdog_config extends uvm_object;
  2. ...
  3. apb_watchdog_rgm rgm;
  4. ...
  5. endclass

(2)在test一层中将声明寄存器模型,将寄存器模型与config中的寄存器模型连接,之后将寄存器模型向下传递;

  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. function void build_phase(uvm_phase phase);
  11. super.build_phase(phase);
  12. rgm = apb_watchdog_rgm::type_id::create("rgm");
  13. rgm.build();
  14. uvm_config_db#(apb_watchdog_rgm)::set(this, "env", "rgm", rgm);
  15. cfg = apb_watchdog_config::type_id::create("cfg");
  16. if(!uvm_config_db#(virtual apb_watchdog_if)::get(this,"","vif", cfg.vif)) begin
  17. `uvm_fatal("GETCFG","cannot get virtual interface from config DB")
  18. end
  19. uvm_config_db#(apb_watchdog_config)::set(this, "env", "cfg", cfg);
  20. env = apb_watchdog_env::type_id::create("env", this);
  21. endfunction
  22. function void connect_phase(uvm_phase phase);
  23. cfg.rgm = rgm;
  24. endfunction
  25. ...
  26. endclass
  27. `endif //APB_WATCHDOG_BASE_TEST

【总结】寄存器模型的传递逻辑是:

  • 先在顶层创建rgm;然后将创建的rgm连接到config中声明的句柄上;
    • 在创建了rgm以后,一定要注意rgm.build(),如果不build那么寄存器模型中的所有寄存器块和map都不会创建。
  • 底层通过config来get寄存器模型,如果get不到就会自己创建一个。

4.1.3 集成rgm

  1. class apb_watchdog_env extends uvm_env;
  2. ...
  3. function void connect_phase(uvm_phase phase);
  4. super.connect_phase(phase);
  5. virt_sqr.apb_mst_sqr = apb_mst.sequencer;
  6. rgm.map.set_sequencer(apb_mst.sequencer, adapter);
  7. apb_mst.monitor.item_collected_port.connect(predictor.bus_in);
  8. predictor.map = rgm.map;
  9. predictor.adapter = adapter;
  10. endfunction
  11. ...
  12. endclass

4.1.4 给定测试序列

(1)编辑apb_watchdog_regacc_seq.sv
之前是通过寄存器总线(apb_transfer)对寄存器中的值进行访问,现在采用RGM对寄存器中的值进行访问;
(2)采用RGM进行访问,那么RGM如何导入到seq中呢?

  • 在apb_watchodg_base_virt_seq(父类)中可以拿到config中的vif和RGM;
  • 父类中有了rgm以后,子类apb_watchdog_regacc_seq就可以对寄存器中的值进行访问:

    • 声明寄存器中的读写值和状态(父类中声明);
    • 通过寄存器模型中寄存器的地址来访问值。 ``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; apb_watchdog_config cfg; uvm_object_utils(apb_watchdog_base_virt_seq)uvm_declare_p_sequencer(apb_watchdog_virtual_sequencer)

    virtual apb_watchdog_if vif; apb_watchdog_rgm rgm;

    bit [31:0] rd_val, wr_val; uvm_status_e status;

    function new(string name = “apb_watchdog_base_virt_seq”);

    1. super.new(name);

    endfunction

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

    1. //Get cfg from p_sequencer
    2. cfg = p_sequencer.cfg;
    3. vif = cfg.vif;
    4. rgm = cfg.rgm;

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

    virtual function void compare_data(logic[31:0] val1, logic[31:0] val2);

    1. cfg.seq_check_count++;

    if(val1 === val2)

    1. `uvm_info("CMPSUC", $sformatf("val1 'h%0x === val2 'h%0x", val1, val2), UVM_LOW)

    else begin

    1. cfg.seq_check_error++;
    2. `uvm_error("CMPSUC", $sformatf("val1 'h%0x !== val2 'h%0x", val1, val2))

    end endfunction

    endclass

`endif //APB_WATCHDOG_BASE_VIRT_SEQ

  1. ```verilog
  2. `ifndef APB_WATCHDOG_regacc_VIRT_SEQ_SV
  3. `define APB_WATCHDOG_regacc_VIRT_SEQ_SV
  4. class apb_watchdog_regacc_virt_seq extends apb_watchdog_base_virt_seq;
  5. `uvm_object_utils(apb_watchdog_regacc_virt_seq)
  6. function new(string name = "apb_watchdog_regacc_virt_seq");
  7. super.new(name);
  8. endfunction
  9. virtual task body();
  10. super.body();
  11. `uvm_info("body","Entered...",UVM_LOW)
  12. // Get value from rgm
  13. //`uvm_do_on_with(apb_rd_seq, p_sequencer.apb_mst_sqr, {addr == 'hFE0;})
  14. rgm.WDOGPERIPHID0.read(status, rd_val);
  15. compare_data(rd_val, 'h24);
  16. //`uvm_do_on_with(apb_rd_seq, p_sequencer.apb_mst_sqr, {addr == 'hFE4;})
  17. //`uvm_do_on_with(apb_rd_seq, p_sequencer.apb_mst_sqr, {addr == 'hFE0;})
  18. rgm.WDOGPERIPHID1.read(status, rd_val);
  19. compare_data(rd_val.data, 'hB8);
  20. //`uvm_do_on_with(apb_rd_seq, p_sequencer.apb_mst_sqr, {addr == 'hFE8;})
  21. //`uvm_do_on_with(apb_rd_seq, p_sequencer.apb_mst_sqr, {addr == 'hFE0;})
  22. rgm.WDOGPERIPHID2.read(status, rd_val);
  23. compare_data(rd_val.data, 'h1B);
  24. //`uvm_do_on_with(apb_rd_seq, p_sequencer.apb_mst_sqr, {addr == 'hFEc;})
  25. //`uvm_do_on_with(apb_rd_seq, p_sequencer.apb_mst_sqr, {addr == 'hFE0;})
  26. rgm.WDOGPERIPHID3.read(status, rd_val);
  27. compare_data(rd_val.data, 'hB0);
  28. `uvm_info("body","Exiting...",UVM_LOW)
  29. endtask
  30. endclass
  31. `endif //APB_WATCHDOG_regacc_VIRT_SEQ_SV

(3)补充apb_watchdog_regacc_test.sv中的内容

  1. `ifndef APB_WATCHDOG_REGACC_TEST_SV
  2. `define APB_WATCHDOG_REGACC_TEST_SV
  3. class apb_watchdog_regacc_test extends apb_watchdog_base_test;
  4. `uvm_component_utils(apb_watchdog_regacc_test)
  5. function new(string name = "apb_watchdog_regacc_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_regacc_virt_seq seq = apb_watchdog_regacc_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_REGACC_TEST_SV

【调试及实验结果】

(1)调试

image.png

调试以后报错未能找到这个对象,debug方法:

  • 在该位置设置断点,点击local查看局部变量,观察对象是否都有例化,也就是是否有艾特值。

image.png

  • 经过查看以后是map没有例化

(2)实验结果

image.png

使用寄存器模型对寄存器中值访问的结果和在apb总线上访问的结果相同

4.2 集成测试模式

image.png

WDOGITCR寄存器控制了集成测试的开关。 当打开了集成测试的开关以后,WDOGINT和WDOGRES的值直接由WDOGITOP来决定。

4.2.1 编辑apb_watchdog_integration_virt_seq

做以下几个数值比较:

  1. 拉高enable信号之前,检查int和res的默认值是否为0;
  2. 拉高enable信号之后,拉高int和res,与1进行比较;
  3. 拉高enable信号之后,拉低int和res,与0进行比较;
  4. 拉高enable信号之后拉高int和res,与1进行比较,之后再拉低enable信号,观察对于int和res信号线是否有影响。
  • 接下来使用前门访问方法update()来复位reset 寄存器;
  • 需要检查的两个信号的数值可以在interface中已经定义,他们在tb中也连接到了对应的端口上,而vif也在base_virt_seq的body中做了连接,所以可以在integration_virt_seq中拿到接口上的信号;
  • 注意设置的时候是对寄存器块中寄存器上的域的值进行配置,因此路径必须准确。 ``verilogifndef APB_WATCHDOG_INTEGRATION_VIRT_SEQ_SV `define APB_WATCHDOG_INTEGRATION_VIRT_SEQ_SV

    class apb_watchdog_integration_virt_seq extends apb_watchdog_base_virt_seq;

    `uvm_object_utils(apb_watchdog_integration_virt_seq)

    function new(string name = “apb_watchdog_integration_virt_seq”);

    1. super.new();

    endfunction

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

    1. // Check WDOGINT & WDOGRES reset value
    2. `uvm_info("INTGTEST","Check WDOGINT & WDOGRES reset value", UVM_LOW)
    3. compare_data(vif.wdog_int, 1'b0);
    4. compare_data(vif.wdog_res, 1'b0);
    5. // Enable integration test mode
    6. rgm.WDOGITCR.ITME.set(1'b1);
    7. rgm.WDOGITCR.update(status);
    8. // Check WDOGINT & WDOGRES test control value
    9. `uvm_info("INTGTEST","Check WDOGINT & WDOGRES test control value", UVM_LOW)
    10. rgm.WDOGITOP.WDOGINT.set(1'b1);
    11. rgm.WDOGITOP.WDOGRES.set(1'b1);
    12. rgm.WDOGITOP.update(status);
    13. compare_data(vif.wdog_int, 1'b1);
    14. compare_data(vif.wdog_res, 1'b1);
    15. rgm.WDOGITOP.WDOGINT.set(1'b0);
    16. rgm.WDOGITOP.WDOGRES.set(1'b0);
    17. rgm.WDOGITOP.update(status);
    18. compare_data(vif.wdog_int, 1'b0);
    19. compare_data(vif.wdog_res, 1'b0);
    20. // Check WDOGINT & WDOGRES test mode exit
    21. `uvm_info("INTGTEST","Check WDOGINT & WDOGRES test mode exit value", UVM_LOW)
    22. rgm.WDOGITOP.WDOGINT.set(1'b1);
    23. rgm.WDOGITOP.WDOGRES.set(1'b1);
    24. rgm.WDOGITOP.update(status);
    25. compare_data(vif.wdog_int, 1'b1);
    26. compare_data(vif.wdog_res, 1'b1);
    27. rgm.WDOGITCR.ITME.set(1'b0);
    28. rgm.WDOGITCR.update(status);
    29. `uvm_info("SEQSTART","virtual sequence body started!", UVM_LOW)
    30. #1us;

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

`endif //apb_watchdog_integration_virt_seq

```

【调试及结果】

image.png

在class中输入 integration找到apb_watchdog_integration_virt_seq并设置断点。

image.png

在拉起enable之前的int和res默认值都是0,第一个测试通过

image.png

在拉起enable进入集成测试模式以后,int和res的值分别是1和0,测试通过;

image.png

对于最后一个测试而言,在enable拉高的时候,res和int的值都是1无误,但是当enable拉低以后,对寄存器中的值产生了影响,值变成了0不再是1。

image.png

从波形上也可以看出,当penable拉低以后,int和res的值也变成0,也就是说变成了复位的默认值。

【分析】

当集成测试的配置功能enable拉低以后,int和res两个信号线就是由watchdog内部的功能决定而不是由寄存器来配置。具体可以在design的驱动逻辑中来查找:
image.png
通过点击DUT中的信号线可以追溯到信号线的设计逻辑,可以发现这是一个组合逻辑,当wdog_itcr为低的时候,watchdog信号线的逻辑由内部的功能逻辑驱动。

【附件】

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