本文介绍了ahb_ram验证环境的搭建及其具体代码

1.1 波形理解

image.png

  • 先看T4-T7拍,可以发现:T4拍写入的地址为0x28,T5拍Ready信号为低,slave一侧没有做好接收数据的准备,因此data等了一拍以后才写出去,从之前的波形中可以看出来,data正常都是等了一拍以后才会写出去,因此在t4拍开始等了两拍,在第三拍的时候才将数据成功发送。

    1.1 搭建VIP_lib框架

    1.1.1 ahb_agent框架搭建

    :::danger 【思考】
    为了验证AHB_RAM的设计代码,其接口类型是AHB的,为了通过这个AHB给DUT给定测试激励,首先需要agent来在环境中帮助给出激励,而这个agent需要VIP来提供,因此我们需要使用到AHB这个协议,此部分来实现VIP。 ::: image.png

    其中ahb_driver_common.sv用来防止一些公共的驱动; ahb_types用来放置一些公共的类型; 之所以有一些类名前没有master,是因为之后slave和master可能有相同的部分,因此都需要继承同一个公共的类。

:::info (1)在ahb_pkg中导入VIP文件; :::

  1. `ifndef AHB_PKG_SV
  2. `define AHB_PKG_SV
  3. package ahb_pkg;
  4. import uvm_pkg::*;
  5. `include "uvm_macros.svh"
  6. `include "ahb_defines.svh"
  7. `include "ahb_types.sv"
  8. `include "ahb_transaction.sv"
  9. `include "ahb_sequencer.sv"
  10. `include "ahb_driver.sv"
  11. `include "ahb_monitor.sv"
  12. `include "ahb_master_transaction.sv"
  13. `include "ahb_master_sequencer.sv"
  14. `include "ahb_master_driver.sv"
  15. `include "ahb_master_monitor.sv"
  16. `include "ahb_master_agent.sv"
  17. endpackage
  18. `endif // AHB_PKG_SV

:::info (2)ahb_driver & ahb_master_driver ::: :::danger 【注】
对于driver和sequencer参数类而言,由于在master和slave中可能传递的是不同的transaction,因此这里应当在父类中给定参数的传递: :::

  1. `ifndef AHB_DRIVER_SV
  2. `define AHB_DRIVER_SV
  3. class ahb_driver #(type REQ = ahb_transaction, type RSP = REQ) extends uvm_driver #(REQ, RSP);
  4. `uvm_component_utils(ahb_driver)
  5. function new (string name = "ahb_driver", uvm_component parent = null);
  6. super.new(name, parent);
  7. endfunction
  8. function build_phase(uvm_phase phase);
  9. super.build_phase(phase);
  10. endfunction
  11. function connect_phase(uvm_phase phase);
  12. super.connect_phase(phase);
  13. endfunction
  14. task run_phase(uvm_phase phase);
  15. super.run_phase(phase);
  16. phase.raise_objection(phase);
  17. phase.drop_objection(phase);
  18. endtask
  19. endclass
  20. `endif // AHB_DRIVER_SV

1.1.2 参数类问题

ahb_driver作为父类而言,不仅不能做参数,还应当保留参数。使得继承于它的子类可以将这些属性保留下来

image.png

  • uvm_sequencer首先应该是一个参数类,所以紧跟它有一个#;
  • 同时,为了将REQ和RSQ在这一层子类的类型传导到父类,所以在后面加了第二个#。
  • 第一个#是声明参数,第二个#是参数的传导/给定。

  • 需要将参数传导至上一层的原因是,父类中传递的事物是uvm_sequence_item类型的,而driver中传递的事物是ahb_transaction类型的。

:::info (3)编辑参数类ahb_sequencer & ahb_master_sequencer :::

  1. `ifndef AHB_SEQUENCER_SV
  2. `define AHB_SEQUENCER_SV
  3. class ahb_sequencer #(type REQ = ahb_transaction, type RSP = REQ) extends uvm_sequencer #(REQ, RSP);
  4. `uvm_component_utils(ahb_sequencer)
  5. function new (string name = "ahb_sequencer", uvm_component parent = null);
  6. super.new(name,parent);
  7. endfunction
  8. function void build_phase(uvm_phase phase);
  9. super.build_phase(phase);
  10. endfunction
  11. function void connect_phase(uvm_phase phase);
  12. super.connect_phase(phase);
  13. endfunction
  14. task run_phase(uvm_phase phase);
  15. super.run_phase(phase);
  16. endtask
  17. endclass
  18. `endif // AHB_SEQUENCER_SV
  1. `ifndef AHB_MASTER_SEQUENCER_SV
  2. `define AHB_MASTER_SEQUENCER_SV
  3. class ahb_master_sequencer extends ahb_sequencer;
  4. `uvm_component_utils(ahb_master_sequencer)
  5. function new (string name = "ahb_master_sequencer", uvm_component parent = null);
  6. super.new(name,parent);
  7. endfunction
  8. function void build_phase(uvm_phase phase);
  9. super.build_phase(phase);
  10. endfunction
  11. function void connect_phase(uvm_phase phase);
  12. super.connect_phase(phase);
  13. endfunction
  14. task run_phase(uvm_phase phase);
  15. super.run_phase(phase);
  16. endtask
  17. endclass
  18. `endif // AHB_MASTER_SEQUENCER_SV

:::info (4)编辑ahb_monitor & ahb_master_monitor :::

  1. `ifndef AHB_MONITOR_SV
  2. `define AHB_MONITOR_SV
  3. class ahb_monitor extends uvm_monitor;
  4. `uvm_component_utils(ahb_monitor)
  5. function new (string name = "ahb_monitor", uvm_component parent = null);
  6. super.new(name,parent);
  7. endfunction
  8. function void build_phase(uvm_phase phase);
  9. super.build_phase(phase);
  10. endfunction
  11. function void connect_phase(uvm_phase phase);
  12. super.connect_phase(phase);
  13. endfunction
  14. task run_phase(uvm_phase phase);
  15. super.run_phase(phase);
  16. endtask
  17. endclass
  18. `endif // AHB_MONITOR_SV
  1. `ifndef AHB_MASTER_MONITOR_SV
  2. `define AHB_MASTER_MONITOR_SV
  3. class ahb_master_monitor extends ahb_monitor;
  4. `uvm_component_utils(ahb_master_monitor)
  5. function new (string name = "ahb_master_monitor", uvm_component parent = null);
  6. super.new(name, parent);
  7. endfunction
  8. function void build_phase(uvm_phase phase);
  9. super.build_phase(phase);
  10. endfunction
  11. function void connect_phase(uvm_phase phase);
  12. super.connect_phase(phase);
  13. endfunction
  14. task run_phase(uvm_phase phase);
  15. super.run_phase(phase);
  16. endtask
  17. endclass
  18. `endif // AHB_MASTER_MONITOR_SV

:::info (5)编辑configuration及agent_configuration :::

  1. `ifndef AHB_CONFIGURATION_SV
  2. `define AHB_CONFIGURATION_SV
  3. class ahb_configuration extends uvm_object;
  4. `uvm_object_utils_begin(ahb_configuration)
  5. `uvm_object_utils_end
  6. function new (string name = "ahb_configuration");
  7. super.new(name);
  8. endfunction
  9. endclass
  10. `endif // AHB_CONFIGURATION_SV

