其他分享
首页 > 其他分享> > 寄存器模型(RAL,Register Abstraction Layer)——UVM

寄存器模型(RAL,Register Abstraction Layer)——UVM

作者:互联网

文章目录

一、寄存器模型的背景

寄存器的作用:例如在一个ALU模块中可以通过配置不同类型的register model来改变使用什么类型的算法。

1.1 寄存器模型的背景

如果不适用UVM RAL的验证平台

class master_sequence extends uvm_sequence #(transaction);
  virutual taks body();
    `uvm_do_with(req,{ addr == 'h110;data == `1;kind == transaction::WRITE;});
    `uvm_do_with(req,{addr == 'h120;kind == transaction::READ;});...;
  endtask
endclass
class master_sequence extends uvm_reg_sequene#(uvm_sequence#(transaction));
  virtual taks body();
    uvm_status_e status;
    uvm_reg_data_t data;
    regmodel.INFO.read(status,data,UVM_BACKDOOR,.parent(this));
    regmodel.INFO.write(status,55,'1,UVM_FRONTDOOR,.parent(this));
  endtask
endclass

1.2 访问寄存器模型方式

访问方式说明
前门访问通过模拟cpu在总线上发出读指令,进行读写操作。在这个过程中,仿真时间($time函数得到的时间)是一直往前走的。
后门访问直接通过寄存器所在的hierarchy path来直接访问寄存器,不需要消耗时间。

在这里插入图片描述

1.3 寄存器模型基本概念

寄存器模型的组成:

寄存器模型的相关类及功能
在这里插入图片描述

类名功能
uvm_reg_field用来针对寄存器功能域来构建对应的比特位
uvm_reg与寄存器相匹配,其内部可以例化和配置多个uvm_reg_field对象
uvm_mem匹配硬件存储模型
uvm_reg_map用来指定寄存器列表中各个寄存器的偏移地址、访问属性以及对应的总线 ,并将其转换成可以访问的物理地址(因为寄存器模型中的地址一般都是偏移地址,而不是绝对地址)
uvm_reg_block可以容纳多个寄存器(uvm_reg)、存储器(uvm_mem)和寄存器列表(uvm_reg_map)

在这里插入图片描述

1.4 寄存器模型建模要点和顺序

class ctrl_reg extends uvm_reg;
    `uvm_object_utils(ctrl_reg)
    uvm_reg_field reserved;
    ...
     function new(string name = "ctrl_reg");
      super.new(name, 32, UVM_NO_COVERAGE);//实例化reg时的,32位的,无覆盖的
    endfunction
    virtual function build();
    //1、创建和实例化
      reserved = uvm_reg_field::type_id::create("reserved"); 
    //2、对该域进行参数配置参 
    reserved.configure(this, 26, 6, "RO", 0, 26'h0, 1, 0, 0);   
   ...
 endclass
new中的标识说明
UVM_NO_COVERAGEno coverage models,不收集覆盖率
UVM_CVR_REG_BITScoverage models for the bits read or written in registers
UVM_CVR_ADD_MAPcoverage models for the addresses read or written in an address map
UVM_CVR_FIELD_VALScoverage models for the values of fields
UVM_CVR_ALLAll coverage models
class mcdf_rgm extends uvm_reg_block;
    `uvm_object_utils(mcdf_rgm)
    rand ctrl_reg chnl0_ctrl_reg;
    ...
    function new(string name = "mcdf_rgm");
      super.new(name, UVM_NO_COVERAGE);//这里的不需要位宽
    endfunction
    virtual function build();
    //1、容纳uvm_reg_block
      chnl0_ctrl_reg = ctrl_reg::type_id::create("chnl0_ctrl_reg");
      chnl0_ctrl_reg.configure(this);//2、进行配置各个uvm_reg实例,将 uvm_reg 关联到 uvm_reg_block 上
      chnl0_ctrl_reg.build();//3、手动调用 uvm_reg 的build(),实例化reg中的各个域
    //容纳uvm_reg_map
     // map name, offset, number of bytes, endianess
     //default_map = creat_map("default_map",0,2,UVM_LITTLE_ENDIAN);//缺省default_map只需要在系统里实例化调用create_map
      map = create_map("map", 'h0, 4, UVM_LITTLE_ENDIAN);//实例化map
     //配置map
     //map.configure(this,null,"map”);
      map.add_reg(chnl0_ctrl_reg, 32'h00000000, "RW");//将 uvm_reg 添加到 map 中
      ...
      //lock_model( ),不允许外部对这个寄存器模型做访问;

二、寄存器模型与验证环境的集成

2.1 寄存器模型与DUT桥接

在这里插入图片描述

2.2 adapter作用

因为adapter的上层(UVM的寄存器模型transaction)与下层(总线DUT,例如不同的总线有不同的sequence item)的标准不同,它们不能共用,这里就是adapter去协调它们的沟通。

uvm_reg_bus_op类成员

typedef struct{
  uvm_access_e      kind;
  uvm_reg_addr_t    addr;
  uvm_reg_data_t    data;
  int               n_bits;
  uvm_reg_byte_en_t byte_en;
  uvm_status_e      status;
}uvm_reg_bus_op
class reg2apb_adapter extends uvm_reg_adapter;
  `uvm_object_utils(reg2apb_adapter)

  virtual function uvm_sequence_item reg2bus(const reg uvm_reg_bus_op rw);
    apb_trans tr = apb_trans::type_id::create("tr");
    tr.read = (rw.kind == UVM_READ)?1:0;
    tr.addr = rw.addr;
    tr.data = rw.data;
    return tr;
  endfunction

  virtual function void bus2reg(uvm_sequence_item bus_item,reg uvm_reg_bus_op rw);
    apb_trans tr;
    if(!$cast(tr,but_item)begin
      `uvm_fatal("NOT_APB_TYPE","Provided bus_item is not apb_trans type")
      return;
    end
    rw.status = UVM_IS_OK;
    rw.kind   = tr.read?UVM_READ:UVM_WRITE;
    rw.addr   = tr.addr;
    rw.data   = tr.data;
  endfunction
endclass

2.3 adapter与寄存器模型集成

adapter、sequencer、map三者的关系,首先需要在环境(一般在env层次时)需要连接三者通过map.set_sequencer(squencer, adapter)
因为本身regmodel充当sequence,adapter充当转换的桥梁,而regmodel中因为有lock_model只有Map能访问内部reg的field,而对于传到bus上也需要用bus的sequencer进行和drv的传递,所以三者是要关联的,这样adapter才能工作。

class base_test extends uvm_test;
  `uvm_component_utils(base_test)
  my_block rm;//reg_block
  reg2apb_adapter reg_sqr_adapter;

  function new(string name = "base_test",uvm_component parent = null);
      super.new(name,parent);
  endfunction

  virtual function void build_phase(uvm_phase phase);
      super.build_phase(phase);
      rm = my_block::type_id::create("rm",this);
      rm.configure(null,"");
      rm.build();
      rm.lock_model();
      rm.reset();
      reg_sqr_adapter = new("reg_sqr_adapter");
  endfunction
endclass  
//connect_phase
function void top_env::connect_phase(uvm_phase phase);
	rm.map.set_sequencer(env.agt.sqr,adapter);//将 map 与 sequencer 和 adapter 连接
endfunction

三、访问寄存器地不同方式

3.1 前门访问

在寄存器模型上做的读写操作,通过bus实现bus上的物理时序访问,是真实地物理操作

class apb_seq extends uvm_reg_sequence;
  apb_rgm rgm;
  `uvm_object_utils(apb_seq)
  `uvm_declare_p_sequncer(apb_bus_sequencer0
  ...
  task body();
    uvm_status_e status;
    uvm_reg_data_t data;
    if(!uvm_config_db#(apb_rgm)::get(null,get_full_name(),"rgm",rgm))begin
        `uvm_errror("GETGM","no top-down RGM handle is assigned")
    end
    // 第一种register model access write()/read()
      rgm.chnl0_ctrl_reg.read (status, data, UVM_FRONTDOOR, .parent(this));
      rgm.chnl0_ctrl_reg.write(status, 'h11, UVM_FRONTDOOR, .parent(this));
      rgm.chnl0_ctrl_reg.read (status, data, UVM_FRONTDOOR, .parent(this));
      //第二种 pre-defined methods access
      read_reg (rgm.chnl1_ctrl_reg, status, data, UVM_FRONTDOOR);
      write_reg(rgm.chnl1_ctrl_reg, status, 'h22, UVM_FRONTDOOR);
      read_reg (rgm.chnl1_ctrl_reg, status, data, UVM_FRONTDOOR);
      #1us;
    endtask
  endclass

有两种方式实现前门访问

  1. uvm_reg::read()/write():在传递时,用户需要注意将参数path指定为UVM_FRONTDOOR。uvm_reg::read()/writer()方法可传入地参数较多,处理status和value两个参数需要传入,其他参数如果不指定,可采用默认值。
  2. uvm_reg_sequence::read()/write_reg(),在使用时也需要将path设置为UVM_FRONTDOOR

3.2 后门访问

后门访问,就是不经过DUT的接口总线,可以直接对DUT的寄存器值进行操作,类似于“走后门”。System verilog提供了这种接口,叫做DPI。跟前门访问相比,多了几步:

  1. 要在reg model中通过set_hdl_path_root加入后门访问的绝对路径,通常寄存器定义都放在这个路径下;
  2. configure函数中参数加入寄存器名字;
  3. 访问方式改为UVM_BACKDOOR。
class base_test extends uvm_test;
  `uvm_component_utils(base_test)

  apb_environment   apb_env;
  virtual_sequencer v_sqr;
  scoreboard        sb;
  reg_model         rm;
  apb_reg_adapter   adapter;

  function new(string name = "base_test",uvm_component parent  = null);
    super.new(name,parent);
  endfunction

  virtual function void build_phase(uvm_phase phase);
      super.build_phase(phase);
      apb_env = apb_environment::type_id::create("apb_env",this);
      v_sqr   = virtaul_sequencer::type_id::create("v_sqr",this);
      sb = scorboard::type_id::create("sb",this);

      rm = reg_model::type_id::create("rm",this);//创建一个reg_block,然后指定容器是env
      rm.configure(null,"");
      rm.bulid();
      rm.lock_model();
      rm.reset();
      rm.set_hdl_path_root("top.dut.regblock");//设置后面基访问路径
      adapter = new("adapter");
  endfunction
  virtual function void connect_phase(uvm_phase phase);
      super.connect_phase(phase);
      v_sqr.mst_sqr = apb_env.mst_agt.sqr;
      apb_env.mst_agt.mon.apb_mon_port.connect(sb.mst_imp);

      v_sqr.p_rm = this.rm;//在virtual sequence种定义
      rm.default_map.set_sequencer(apb_env.mst_agt.sqr,adapter);
      rm.default_map.set_auto_predict(1);
  endfunction
endclass

四、实现RAL的六个步骤

4.1 不使用RAL,只是创建和验证前门,比如使用driver

//========================transaction==============
//事物数据建模中说明数据的操作、地址、数据和状态
class transaction extends uvm_sequence_item;
  ...
  typedef enum int unsigned{READ,WRITE}kind_e;
  rand kind_e kind;
  status_e status;
  rand bit [15:0]addr,data;
endclass
//========================transaction==============
class master_driver extends uvm_driver#(transaction);
 ..
 task run_phase(uvm_phase phase);
   forever begin
     seq_item_port.get_next_item(req);
     wr_data(req);
     seq_item_port.item_done();
   end
 endtask
 ...
endclass
//========================sequence==============
//在seuquence中使用硬编码的方式,编写地址,并通过uvm_do的操作方式,进行读写操作
class bsm_sequence extends uvm_sequence#(transaction);
  ...
  task body();
    `uvm_do_with(req,{addr == 'h000;kind == transactiion::READ;});
    `uvm_do_with(req,{addr == 'h000;data == '1;kind == transactiion::READ;});
    `uvm_do_with(req,{addr == 'h100;kind == transactiion::READ;});
    if(starting_phase != null)
      starting_phase.drop_objection(this);
 endtask
enclass 
//========================agent==============
class master_agent extends uvm_agent;
  typedef uvm_sequencer#(transaction) master_sequncer;
  master_driver drv;
  master_monitor mon;
  master_sequencer sqr;
endclass
//========================env==============
class master_env extends uvm_env;
  master_agent m_agent;
  function void build_phase(uvm_phase phase);
      super.build_phase(phase);
      uvm_config_db#(uvm_object_wrapper)::set(this,
                                             "m_agent.srq.configure_phase",
                                             "default_sequence",
                                             bfm_sequence::get_type());
  endfunction
endclass
//========================base_test==============
//需要看波形,看下是否是期望值
class base_test extends uvm_test;
  master_env m_env;
  function void build_phase (phase);
       `uvm_config_db#(virtual master_io)::set(this,
                                              "m_env.m_agent",
                                              "mater_io",DUV_test_top.master);
 endfunction
endclass

4.2 使用寄存器模型文件(.ralf)描述寄存器字段

使用VCS

4.3 使用RAL generator(ralgen)生成RAL类;

使用VCS

4.4 创建RAL适配器(adapter)

见上面

4.5 在验证环境中实例化RAL模型

//==============================RAL寄存器sequence=========================
class master_ral_sequence extends uvm_reg_sequence#(master_sequence_base);
  ral_block_master_regmodel regmodel;
  virtual task pre_start();
    super.pre_start();//raise_objection code;
    uvm_config_db#(ral_block_master_regmodel)::get(get_suequencer(),
                                                  "",
                                                  "regmodel",
                                                  regmodel);
  endtask
  virtual task body();
    regmodel.INFO.read(status,data,.parent(this));//can specify path
    regmodel.INT.write(status,8,'1,.parent(this));//default to frontdoor
  endtask
endclass                               
//==============================在验证环境中例化RAL=========================
class master_env extends uvm_env;
  master_agent m_agent;
  ral_block_master_regmodel regmodel;
  virtual function void build_phase(uvm_phase phase);
      super.build_phase(phase);
      uvm_config_db#(ral_block_master_regmodel)::get(this,
                                                     "",
                                                     "regmodel",
                                                     regmodel);
      if(regmodel == null)begin
        string hdl_path;
        //1、创建寄存器实例化
        regmodel = ral_block_master_regmodel::type_id::create("regmodel",this);
        //2、创建UVM寄存器层次,注意没有使用build_phase()
        regmodel.build();
        //3、锁定寄存器的层次结构并创建地址映射
        regmodel.info_model();
        //4、
        if(!uvm_resource_db#(string)::read_by_name("master_regmodel", 
                                                   "hdl_path",
                                                   hdl_path,
                                                   this))
           regmodel.set_hdl_path_root(hdl_path);
        else 
          `uvm_warning("master_regmodel","Master XMR path is not set")
        //5、为sequence设置寄存器模型
        uvm_config_db#(ral_block_master_regmodel)::set(this,
                                                      "m_agent_sqr",
                                                      "regmodel",
                                                      regmodel);
       end
   endfunction                                                                                                                                             

4.6 编写并运行RAL的测试序列

class base_test extends uvm_test;
  master_env env;
  virtual function void build_phase(uvm_phase phase);
    //super.build_phase and component construction not shown
    uvm_config_db#(string)::set(this,"m_env","hdl_path","DUT_test_top.duv");
  endfunction
  virtual task configure_phase(uvm_phase phase);
      super.configure_phase(phase);
      master_ral_sequence master_seq;
      master_seq = master_ral_sequence::type_id::create("master_seq");
      master_seq.regmodel = m_env.regmodel;
      master_seq.start(null);
  endtask
endclass
class test_ral_base extends base_test;
  virtual function void build_phase(uvm_phase phase);
      uvm_resource_db#(string)::set("master_regmodel","hdl_path","master_test_top.duv",this);
  endfunction
endclass
//======================隐式执行RALsequence==============
class test_ral_implicit extends test_ral_base;
  virtual function void configure_phase(phase);
      uvm_config_db#(uvm_object_wrapper)::set(this,"*.seqr.configure_phase","default_sequence",master_ral_sequence::get_type());
  endfunction
endclass
//======================显式执行RALsequence==============
class test_ral_explicit extends test_ral_base;
  virtual function void configure_phase(uvm_phase phase);
    master_ral_sequence m_sqe;
    phase.raise_objection(this);
    m_seq = master_ral_sequence::type_id::create("m_seq",this);
    m_seq.start(env.m_agent.seqr);
    phase.drop_objection(this);
  endfunctio
endclass 

4.6.3 UVM RAL sequences

在这里插入图片描述

当使用后门访问寄存器时,sequence依赖于寄存器mirror值的更新

sequence namedescription
uvm_reg_hw_reset_seq测试寄存器的硬复位值
uvm_reg_bit_bash_seq所有寄存器比特网
uvm_reg_access_seq验证所有寄存器的操作属性
uvm_mem_walk_seq使用遍历算法验证寄存器
uvm_mem_access_seq使用前门访问或者后门访问方式验证寄存器的读写操作
uvm_reg_mem_build_in_seq运行所有寄存器和存储器的测试用例
uvm_reg_mem_hdl_paths_seq验证寄存器和存储器的层次化路径
uvm_reg_mem_shared_access_seq验证共享寄存器和存储器的读写操作

加粗为常见

4.6.4 UVM RAL 隐式执行镜像预测

//======================隐式执行镜像预测==============
//当对寄存器进行读写操作时,更新寄存器的镜像值,自动调用读写操作更新镜像值,不需要自己编写代码
//镜像值的更新时序不一定是精确到时钟周期,DUT内部的更改可能不会影响镜像值
class environment extends uvm_env;
  virtual function void connect_phase(uvm_phase phase);
    regmodel.default_map.set_auto_predict(1);
  endfunction
endclass

4.6.5 在sequence中使用auto predict来运行RAL的测试案例

class test_ral extends test_base;
  string seq_name="uvm_reg_bit_bash_seq";
  uvm_reg_sequence selftest_seq;
  virtual reset_sequence rst_seq;
  virtual function void build_phase(uvm_phase phase);
      super.build_phase();
      uvm_config_db#(uvm_object_wrapper)::set(this,
                                             "*",
                                             "default_sequence",
                                             null);
  endfunction
  virtual task run_phase(uvm_phase phase);
      rst_seq = virtual_reset_sequence::type_id::create("rst_seq",this);
      phase.raise_objection(this,"starting test");
      v_reset_req.start(env.v_reset_seqr);//run reset
      clp.get_arg_value("+seq=",seq_name);//能够调用之前自定义的seq
      $cast(selftest_seq,factory.create_object_by_name(seq_name));//create test
      env.regmodel.default_map.set_auto_predict(1);//enable auto predict if not done in env
      selftest_seq.start(env.m_agent.seqr);//run test
      phase.drop_objection(this,"Done with tests");
  endtask
endclass                                                                                                  

还可以通过命令行的方式实现

+UVM_TESTNAME=test_ral+seq=uvm_reg_hw_reset_seq

4.6.6 显示执行镜像预测

在这里插入图片描述

class environment extends uvm_env;
  typedef uvm_reg_predict#(master_data)mreg_predictor;
  mreg_predictor mreg_predict;
  virtual function void build_phase(uvm_phase phase);
      mreg_predict = mreg_predictor::type_id::create("mreg_predict",this);
  endfunction
  virtual function void connect_phase(uvm_phase phase);
    mreg_predict.map = regmodel.get_default_map();
    mreg_predict.adapter = adapter;
    regmodel.default_map.set_auto_predict(0);
    m_agent.analysis_port.connect(mreg_predict.bus_in);
  endfunction
endclass

4.6.7 RAL test case显示执行镜像预测

class test_ral extends test_base;
//code identical to auto predict test is left off
  virtual task run_phase(uvm_phase phase);
      phase.raise_objection(this,"starting reset test");
      v_reset_seq = virtual_reset_sequence::type_id::create("v_reset_seq",this);
      v_reset_seq.start(env.v_reset_seqr);
      clp.get_arg_value("+seq=",seq_name);
      $cast(selftest_seq,factory.create_objection_by_name(seq_name));
      env.regmodel.default_map.set_auto_predict(0);//这个可以省略
      env.regmodel.default_map.set_auto_predict(1);//enable auto predict if not done in env
      selftest_seq.start(env.m_agent.seqr);//run test
      phase.drop_objection(this,"Done with tests");
    endtask
endclass
//================例化UVM内建test_case进行自动测试
class hw_reset extends test_base;
  reset_sequence reset_seq;
  uvm_reg_hw_reset_seq reset_test;
  virtual task run_phase(uvm_phase phase);
      phase.raise_objection(this,"starting register test");
      reset_seq = reset_sequence::type_id::create("reset_seq",this);
      reset_seq.start(env.reset_seqr);
      //创建并运行test_case
      reset_test = uvm_reg_hw_reset_seq::type_id::create("reset_test",this);
      reset_test.model = env.regmodel;
      reset_test.model.set_auto_predict(1);
      reset_test.start(null);
      phase.drop_objection(this,"Done with register test");
  endtask
endclass  

标签:Layer,Abstraction,seq,Register,test,uvm,寄存器,phase,reg
来源: https://blog.csdn.net/weixin_42705678/article/details/122461344