AHB_SRAM UVM验证(2)搭建顶层环境

验证架构

在这里插入图片描述

  • 最基本的框架如上图所示,上一节中搭建了红色的lvc部分的架构
  • 本节搭建rkv的顶层环境:
  • 在uvm文件夹下创建env文件夹存放顶层环境的组件、创建cov文件夹存放收集覆盖率的文件、创建cfg文件夹存放顶层的配置文件,新建rgm文件夹存放顶层vip的寄存器模型文件以及adapter文件,新建test文件夹存放test文件,新建seq_lib存放各种测试情况的sequence(在其下新建elem_seqs存放基本的sequence)
  • env文件夹中:
  • rkv_ahbram_pkg:在上一节中以及简单提及并在其中导入了lvc的包,本节新添加rkv环境下的组件
  • rkv_ahbram_env:顶层的环境组件
  • rkv_ahbram_virtual_sequencer:virtual sequencer,由于本项目只有lvc_ahb_master_sequencer,所以其中只有一个sequencer,在rkv_ahbram_env中连接
  • rkv_ahbram_subscriber:负责监听monitor的数据
  • rkv_ahbram_scoreboard:继承于rkv_ahbram_subscriber
  • cov文件夹中
  • rkv_ahbram_cov:收集覆盖率
  • cfg文件夹中
  • rkv_ahbram_config:顶层的配置文件
  • rgm文件夹中
  • rkv_ahbram_rgm:寄存器模型
  • rkv_ahbram_adapter:
  • test文件夹中
  • rkv_ahbram_base_test:base test文件
  • seq_lib文件夹中
  • rkv_ahbram_base_virtual_sequence
  • rkv_ahbram_seq_lib

configuration:在其中定义检查的count变量,并在其中例化lvc的configuration

// config set in env
`ifndef RKV_AHBRAM_CONFIG_SV
`define RKV_AHBRAM_CONFIG_SV

class rkv_ahbram_config extends uvm_object;

	int seq_check_count;
	int seq_check_error;

	int scb_check_count;
	int scb_check_error;

	bit enable_cov = 1;
	bit enable_scb = 1;

   // dut addr width 16, limit 
    bit [31:0] addr_start;
    bit [31:0] addr_end;

    int data_width;

	lvc_ahb_agent_configuration ahb_cfg; // import low layer agent config
	virtual rkv_ahbram_if vif; // interface
	rkv_ahbram_rgm rgm; // regist model

	`uvm_object_utils(rkv_ahbram_config)

	// USER to specify the config item

	function new(string name = "rkv_ahbram_config");
		super.new(name);
		ahb_cfg = lvc_ahb_agent_configuration::type_id::create("ahb_cfg");
	endfunction : new


endclass
`endif

覆盖率收集rkv_ahbram_cov、寄存器模型的rkv_ahbram_rgm、rkv_ahbram_adapter搭建基本框架即可:

`ifndef RKV_AHBRAM_COV_SV
`define RKV_AHBRAM_COV_SV
class rkv_ahbram_cov extends rkv_ahbram_subscriber;
  `uvm_component_utils(rkv_ahbram_cov)
	function new(string name = "rkv_ahbram_cov", uvm_component parent);
		super.new(name, parent);
	endfunction
	function void build_phase(uvm_phase phase);
		super.build_phase(phase);
	endfunction
  endclass
`endif
`ifndef RKV_AHBRAM_REG_SV
`define RKV_AHBRAM_REG_SV

class rkv_ahbram_rgm extends uvm_reg_block;

	`uvm_object_utils(rkv_ahbram_rgm)

	uvm_reg_map map;
	function new(string name = "rkv_ahbram_rgm");
		super.new(name,UVM_NO_COVERAGE);
	endfunction

	virtual function build();
		map = create_map("map", 'h0, 4, UVM_LITTLE_ENDIAN);
    lock_model();
	endfunction
endclass
`endif

`ifndef RKV_AHBRAM_REG_ADAPTER_SV
`define RKV_AHBRAM_REG_ADAPTER_SV

