• 博客园logo
  • 会员
  • 周边
  • 新闻
  • 博问
  • 闪存
  • 众包
  • 赞助商
  • Chat2DB
    • 搜索
      所有博客
    • 搜索
      当前博客
  • 写随笔 我的博客 短消息 简洁模式
    用户头像
    我的博客 我的园子 账号设置 会员中心 简洁模式 ... 退出登录
    注册 登录

SOC/IP验证工程师

  • 博客园
  • 联系
  • 订阅
  • 管理

公告

View Post

UVM中关于寄存器模型的set_auto_predict

mirrored、 desired 和 actual value

在应用寄存器模型时, 除了利用它的寄存器信息, 还可以利用它来跟踪寄存器的值。

跟踪寄存器的值, 一方面是建立 mirrored value, 另一方面是为建立 desired value。

寄存器模型中的每一个寄存器都应该有两个值,一个是镜像值(mirrored value),一个是期望值 (desired value) 。 期望值是先利用寄存器模型修改软件对象值, 而后利用该值更新硬件值;镜像值是表示当前硬件的已知状态值。镜像值往往由模型预测给出,关于预测,在前门访问时通过观察总线或在后门访问时通过自动预测等方式来给出镜像值。

然而,镜像值有可能与硬件实际值 (hardware actual value)不一致,例如状态寄存器的镜像值就无法与硬件实际值保持同步更新。另外, 如果其他访问寄存器的通路修改了寄存器, 那么可能由于那一路总线没有被监测, 导致寄存器的镜像值未得到及时更新。

prediction的分类

UVM 提供了两种用来跟踪寄存器值的方式, 我们将其分为自动预测 (auto prediction)和显式预测 (explicit)。如果读者想使用自动预测的方式,还需要调用函数 **uvm_reg_map: :set_auto_predict () **。两种预测方式的显著差别在于, 显式预测对寄存器数值预测更为准确, 我们可以通过下面对两种模式的分析得出具体原因。

自动预测 (auto prediction) :如果读者没有在环境中集成独立的 predictor, 而是利用寄存器的操作来自动记录每一次寄存器的读写数值, 并在后台自动调用 predict()方法的话, 则这种方式称为自动预测。这种方式简单有效, 然而需要注意, 如果出现其他一些sequence 直接在总线层面上,对寄存器进行操作(跳过寄存器级别的 write()/read()操作), 或通过其他总线来访问寄存器等这些额外的情况, 都无法自动得到寄存器的镜像值和预期值。

显式预测 (explicit prediction):更为可靠的一种方式是在物理总线上通过监视器来捕捉总线事务, 并将捕捉到的事务传递给外部例化的 predictor (预测器),该 predictor 由 UVM 参数化类 uvm_reg_predictor 例化并集成在顶层环境中。 如下图, 在集成的过程中需要将 adapter 与 map 的句柄也一并传递给 predictor, 同时将 monitor 采集的事务通过 analysis port 接入到 predictor一侧。这种集成关系可以使得 monitor一旦捕捉到有效事务, 会发送给 predictor, 再由其利用adapter 的桥接方法, 实现事务信息转换, 并将转化后的寄存器模型有关信息更新到 map 中。默认情况下,系统将采用显式预测的方式, 这就要求集成到环境中的总线 UVC monitor 需要具备捕捉事务 的功能和对应的 analysis port, 以便于同 predictor 连接。

image
关于 predictor 在顶层环境中的集成, 读者可以通过下面的一段例码片段来掌握集成时的几个要素:

