SystemVerilog:如何处理UVM中的reset(第1部分)

即使听起来很简单,但在实际实现中,在UVM agent中处理reset也不是那么简单。
在本文中,我将介绍一种处理reset的通用机制,该机制可以在任何UVM agent中重复使用。

让我们考虑一下,我们有一个具有以下架构的UVM agent:

A Typical UVM Agent Architecture
步骤#1:处理agent组件中的reset


因为agent是最重要的组件,所以我们可以在其中实现一些逻辑,该逻辑可以检测到reset何时变为活动状态,然后通知其所有子组件,它们应该reset其逻辑(包括driver,monitor,sequencer等)。

class cfs_agent extends uvm_agent;
   ...
   virtual task run_phase(uvm_phase phase);
      forever begin
         wait_reset_start();
         if(agent_config.get_should_handle_reset() == 1) begin
            handle_reset(phase, "HARD");
         end
         wait_reset_end();
      end
   endtask
   ...
endclass


通知所有子组件,它们应该重新reset相应逻辑,其实很简单:

class cfs_agent extends uvm_agent;
   ...
   virtual function void handle_reset(uvm_phase phase, string kind = "HARD");
      monitor.handle_reset(kind);

      if(driver != null) begin
         driver.handle_reset(kind);
      end

      if(sequencer != null) begin
         sequencer.handle_reset(phase, kind);
      end

      if(coverage != null) begin
         coverage.handle_reset(kind);
      end

      //add here any other component which might need to be reset
   endfunction
   ...
endclass


在agent配置类中,我们声明用于控制reset处理的开关:

class cfs_agent_config extends uvm_component;
   ...
   protected bit should_handle_reset;

   function new(string name = "");
      super.new(name);
      should_handle_reset = 1;
   endfunction

   virtual function bit get_should_handle_reset();
      return should_handle_reset();
   endfunction

   virtual function void set_should_handle_reset(bit should_handle_reset);
      this.should_handle_reset = should_handle_reset;
   endfunction
endclass

关于此切换背后的原因,请看一下本文的第2部分。

如果您想找到我们如何更好地抽象该agent逻辑,请阅读SystemVerilog中的“多重继承”。

步骤#2:处理monitor组件中的复位


从最基本的角度来看,monitor程序逻辑是一个连续的循环,它监视某些物理总线并收集所有传输。
基于此,我们可以说复位逻辑应停止该循环(无论复位来时其状态如何),清除所有临时信息并在复位完成后重新启动监视循环。
当然,无论agnet处理的物理协议如何,都必须这样做。

class cfs_monitor extends uvm_monitor;
   ...
   //process for collect_transactions() task
   protected process process_collect_transactions;

   //task for collecting all transactions
   virtual task collect_transactions();
      fork
         begin
            process_collect_transactions = process::self();

            forever begin
               collect_transaction();
            end
         end
      join
   endtask

   virtual task run_phase(uvm_phase phase);
      forever begin
         fork
            begin
               wait_reset_end();
               collect_transactions();
               disable fork;
            end
         join
      end
    endtask

    //function for handling reset
    virtual function void handle_reset(string kind = "HARD");
       if(process_collect_transactions != null) begin
          process_collect_transactions.kill();
       end
       //clear here any temporary information from the monitor
    endfunction
   ...
endclass

步骤#3:处理driver组件中的复位


我们在monitor中实现的相同逻辑可以适用于driver组件。最后,driver组件的逻辑只是一个循环,等待sequencer的sequence并将它们放在物理总线上。

class cfs_driver extends uvm_driver;
   ...
   //process for drive_transactions() task
   protected process process_drive_transactions;

   //task for driving all transactions
   virtual task drive_transactions();
      fork
         begin
            process_drive_transactions = process::self();

            forever begin
               cfs_item_drv_master transaction;
               seq_item_port.get_next_item(transaction);
               drive_transaction(transaction);
               seq_item_port.item_done();
            end
         end
      join
   endtask

   task run_phase(uvm_phase phase);
      forever begin
         fork
            begin
               wait_reset_end();
               drive_transactions();
               disable fork;
           end
         join
      end
   endtask

   //function for handling reset
   virtual function void handle_reset(string kind = "HARD");
      if(process_drive_transactions != null) begin
         process_drive_transactions.kill();
      end
      //clear here any temporary information, initialize some interface signals etc
   endfunction
   ...
endclass

步骤4:在sequencer组件中处理重置


复位sequencer非常简单。我们只需要确保丢弃所有待处理的项目,以便sequencer可以在重置后处理新项目:

class cfs_sequencer extends uvm_sequencer;
   ...
   virtual function void handle_reset(uvm_phase phase, string kind = "HARD");
      uvm_objection objection = phase.get_objection();
      int objections_count;

      stop_sequences();

      objections_count = objection.get_objection_count(this);

      if(objections_count > 0) begin
         objection.drop_objection(this, $sformatf("Dropping %0d objections at reset", objections_count), objections_count);
      end

      start_phase_sequence(phase);
   endfunction
   ...
endclass

步骤5:处理Coverage组件中的复位


复位coverage组件更多地取决于物理协议,因为没有上述组件必须执行的“标准”逻辑。
因此,您可以使用handle_reset()函数在复位期间进行一些覆盖率采样,并清除所有临时信息:

class cfs_coverage extends uvm_component;
   ...
   virtual function void handle_reset(string kind = "HARD");
      //sample coverage groups related to reset
      //clear some temporary information
   endfunction
   ...
endclass

就是这样!
该技术非常通用,因此可以用于任何agent。

如果您想了解有关如何将此技术集成到通用agent中的更多信息,汉密尔顿·卡特(Hamilton Carter)曾在2015年写过两篇关于此类通用agent的文章:

希望这可以帮助?

在本文的第2部分中,您可以阅读有关如何在验证环境中处理重置的信息:SystemVerilog:如何在UVM中处理复位(第2部分)

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值