C/C++教程

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

本文主要是介绍寄存器模型(RAL,Register Abstraction Layer)——UVM,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

文章目录

    • 一、寄存器模型的背景
      • 1.1 寄存器模型的背景
      • 1.2 访问寄存器模型方式
      • 1.3 寄存器模型基本概念
      • 1.4 寄存器模型建模要点和顺序
    • 二、寄存器模型与验证环境的集成
      • 2.1 寄存器模型与DUT桥接
      • 2.2 adapter作用
      • 2.3 adapter与寄存器模型集成
    • 三、访问寄存器地不同方式
      • 3.1 前门访问
      • 3.2 后门访问
    • 四、实现RAL的六个步骤
      • 4.1 不使用RAL,只是创建和验证前门,比如使用driver
      • 4.2 使用寄存器模型文件(.ralf)描述寄存器字段
      • 4.3 使用RAL generator(ralgen)生成RAL类;
      • 4.4 创建RAL适配器(adapter)
      • 4.5 在验证环境中实例化RAL模型
      • 4.6 编写并运行RAL的测试序列
        • 4.6.3 UVM RAL sequences
        • 4.6.4 UVM RAL 隐式执行镜像预测
        • 4.6.5 在sequence中使用auto predict来运行RAL的测试案例
        • 4.6.6 显示执行镜像预测
        • 4.6.7 RAL test case显示执行镜像预测

一、寄存器模型的背景

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

1.1 寄存器模型的背景

  • 寄存器的作用 通常情况下能够通过寄存器进行配置硬件中的各个模块的功能和访问状态,并且处理器之间的交互是通过寄存器读写实现的。
  • 读取寄存器的困难 :在没有寄存器模型之前,只能启动sequence通过**前门(FRONTDOOR)**访问的方式来读取寄存器,局限较大,在 scoreboard(或者其他component)中难以控制。
  • 寄存器模型解决了读取寄存器的困难 1)scoreboard只与寄存器模型打交道,无论是发送读的指令还是获取读操作的返回值,都可以由寄存器模型完成。 2)访问方式:可以在任何耗费时间的phase中使用寄存器模型以前门访问或后门(BACKDOOR)访问的方式来读取寄存器的值,同时还能在某些不耗费时间的phase(如check_phase)中使用后门访问的方式来读取寄存器的值。

如果不适用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
  • 地址硬编码字段名位置,执行状态位置,只能够执行前门访问。
    如果使用了UVM RAL的验证平台
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_block)由包含很多的寄存器(uvm_reg),也可以有存储器(uvm_mem);
  • 每个寄存器(uvm_reg)都由很多的域(uvm_reg_field)组成;
  • 单个域(uvm_reg_filed)包含多个bit位。
  • 寄存器模型相关类(均为Object类型)

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

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

在这里插入图片描述

  • reserved表示该域包含的比特位暂时保留以后作为日后功能的扩展使用,而对保留域的读写不起任何作用

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
  • uvm_reg_field要在创建和实例化之后,还要在 uvm_reg 中调用configure( )函数对该域进行参数配置。其中:第一个参数指定关联到的寄存器uvm_reg;第二个参数是位数长,第三个是起点位,第四个为访问属性(RW、RO等),第五个为是否volatile,第六个为上电复位后的默认值,第七个为是否可以复位(一般都可以复位,为1),第八个表示是否可以随机化,第九个表示是否可以单独存取。
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( ),不允许外部对这个寄存器模型做访问;
  • uvm_reg_block uvm_reg_block可以用来容纳多个uvm_reguvm_mem实例,map的作用一方面是用来表示寄存器和存储对应的偏移地址,同时由一个reg_block包含的多个reg_map,各个map可以分别对应不同的总线或地址段。在reg_block中创建各个uvm_reg之后,需要调用uvm_reg::configure()去配置各个uvm_reg实例的属性。由于它能够对更大地系统做寄存器建模,这意味着uvm_reg_block之间可能存在层次关系。

  • uvm_reg_map也会在uvm_reg_block中例化,在例化之后通过uvm_reg_map::add_reg()函数来添加各个uvm_reg对应的偏移地址和访问属性。只有这样才能正确地通过前门访问给出正确地地址;
  • create_map 1)name;2)基地址;3)系统总线宽度(byte);4)大小端;
  • configure 1)block_parent;2)regfile_parent;3)hdl_path,执行后门访问时,路径是由block+reg两个部分组成的;
  • add_reg 1)加入的寄存器;2)寄存器地址;3)map中的寄存器的读取方式;

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