class mcdf_bus_env extends uvm_env;
  mcdf_bus_agent agent;
  mcdf_rgm rgm; 
  reg2mcdf_adapter reg2mcdf; 
  uvm_reg_predictor #(mcdf_bus_trans) mcdf2reg_predictor; 
  `uvm_component_utils(mcdf_bus_env)
...
  function void build_phase(uvm_phase phase); 
    agent=mcdf_bus_agent::type_id::create("agent", this); 
    if(!uvm_config_db#(mcdf_rgm)::get(this, "", "rgm", rgm)) begin
      `uvm_info("GETRGM", "no top-down RGM handle is assigned", UVM_LOW) 
      rgm = mcdf_rgm::type_id::create("rgm", this); 
      `uvm_info("NEWRGM", "created rgm instance locally", UVM_LOW)
    end 
    rgm. build() ; 
    reg2mcdf = reg2mcdf_adapter::type_id::create("reg2mcdf"); 
    mcdf2reg_predictor = uvm_reg_predictor#(mcdf_bus_trans)::type_ id: : create ("mcdf2reg_predcitor", this); 
    mcdf2reg_predictor.map = rgm.map; 
    mcdf2reg_predictor.adapter = reg2mcdf; 
  endfunction 

  function void connect_phase(uvm_phase phase);
    rgm.map.set_sequencer(agent.sequencer, reg2mcdf); 
    agent.monitor.ap.connect(mcdf2reg_predictor.bus_in);
   endfunction 

endclass

uvm白皮书第七章:
my_adapter.sv

`ifndef MY_ADAPTER__SV 
`define MY_ADAPTER__SV 
class my_adapter extends uvm_reg_adapter;
    string tID = get_type_name();

    `uvm_object_utils(my_adapter)

   function new(string name="my_adapter");
      super.new(name);
   endfunction : new

   function uvm_sequence_item reg2bus(const ref uvm_reg_bus_op rw);
      bus_transaction tr;
      tr = new("tr"); 
      tr.addr = rw.addr;
      tr.bus_op = (rw.kind == UVM_READ) ? BUS_RD: BUS_WR;
      if (tr.bus_op == BUS_WR)
         tr.wr_data = rw.data; 
      return tr;
   endfunction : reg2bus

   function void bus2reg(uvm_sequence_item bus_item, ref uvm_reg_bus_op rw);
      bus_transaction tr;
      if(!$cast(tr, bus_item)) begin
         `uvm_fatal(tID,
          "Provided bus_item is not of the correct type. Expecting bus_transaction")
          return;
      end
      rw.kind = (tr.bus_op == BUS_RD) ? UVM_READ : UVM_WRITE;
      rw.addr = tr.addr;
      rw.byte_en = 'h3;
      rw.data = (tr.bus_op == BUS_RD) ? tr.rd_data : tr.wr_data;
      rw.status = UVM_IS_OK;
   endfunction : bus2reg

endclass : my_adapter
`endif

base_test.sv

`ifndef BASE_TEST__SV
`define BASE_TEST__SV

class base_test extends uvm_test;

   my_env         env;
   my_vsqr        v_sqr;//
   reg_model      rm;//
   my_adapter     reg_sqr_adapter;//
   my_adapter     mon_reg_adapter;//

   uvm_reg_predictor#(bus_transaction) reg_predictor;
   
   function new(string name = "base_test", uvm_component parent = null);
      super.new(name,parent);
   endfunction
   
   extern virtual function void build_phase(uvm_phase phase);
   extern virtual function void connect_phase(uvm_phase phase);
   extern virtual function void report_phase(uvm_phase phase);
   `uvm_component_utils(base_test)
endclass

function void base_test::build_phase(uvm_phase phase);
   super.build_phase(phase);
   env  =  my_env::type_id::create("env", this); //
   v_sqr =  my_vsqr::type_id::create("v_sqr", this);//

   rm = reg_model::type_id::create("rm", this);//
   rm.configure(null, "");//
   rm.build();//
   rm.lock_model();//
   rm.reset();//

   reg_sqr_adapter = new("reg_sqr_adapter");//
   mon_reg_adapter = new("mon_reg_adapter");//
   reg_predictor = new("reg_predictor", this);//
   env.p_rm = this.rm;//
endfunction

function void base_test::connect_phase(uvm_phase phase);
   super.connect_phase(phase);
   v_sqr.p_my_sqr = env.i_agt.sqr;//
   v_sqr.p_bus_sqr = env.bus_agt.sqr;//
   v_sqr.p_rm = this.rm;//

   rm.default_map.set_sequencer(env.bus_agt.sqr, reg_sqr_adapter);//
   rm.default_map.set_auto_predict(0);//

   reg_predictor.map = rm.default_map;//
   reg_predictor.adapter = mon_reg_adapter;//
   env.bus_agt.ap.connect(reg_predictor.bus_in);//
endfunction

function void base_test::report_phase(uvm_phase phase);
   uvm_report_server server;
   int err_num;
   super.report_phase(phase);

   server = get_report_server();
   err_num = server.get_severity_count(UVM_ERROR);

   if (err_num != 0) begin
      $display("TEST CASE FAILED");
   end
   else begin
      $display("TEST CASE PASSED");
   end
endfunction

`endif

posted on 2025-12-27 09:22  SOC验证工程师  阅读(15)  评论(0)    收藏  举报

刷新页面返回顶部
 
博客园  ©  2004-2026
浙公网安备 33010602011771号 浙ICP备2021040463号-3