config文件不仅要对ahb进行配置,还需要对ahb_vip中的agent进行配置。

:::info (6)Makefile文件 ::: image.png :::danger 【思考】

  1. 搭好了框架以后如何让AHB开始工作?AHB在ENV中应该给出什么样的激励给DUT?
  2. 给AHB_RAM供给什么数据内容? :::

    1.1.3 VIP_lib补充

    注:实际上对于VIP_lib的补充是发生在env连接关系之后的,根据移植过来的env环境来对vip_lib中的各个组件进行修改。 :::info 根据env中的连接关系:
  • 虽然在env中是ahb_mst_monitor上的port连接到了predictor上,实际上mst_monitor和slave_monitor都会监测数据,所以将这个port放在ahb_monitor上,使得继承于它的子类都能够使用该port。 ::: ``verilogifndef AHB_MONITOR_SV `define AHB_MONITOR_SV

class ahb_monitor extends uvm_monitor;

uvm_analysis_port #(ahb_transaction) item_observed_port;

`uvm_component_utils(ahb_monitor)

function new (string name = “ahb_monitor”, uvm_component parent = null); super.new(name,parent); item_observed_port = new(“item_observed_port”, this); endfunction

function void build_phase(uvm_phase phase); super.build_phase(phase); endfunction

function void connect_phase(uvm_phase phase); super.connect_phase(phase); endfunction

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