2.1 寄存器模型与DUT桥接

在这里插入图片描述

  • 寄存器模型(而不是总线序列)将带有寄存器的相关信息存放在uvm_reg_item实例中,送往adapter;
  • adapter接收到uvm_reg_item实例之后,从中抽取DUT所需的信息,同时生成DUT需要的bus_seq_item类型。在完成数据内容读取和二次写入之后,bus_seq_item送往DUT;
  • DUT从bus_seq_item获取地址、数据、操作模式等信息后开始对DUT进行读写访问。如果DUT上由反馈信号标识访问是否成功,则该标识应当由总线sequencer按照response item的路径返回至adapter,adapter对反馈信号做出处理。在反馈路径在读访问时也会将总线读回的数据返回至adapter,并最终作为返回值交回到寄存器操作有关的方法;

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
  • addr :地址,默认64位
  • data:读写数据,默认64位;
  • uvm_access_e :UVM_READ,UVM_WRITE,UVM_BURST_READ,UVM_BURST_WRITE
  • n_bits : 传输value的bit数
  • byte_en: 需要总线支持字节使能
  • status : 事务的结果,UVM_IS_OK,UVM_HAS_X,UVM_NOT_OK
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
  • reg2bus()bus2reg()两个函数实现了uvm_reg_bus_op与DUT在各自的数据transaction映射。
  • reg2bus()完成的桥接场景是如果用户在寄存器级别做了操作,那么寄存器级别的操作信息uvm_reg_bus_op会被记录,同时调用uvm_reg_adapter::reg2bus()函数。在完成uvm_reg_bus_op的信息映射到apb_trans之后,函数将apb_trans实例返回。
  • 在返回apb_trans之火,该实例通过bus_sequencer传入到bus_driver。这里的transaction传输是后台隐式调用的,不需要自己发起;
  • 寄存器无论读写都应该知道总线操作后的状态返回,读操作也需要总线返回的读数据,因此uvm_reg_adapter::bus2reg()是从bus_driver()将数据写回至bus_sequencer,而一直保持监听的。

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
  • 对于寄存器模型的集成,一般倾向于从顶层传递的方式,即最终从test层传入寄存器模型句柄;
  • 寄存器模型在创建之后,要显式的调用build函数,因为uvm_reg_block是object类型,build函数并不会自动执行;
  • 顶层环境的connect_phase 阶段,需要通过uvm_reg_map::set_sequencer(“bus sequencer句柄”,“adapter句柄”)的方式,将寄存器模型的map组件与bus sequencer和adapter连接,这会将map(寄存器信息)、sequencer(总线侧激励驱动)和 adapter(寄存器级别和硬件总线级别的桥接)关联在一起。只有通过这一步,才能完成adapter的桥接功能。

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

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
  • uvm_reg::read()/write(),调用该方法要注明使用UVM_BACKDOOR地访问方式
  • uvm_reg::sequence::read_reg()/write_reg();
  • uvm_reg::peek()/poke(),对应了读取寄存器(peek)和修改寄存器(poke)的操作,不需要指定访问方式,因为这种方法是针对后门访问的。

四、实现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
  • mirror值的更新时序不一定是精确到时钟周期
  • DUT内部的更改可能不会影响mirror值
  • 如果在测试用例中需要使用mirror,使用隐式mirror镜像预测是不可取的;

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
  • 如果监视器观察到寄存器的值有改变时,更新mirror值
  • 通过观察总线协议更新mirror值
  • DUT内部的改动也会影响mirror值
  • 如果DUT中需要使用mirror值,使用显示mirror预测是正确的选择
  • 但是设置比较复杂,还需要设置监视器

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  
  • 不同之处是关闭了自动预测
这篇关于寄存器模型(RAL,Register Abstraction Layer)——UVM的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!