class rkv_ahbram_reg_adapter extends uvm_reg_adapter;

	`uvm_object_utils(rkv_ahbram_reg_adapter)
	function new(string name = "rkv_ahbram_reg_adapter");
		super.new(name);
   		provides_responses = 1;
	endfunction

  function uvm_sequence_item reg2bus(const ref uvm_reg_bus_op rw);

  endfunction
  function void bus2reg(uvm_sequence_item bus_item, ref uvm_reg_bus_op rw);

  endfunction

endclass

`endif

更新的rkv_ahbram_pkg:新include进来的都为rkv的组件。

`ifndef RKV_AHBRAM_PKG_SV
`define RKV_AHBRAM_PKG_SV
 
package rkv_ahbram_pkg;
  import uvm_pkg::*;
  `include "uvm_macros.svh"
  import lvc_ahb_pkg::*;


  `include "../reg/rkv_ahbram_rgm.sv"
  `include "../reg/rkv_ahbram_reg_adapter.sv" 
  `include "../cfg/rkv_ahbram_config.sv"

  `include "rkv_ahbram_virtual_sequencer.sv"
  `include "rkv_ahbram_subscriber.sv"

  `include "rkv_ahbram_scoreboard.sv"
  `include "rkv_ahbram_cov.sv" 

  `include "rkv_ahbram_env.sv"
  `include "rkv_ahbram_seq_lib.svh"
  `include "rkv_ahbram_base_virtual_sequence.sv"

  `include "rkv_ahbram_base_test.sv"