endclass

`endif // AHB_MONITOR_SV

  1. :::info
  2. 2)在envconnect_phase中,有许多port连接到了组件上,因此需要在agent中对组件进行例化:
  3. - agent中声明configvif,并在build_phase中从上层拿到cfgvif
  4. - agent中声明组件并在build_phase中例化;
  5. - connect_phase中完成driversequencer之间端口的连接,将vif与子一级的组件之间进行连接
  6. :::
  7. :::info
  8. 【补充】<br />根据标准的VIP_lib,在ahb_agent_configuration中需要声明is_active变量,作用是对drivermonitor进行开关控制。
  9. :::
  10. ```verilog
  11. `ifndef AHB_MASTER_AGENT_SV
  12. `define AHB_MASTER_AGENT_SV
  13. class ahb_master_agent extends uvm_agent;
  14. ahb_agent_configuration cfg;
  15. ahb_master_driver driver;
  16. ahb_master_monitor monitor;
  17. ahb_master_sequencer sequencer;
  18. virtual ahb_if vif;
  19. `uvm_component_utils(ahb_master_agent)
  20. function new (string name = "ahb_master_agent", uvm_component parent = null);
  21. super.new(name, parent);
  22. endfunction
  23. function void build_phase(uvm_phase phase);
  24. super.build_phase(phase);
  25. if(!uvm_config_db #(ahb_agent_configuration)::get(this, "", "cfg", cfg) begin
  26. `uvm_fatal("GETCFG", "cannot get ahb_agent_configuration")
  27. end
  28. if(!uvm_config_db #(ahb_if)::get(this, "", "vif", vif) begin
  29. `uvm_fatal("GETVIF", "cannot get vif")
  30. end
  31. monitor = ahb_master_monitor::type_id::create("monitor", this);
  32. if(cfg.is_active) begin
  33. driver = ahb_master_driver::type_id::create("driver", this);
  34. sequencer = ahb_master_sequencer::type_id::create("sequencer", this);
  35. end
  36. endfunction
  37. function void connect_phase(uvm_phase phase);
  38. super.connect_phase(phase);
  39. if(cfg.is_active) begin
  40. driver.seq_item_port.connect(sequencer.seq_item_export);
  41. driver.vif = vif;
  42. monitor.vif = vif;
  43. sequencer.vif = vif;
  44. end
  45. endfunction
  46. task run_phase(uvm_phase phase);
  47. super.run_phase(phase);
  48. endtask
  49. endclass
  50. `endif // AHB_MASTER_AGENT_SV
  1. `ifndef AHB_MASTER_DRIVER_SV
  2. `define AHB_MASTER_DRIVER_SV
  3. class ahb_master_driver extends ahb_driver;
  4. ahb_agent_configuration cfg;
  5. virtual ahb_if vif;
  6. `uvm_component_utils(ahb_master_driver)
  7. function new (string name = "ahb_master_driver", uvm_component parent = null);
  8. super.new(name, parent);
  9. endfunction
  10. function void build_phase(uvm_phase phase);
  11. super.build_phase(phase);
  12. endfunction
  13. function void connect_phase(uvm_phase phase);
  14. super.connect_phase(phase);
  15. endfunction
  16. task run_phase(uvm_phase phase);
  17. super.run_phase(phase);
  18. endtask
  19. endclass
  20. `endif // AHB_MASTER_DRIVER_SV
  1. `ifndef AHB_MASTER_MONITOR_SV
  2. `define AHB_MASTER_MONITOR_SV
  3. class ahb_master_monitor extends ahb_monitor;
  4. ahb_agent_configuration cfg;
  5. virtual ahb_if vif;
  6. `uvm_component_utils(ahb_master_monitor)
  7. function new (string name = "ahb_master_monitor", uvm_component parent = null);
  8. super.new(name, parent);
  9. endfunction
  10. function void build_phase(uvm_phase phase);
  11. super.build_phase(phase);
  12. endfunction
  13. function void connect_phase(uvm_phase phase);
  14. super.connect_phase(phase);
  15. endfunction
  16. task run_phase(uvm_phase phase);
  17. super.run_phase(phase);
  18. endtask
  19. endclass
  20. `endif // AHB_MASTER_MONITOR_SV

1.2 ahb_ram顶层环境搭建及仿真

1.2.1 env一侧代码

:::danger 之前已经完成了agent框架的搭建,接下来需要搭建ahb_ram的上层环境,在env中例化agent并运行仿真,在仿真中观察验证结构是什么样的。 ::: :::info (1)ahb_ram_virt_sequencer.sv文件编辑 :::

  1. `ifndef AHB_RAM_VIRTUAL_SEQUENCER_SV
  2. `define AHB_RAM_VIRTUAL_SEQUENCER_SV
  3. class ahb_ram_virtual_sequencer extends uvm_sequencer;
  4. ahb_master_sequencer ahb_mst_sqr;
  5. ahb_ram_config cfg;
  6. `uvm_component_utils(ahb_ram_virtual_sequencer)
  7. function new(string name = "ahb_ram_virtual_sequencer", uvm_component parent);
  8. super.new(name, parent);
  9. endfunction
  10. function void build_phase(uvm_phase phase);
  11. super.build_phase(phase);
  12. //Get configuration from env layer
  13. uvm_config_db#(ahb_ram_config)::get(this, "", "cfg", cfg);
  14. endfunction
  15. endclass
  16. `endif //AHB_RAM_VIRTUAL_SEQUENCER

:::info (2)env中已经例化了ahb_config文件,所以此处对ahb_config文件进行编辑:

  • 声明并例化ahb_vip中的config;
  • 在config中声明vif的句柄。 ::: ``verilogifndef AHB_RAM_CONFIG_SV `define AHB_RAM_CONFIG_SV

class ahb_ram_config extends uvm_object;

int seq_check_count; int seq_check_error;

int scb_check_count; int scb_check_error;

bit scb_enable = 1; bit cov_enable = 1;

ahb_configuration ahb_cfg; virtual ahb_ram_if vif;

`uvm_object_utils(ahb_ram_config)

// USER to specify the config items

function new (string name = “ahb_ram_config”); super.new(name); ahb_cfg = ahb_configuration::type_id::create(“ahb_cfg”); endfunction : new

endclass `endif // AHB_RAM_CONFIG_SV

  1. > config中配置了用于控制scoreboardcoverage的开关。
  2. :::info
  3. 3)在config中配置了用于控制scoreboardcoverage的开关,因此需要对subscriber编辑:
  4. :::
  5. ```verilog
  6. `ifndef AHB_RAM_SUBSCRIBER_SV
  7. `define AHB_RAM_SUBSCRIBER_SV
  8. `uvm_analysis_imp_decl(_apb)
  9. class ahb_ram_subscriber extends uvm_component;
  10. // analysis import
  11. uvm_analysis_imp #(ahb_transaction, ahb_ram_subscriber) ahb_trans_observed_imp;
  12. // Declare events
  13. ahb_ram_config cfg;
  14. virtual ahb_ram_if vif;
  15. `uvm_component_utils(ahb_ram_subscriber)
  16. function new(string name = "ahb_ram_subscriber", uvm_component parent);
  17. super.new(name, parent);
  18. endfunction
  19. function void build_phase(uvm_phase phase);
  20. super.build_phase(phase);
  21. apb_trans_observed_imp = new("apb_trans_observed_imp", this);
  22. // Get configuration from test layer
  23. if(!uvm_config_db#(ahb_ram_config)::get(this, "", "cfg", cfg)) begin
  24. `uvm_fatal("GETCFG", "cannot get conifg object from config db")
  25. end
  26. vif = cfg.vif;
  27. endfunction
  28. task run_phase(uvm_phase phase);
  29. super.run_phase(phase);
  30. do_events_trigger();
  31. do_listen_events();
  32. endtask
  33. virtual function void write(ahb_transaction tr);
  34. endfunction
  35. virtual task do_events_trigger();
  36. endtask
  37. virtual task do_listen_events();
  38. endtask
  39. endclass
  40. `endif // AHB_RAM_SUBSCRIBER_SV

:::info (4)suscriber中监听了来自monitor的数据,scoreboard对采集到的数据进行比较: :::

  1. `ifndef AHB_RAM_SCOREBOARD_SV
  2. `define AHB_RAM_SCOREBOARD_SV
  3. class ahb_ram_scoreboard extends ahb_ram_subscriber;
  4. // Events of scoreboard
  5. `uvm_component_utils(ahb_ram_scoreboard)
  6. function new (string name = "ahb_ram_scoreboard", 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. super.run_phase(phase);
  14. do_countdown_check();
  15. endtask
  16. task do_listen_events();
  17. endtask
  18. virtual task do_data_check();
  19. endtask
  20. endclass
  21. `endif // AHB_RAM_SCOREBOARD_SV

:::info (5)编辑ahb_ram的coverage文件 :::

  1. `ifndef AHB_RAM_COV_SV
  2. `define AHB_RAM_COV_SV
  3. class ahb_ram_cov extends ahb_ram_subscriber;
  4. `uvm_component_utils(ahb_ram_cov)
  5. // Covergroup definition below
  6. function new (string name = "ahb_ram_cov", 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 do_listen_events();
  13. endtask
  14. endclass
  15. `endif // AHB_RAM_COV_SV

:::info (6)寄存器模型编辑:
在生成寄存器模型的时候也需要将map声明到寄存器模型中 :::

  1. `ifndef AHB_RAM_REG_SV
  2. `define AHB_RAM_REG_SV
  3. class ahb_ram_rgm extends uvm_object;
  4. `uvm_object_utils(ahb_ram_rgm)
  5. uvm_reg_map map;
  6. function new (string name = "ahb_ram_rgm");
  7. super.new(name);
  8. endfunction
  9. virtual function build();
  10. map = create_map("map", 'h0, 4, UVM_LITTLE_ENDIAN);
  11. endfunction
  12. endclass
  13. `endif // AHB_RAM_REG_SV

:::info (7)有了寄存器模型,那么也相应需要adapter来进行寄存器模型和总线之间的访问:
adapter中暂时没有声明具体的方法来完成rgm_operation和bus_item之间的转换。 :::

  1. `ifndef AHB_RAM_ADAPTER_SV
  2. `define AHB_RAM_ADAPTER_SV
  3. class ahb_ram_adapter extends uvm_reg_adapter;
  4. `uvm_object_utils(ahb_ram_adapter)
  5. function new(string name = "ahb_ram_adapter");
  6. super.new(name);
  7. endfunction
  8. function uvm_sequence_item reg2bus(const ref uvm_reg_bus_op rw);
  9. endfunction
  10. function void bus2reg(uvm_sequence_item bus_item, ref uvm_reg_bus_op rw);
  11. endfunction
  12. endclass
  13. `endif //AHB_RAM_ADAPTER_SV

:::danger (7)在完成了上述组件的内容之后,最后一步就是将他们集成到env中: :::

  1. `ifndef AHB_RAM_ENV_SV
  2. `define AHB_RAM_ENV_SV
  3. class ahb_ram_env extends uvm_env;
  4. ahb_master_agent ahb_mst;
  5. ahb_ram_config cfg;
  6. ahb_ram_virtual_sequencer virt_sqr;
  7. ahb_ram_rgm rgm;
  8. ahb_ram_adapter adapter;
  9. uvm_reg_predictor #(ahb_transfer) predictor;
  10. ahb_ram_cov cov;
  11. ahb_ram_scoreboard scb;
  12. `uvm_component_utils(ahb_ram_env)
  13. function new (string name = "ahb_ram_env", uvm_component parent);
  14. super.new(name, parent);
  15. endfunction
  16. function void build_phase(uvm_phase phase);
  17. super.build_phase(phase);
  18. // Get configuration from test layer
  19. if(!uvm_config_db#(ahb_ram_config)::get(this,"","cfg", cfg)) begin
  20. `uvm_fatal("GETCFG","cannot get config object from config DB")
  21. end
  22. uvm_config_db#(ahb_ram_config)::set(this, "virt_sqr", "cfg", cfg);
  23. uvm_config_db#(ahb_ram_config)::set(this, "cov", "cfg", cfg);
  24. uvm_config_db#(ahb_ram_config)::set(this, "scb", "cfg", cfg);
  25. uvm_config_db#(ahb_agent_configuration)::set(this, "ahb_mst", "cfg", cfg.ahb_cfg);
  26. ahb_mst = ahb_master_agent::type_id::create("ahb_mst", this);
  27. virt_sqr = ahb_ram_virtual_sequencer::type_id::create("virt_sqr", this);
  28. if(!uvm_config_db#(ahb_ram_rgm)::get(this,"","rgm", rgm)) begin
  29. rgm = ahb_ram_rgm::type_id::create("rgm", this);
  30. rgm.build();
  31. end
  32. uvm_config_db#(ahb_ram_rgm)::set(this, "*", "rgm", rgm);
  33. adapter = ahb_ram_adapter::type_id::create("adapter");
  34. predictor = uvm_reg_predictor#(ahb_transfer)::type_id::create("predictor", this);
  35. scb = ahb_ram_scoreboard::type_id::create("scb", this);
  36. cov = ahb_ram_cov::type_id::create("cov", this);
  37. endfunction
  38. function void connect_phase(uvm_phase phase);
  39. super.connect_phase(phase);
  40. virt_sqr.ahb_mst_sqr = ahb_mst.sequencer;
  41. rgm.map.set_sequencer(ahb_mst.sequencer, adapter);
  42. ahb_mst.monitor.item_observed_port.connect(predictor.bus_in);
  43. predictor.map = rgm.map;
  44. predictor.adapter = adapter;
  45. ahb_mst.monitor.item_observed_port.connect(cov.ahb_trans_observed_imp);
  46. ahb_mst.monitor.item_observed_port.connect(scb.ahb_trans_observed_imp);
  47. endfunction
  48. function void report_phase(uvm_phase phase);
  49. string reports = "\n";
  50. super.report_phase(phase);
  51. reports = {reports, $sformatf("================================================= \n")};
  52. reports = {reports, $sformatf("CURRENT TEST SUMMARY \n")};
  53. reports = {reports, $sformatf("SEQUENCE CHECK COUNT : %0d \n", cfg.seq_check_count)};
  54. reports = {reports, $sformatf("SEQUENCE CHECK ERROR : %0d \n", cfg.seq_check_error)};
  55. reports = {reports, $sformatf("SCOREBOARD CHECK COUNT : %0d \n", cfg.scb_check_count)};
  56. reports = {reports, $sformatf("SCOREBOARD CHECK COUNT : %0d \n", cfg.scb_check_error)};
  57. reports = {reports, $sformatf("=================================================")};
  58. `uvm_info("TEST_SUMMARY",reports, UVM_LOW);
  59. endfunction
  60. endclass
  61. `endif // AHB_RAM_ENV_SV

在env搭建这一步中,特别是在connect_phase这一步中,需要观察每一个组件中哪些部分进行了连接:

  1. rgm中map连接到了sequencer和adapter中,故需要在adapter中添加map;
  2. monitor的port连接到了predictor的bus_in上,故需要在monitor中声明port;

1.2.2 test一侧代码

:::info 新建ahb_ram_seq_lib.svh并将base_virt_seq和发烟_seq集成在内; :::

  1. `ifndef AHB_RAM_SEQ_LIB_SVH
  2. `define AHB_RAM_SEQ_LIB_SVH
  3. `include "ahb_ram_base_virtual_seq.sv"
  4. `include "ahb_ram_smoke_virt_seq.sv"
  5. `endif
  1. `ifndef AHB_RAM_BASE_VIRT_SEQ_SV
  2. `define AHB_RAM_BASE_VIRT_SEQ_SV
  3. class ahb_ram_base_virt_seq extends uvm_sequence;
  4. ahb_ram_config cfg;
  5. virtual ahb_ram_if vif;
  6. ahb_ram_rgm rgm;
  7. bit [31:0] rd_val, wr_val;
  8. uvm_status_e status;
  9. `uvm_object_utils(ahb_ram_base_virt_seq)
  10. `uvm_declare_p_sequencer(ahb_ram_virtual_sequencer)
  11. function new(string name = "ahb_ram_base_virt_seq");
  12. super.new(name);
  13. endfunction
  14. virtual task body();
  15. `uvm_info("body","Entered...",UVM_LOW)
  16. //Get cfg from p_sequencer
  17. cfg = p_sequencer.cfg;
  18. vif = cfg.vif;
  19. rgm = cfg.rgm;
  20. `uvm_info("body","Exiting...",UVM_LOW)
  21. endtask
  22. virtual function void compare_data(logic[31:0] val1, logic[31:0] val2);
  23. cfg.seq_check_count++;
  24. if(val1 === val2)
  25. `uvm_info("CMPSUC", $sformatf("val1 'h%0x === val2 'h%0x", val1, val2), UVM_LOW)
  26. else begin
  27. cfg.seq_check_error++;
  28. `uvm_error("CMPSUC", $sformatf("val1 'h%0x !== val2 'h%0x", val1, val2))
  29. end
  30. endfunction
  31. task wait_reset_asserted();
  32. @(posedge vif.rst_n);
  33. endtask
  34. task wait_reset_released();
  35. @(negedge vif.rst_n);
  36. endtask
  37. endclass
  38. `endif //AHB_RAM_BASE_VIRT_SEQ
  1. `ifndef AHB_RAM_SMOKE_VIRT_SEQ_SV
  2. `define AHB_RAM_SMOKE_VIRT_SEQ_SV
  3. class ahb_ram_smoke_virt_seq extends apb_watchdog_base_virt_seq;
  4. `uvm_object_utils(ahb_ram_smoke_virt_seq)
  5. function new(string name = "ahb_ram_smoke_virt_seq");
  6. super.new(name);
  7. endfunction
  8. virtual task body();
  9. super.body();
  10. `uvm_info("body","Entered...",UVM_LOW)
  11. `uvm_info("body","EXited...", UVM_LOW)
  12. endtask
  13. endclass
  14. `endif //AHB_RAM_SMOKE_VIRT_SEQ_SV

:::info 在test一层中补充对应的test文件:

  • apb_ram_base_test.sv
  • apb_ram_smoke_test.sv ::: ``verilogifndef AHB_RAM_BASE_TEST_SV `define AHB_RAM_BASE_TEST_SV

virtual class ahb_ram_base_test extends uvm_test;

  1. ahb_ram_config cfg;
  2. ahb_ram_env env;
  3. ahb_ram_rgm rgm;
  4. function new(string name = "ahb_ram_base_test", uvm_component parent);
  5. super.new(name, parent);
  6. endfunction
  7. function void build_phase(uvm_phase phase);
  8. super.build_phase(phase);
  9. rgm = ahb_ram_rgm::type_id::create("rgm");
  10. rgm.build();
  11. uvm_config_db#(ahb_ram_rgm)::set(this, "env", "rgm", rgm);
  12. cfg = ahb_ram_config::type_id::create("cfg");
  13. cfg.rgm = rgm;
  14. if(!uvm_config_db#(virtual ahb_ram_if)::get(this,"","vif", cfg.vif)) begin
  15. `uvm_fatal("GETCFG","cannot get virtual interface from config DB")
  16. end
  17. uvm_config_db#(ahb_ram_config)::set(this, "env", "cfg", cfg);
  18. env = ahb_ram_env::type_id::create("env", this);
  19. endfunction
  20. function void connect_phase(uvm_phase phase);
  21. super.connect_phase(phase);
  22. endfunction
  23. task run_phase(uvm_phase phase);
  24. super.run_phase(phase);
  25. phase.phase_done.set_drain_time(this, 1us);
  26. phase.raise_objection(this);
  27. phase.drop_objection(this);
  28. endtask

endclass

`endif //AHB_RAM_BASE_TEST

  1. ```verilog
  2. `ifndef AHB_RAM_SMOKE_TEST_SV
  3. `define AHB_RAM_SMOKE_TEST_SV
  4. class ahb_ram_smoke_test extends apb_watchdog_base_test;
  5. `uvm_component_utils(ahb_ram_smoke_test)
  6. function new(string name = "ahb_ram_smoke_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. ahb_ram_smoke_virt_seq seq = ahb_ram_smoke_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 //AHB_RAM_SMOKE_TEST_SV
  1. `ifndef AHB_RAM_TESTS_SVH
  2. `define AHB_RAM_TESTS_SVH
  3. `include "ahb_ram_base_test.sv"
  4. `include "ahb_ram_smoke_test.sv"
  5. `endif // AHB_RAM_TESTS_SVH

【调试及结果】

image.png

调试报错没有拿到vif

:::info 在tb中例化interface并使用config_db机制向下传递。 ::: image.png
image.png

搭建好以后的结构如上图所示