endpackage
`endif

virtual_sequencer:声明指向lvc_ahb_master_sequencer的句柄

`ifndef RKV_AHBRAM_VIRTUAL_SEQUENCER_SV
`define RKV_AHBRAM_VIRTUAL_SEQUENCER_SV
 
class rkv_ahbram_virtual_sequencer extends uvm_sequencer;
 
  // add sub-instances' sqr handles below for routing把各个Sequencer添加在下面
  rkv_ahbram_config cfg;	//顶层的配置文件
  lvc_ahb_master_sequencer ahb_mst_sqr;
 
  `uvm_component_utils(rkv_ahbram_virtual_sequencer)
 
  function new (string name = "rkv_ahbram_virtual_sequencer", uvm_component parent);
    super.new(name, parent);
  endfunction
 
  function void build_phase(uvm_phase phase);
    super.build_phase(phase);
    // Get configuration from test layer	//获取配置
    if(!uvm_config_db#(rkv_ahbram_config)::get(this,"","cfg", cfg)) begin
      `uvm_fatal("GETCFG","cannot get config object from config DB")
    end
  endfunction
endclass
`endif

subscriber:在其中需要声明uvm_analysis_imp是monitor中广播的一个对象,并在build_phase中为其开辟空间。

`ifndef RKV_AHBRAM_SUBSCRIBER_SV
`define RKV_AHBRAM_SUBSCRIBER_SV
 
class rkv_ahbram_subscriber extends uvm_component;
 
  // analysis import
  uvm_analysis_imp #(lvc_ahb_transaction, rkv_ahbram_subscriber) ahb_trans_observed_imp;
 
  // events delcared
 
  protected uvm_event_pool _ep;
  
  rkv_ahbram_config cfg;
  virtual rkv_ahbram_if vif;
 
  `uvm_component_utils(rkv_ahbram_subscriber)
 
  function new (string name = "rkv_ahbram_subscriber", uvm_component parent);
    super.new(name, parent);
  endfunction
 
  function void build_phase(uvm_phase phase);
    super.build_phase(phase);
    ahb_trans_observed_imp = new("ahb_trans_observed_imp", this);//例化import
    // Get configuration from test layer
    if(!uvm_config_db#(rkv_ahbram_config)::get(this,"","cfg", cfg)) begin
      `uvm_fatal("GETCFG","cannot get config object from config DB")
    end
    vif = cfg.vif;//
    // Local event pool and events creation
    _ep = new("_ep");
  endfunction
 
  task run_phase(uvm_phase phase);
    super.run_phase(phase);
    do_events_trigger();
    do_listen_events();
  endtask
 
  virtual function void write(lvc_ahb_transaction tr);
  endfunction
 
  virtual task do_events_trigger();
  endtask
 
  virtual task do_listen_events();
  endtask
 
endclass
 
`endif

scoreboard 继承与subscriber,用来比对读回的值是否与写入的值一致,功能的比对组件:

`ifndef RKV_AHBRAM_SCOREBOARD_SV
`define RKV_AHBRAM_SCOREBOARD_SV
 
class rkv_ahbram_scoreboard extends rkv_ahbram_subscriber;
 
  // events of scoreboard
 
  // typedef enum {CHECK_LOADCOUNTER} check_type_e;
  `uvm_component_utils(rkv_ahbram_scoreboard)
 
  function new (string name = "rkv_ahbram_scoreboard", 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);
    super.run_phase(phase);
    do_data_check();
  endtask
 
  task do_listen_events();
  endtask
 
  virtual task do_data_check();
  endtask
endclass
 
`endif 

最后为环境env,需要例化整个验证环境中的组件:master_agent、rkv_config、virtual_sequencer、rgm、adapter、predictor、cov、scoreboard。并将在env中从上一级set下来的配置文件cfg再set到其所例化的组件中去(cov、scb:后续比对过程中对比对的count以及错误的count次数需要加一修改、virt_sqr)。还要在connent_phase中进行连接。将virtual_sequencer中例化的lvc的sequencer连接起来(lvc的master_sequencer已经开辟好空间,virtual中声明句柄,需要连接),寄存器模型的连接(vip中的架构,此验证中不涉及到寄存器模型,不用太在意);将monitor的输出的port与需要数据的地方的port连接起来;打印最后的比对报告。

 
`ifndef RKV_AHBRAM_ENV_SV
`define RKV_AHBRAM_ENV_SV
 
class rkv_ahbram_env extends uvm_env;
 
  lvc_ahb_master_agent ahb_mst;
  rkv_ahbram_config cfg;
  rkv_ahbram_virtual_sequencer virt_sqr;
  rkv_ahbram_rgm rgm;
  rkv_ahbram_reg_adapter adapter;
  uvm_reg_predictor #(lvc_ahb_transaction) predictor;
  rkv_ahbram_cov cov;
  rkv_ahbram_scoreboard scb;
 
  `uvm_component_utils(rkv_ahbram_env)
 
  function new (string name = "rkv_ahbram_env", uvm_component parent);
    super.new(name, parent);
  endfunction
 
  function void build_phase(uvm_phase phase);
    super.build_phase(phase);
    // Get configuration from test layer
    if(!uvm_config_db#(rkv_ahbram_config)::get(this,"","cfg", cfg)) begin
      `uvm_fatal("GETCFG","cannot get config object from config DB")
    end
    uvm_config_db#(rkv_ahbram_config)::set(this, "virt_sqr", "cfg", cfg);
    uvm_config_db#(rkv_ahbram_config)::set(this, "cov", "cfg", cfg);
    uvm_config_db#(rkv_ahbram_config)::set(this, "scb", "cfg", cfg);
    uvm_config_db#(lvc_ahb_agent_configuration)::set(this, "ahb_mst", "cfg", cfg.ahb_cfg);//config的set都在env
    ahb_mst = lvc_ahb_master_agent::type_id::create("ahb_mst", this);
    virt_sqr = rkv_ahbram_virtual_sequencer::type_id::create("virt_sqr", this);
    if(!uvm_config_db#(rkv_ahbram_rgm)::get(this,"","rgm", rgm)) begin
      rgm = rkv_ahbram_rgm::type_id::create("rgm", this);
      rgm.build();
    end
    uvm_config_db#(rkv_ahbram_rgm)::set(this,"*","rgm", rgm);//set rgm?
    adapter = rkv_ahbram_reg_adapter::type_id::create("adapter", this);
    predictor = uvm_reg_predictor#(lvc_ahb_transaction)::type_id::create("predictor", this);
    cov = rkv_ahbram_cov::type_id::create("cov", this);
    scb = rkv_ahbram_scoreboard::type_id::create("scb", this);
  endfunction
 
  function void connect_phase(uvm_phase phase);
    super.connect_phase(phase);
    virt_sqr.ahb_mst_sqr = ahb_mst.sequencer;
    rgm.map.set_sequencer(ahb_mst.sequencer, adapter);//??
    ahb_mst.monitor.item_observed_port.connect(predictor.bus_in);
    predictor.map = rgm.map;
    predictor.adapter = adapter;
    ahb_mst.monitor.item_observed_port.connect(cov.ahb_trans_observed_imp);
    ahb_mst.monitor.item_observed_port.connect(scb.ahb_trans_observed_imp);
  endfunction
 
  function void end_of_elaboration_phase(uvm_phase phase);
    super.end_of_elaboration_phase(phase);
  endfunction
 
  function void report_phase(uvm_phase phase);
    string reports = "\n";
    super.report_phase(phase);
    reports = {reports, $sformatf("=============================================== \n")};
    reports = {reports, $sformatf("CURRENT TEST SUMMARY \n")};
    reports = {reports, $sformatf("SEQUENCE CHECK COUNT : %0d \n", cfg.seq_check_count)};
    reports = {reports, $sformatf("SEQUENCE CHECK ERROR : %0d \n", cfg.seq_check_error)};
    reports = {reports, $sformatf("SCOREBOARD CHECK COUNT : %0d \n", cfg.scb_check_count)};
    reports = {reports, $sformatf("SCOREBOARD CHECK ERROR : %0d \n", cfg.scb_check_error)};
    reports = {reports, $sformatf("=============================================== \n")};
    `uvm_info("TEST_SUMMARY", reports, UVM_LOW)
  endfunction
 
endclass 
`endif // RKV_AHBRAM_ENV_SV

完善lvc_master_agent:创建monitor、sequencer、driver等组件

`ifndef LCV_AHB_MASTRE_AGENT_SV
`define LCV_AHB_MASTRE_AGENT_SV
class lvc_ahb_master_agent extends uvm_agent;
	`uvm_component_utils(lvc_ahb_master_agent);

	// 创建组件
	lvc_ahb_agent_configuration cfg;
	lvc_ahb_master_driver driver;
	lvc_ahb_master_monitor monitor;
	lvc_ahb_master_sequencer sequencer;


	virtual lvc_ahb_if vif;
	function new(string name = "lvc_ahb_master_agent", uvm_component parent);
		super.new(name,parent);
	endfunction

    // cfg 来自env中的set,得到的是lvc的cfg,需要is_avtive信号判断是否需要例化driver和sequencer
	function void build_phase(uvm_phase phase);
		super.build_phase(phase);
		if(!uvm_config_db#(lvc_ahb_agent_configuration)::get(this,"","cfg",cfg)) begin
			`uvm_fatal("GETCFG","cannot get config object fraom config DB");
		end
		if(!uvm_config_db#(virtual lvc_ahb_if)::get(this,"","vif", vif)) begin
     		`uvm_fatal("GETVIF","cannot get vif handle from config DB")
   		end

		monitor  = lvc_ahb_master_monitor::type_id::create("monitor",this);
		if(cfg.is_active) begin
			driver = lvc_ahb_master_driver::type_id::create("driver",this);
			sequencer = lvc_ahb_master_sequencer::type_id::create("sequencer",this);
		end

	endfunction

	// 将driver与sequencer连接起来,并将interface与monitor的driver的sequencer的interface连接起来
	function void connect_phase(uvm_phase phase);
	  super.connect_phase(phase);
	  monitor.vif = vif;
	  if(cfg.is_active) begin
	  	  driver.seq_item_port.connect(sequencer.seq_item_export);
		  driver.vif = vif;
          sequencer.vif = vif;
	  end
	endfunction
		
	task run_phase(uvm_phase phase);
	  super.run_phase(phase);
	endtask
endclass
`endif

最后还需要seq以及test文件:seq_lib文件夹下创建rkv_ahbram_base_virtual_sequence,这是一个virtual sequence,是sequence的组合,其中声明了compare函数后续可以做比对,并声明了p_sequencer为rkv_ahbram_virtual_sequencer,说明后续产生的sequence会挂载到virtual_sequencer上,而由于在env的connet_phase中将virahb_master_sequencer与ahb_master_sequencer连接到了一起,所以sequence会发送到lvc的sequencer上去,最后被driver get到。

`ifndef RKV_AHBRAM_BASE_VIRTUAL_SEQUENCE_SV
`define RKV_AHBRAM_BASE_VIRTUAL_SEQUENCE_SV
 
class rkv_ahbram_base_virtual_sequence extends uvm_sequence;
 
  rkv_ahbram_config cfg;
  virtual rkv_ahbram_if vif;
  rkv_ahbram_rgm rgm;
  bit[31:0] wr_val, rd_val;
  uvm_status_e status;//?
  `uvm_object_utils(rkv_ahbram_base_virtual_sequence)
  `uvm_declare_p_sequencer(rkv_ahbram_virtual_sequencer)
 
  function new (string name = "rkv_ahbram_base_virtual_sequence");
    super.new(name);
  endfunction
 
  virtual task body();
    `uvm_info("body", "Entered...", UVM_LOW)
    // get cfg from p_sequencer
    cfg = p_sequencer.cfg;//?
    vif = cfg.vif;
    rgm = cfg.rgm;
    // TODO in sub-class
    `uvm_info("body", "Exiting...", UVM_LOW)
  endtask
 
  virtual function void compare_data(logic[31:0] val1, logic[31:0] val2);//?
    cfg.seq_check_count++;
    if(val1 === val2)
      `uvm_info("CMPSUC", $sformatf("val1 'h%0x === val2 'h%0x", val1, val2), UVM_LOW)
    else begin
      cfg.seq_check_error++;
      `uvm_error("CMPERR", $sformatf("val1 'h%0x !== val2 'h%0x", val1, val2))
    end
  endfunction
 
  task wait_reset_signal_assertted();
      @(posedge vif.rstn);
  endtask
 
  task wait_reset_signal_released();
      @(negedge vif.rstn);
  endtask
 
endclass
 
`endif  

在seq_lib文件夹下的 rkv_ahbram_seq_lib中存放sequence的lib

`ifndef RKV_AHBRAM_SEQ_LIB_SVH
`define RKV_AHBRAM_SEQ_LIB_SVH

`include "rkv_ahbram_base_virtual_sequence.sv"
`endif

base_test文件:

`ifndef RKV_AHBRAM_BASE_TEST_SV
`define RKV_AHBRAM_BASE_TEST_SV
 
virtual class rkv_ahbram_base_test extends uvm_test;
 
  rkv_ahbram_config cfg;
  rkv_ahbram_env env;
  rkv_ahbram_rgm rgm;
 
  function new (string name = "rkv_ahbram_base_test", uvm_component parent);
    super.new(name, parent);
  endfunction
 
  function void build_phase(uvm_phase phase);
    super.build_phase(phase);
    rgm = rkv_ahbram_rgm::type_id::create("rgm");//rgm的创建在test中
    rgm.build();
    uvm_config_db#(rkv_ahbram_rgm)::set(this, "env", "rgm", rgm);
    cfg = rkv_ahbram_config::type_id::create("cfg");//config的创建
    cfg.rgm = rgm;
    if(!uvm_config_db#(virtual rkv_ahbram_if)::get(this,"","vif", cfg.vif))
      `uvm_fatal("GETCFG","cannot get virtual interface from config DB")
    uvm_config_db#(rkv_ahbram_config)::set(this, "env", "cfg", cfg);
    env = rkv_ahbram_env::type_id::create("env", this);
  endfunction
 
  function void connect_phase(uvm_phase phase);
    super.connect_phase(phase);
  endfunction
 
  task run_phase(uvm_phase phase);
    super.run_phase(phase);
    phase.phase_done.set_drain_time(this, 1us);
    phase.raise_objection(this);
    phase.drop_objection(this);
  endtask 
endclass
`endif

到此为止,整个最基本的框架就已经搭建好了。后续对框架内的内容进行完善。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值