zoukankan      html  css  js  c++  java
  • uvm_cookbook--sequences--wait for a signal

    In the general case, synchronizing to hardware events is taken care of in UVM testbenches by drivers (proxy & BFM) and monitors (proxy & BFM). However, there are some cases where it is useful for a sequence or a component to synchronize to a hardware event such as a clock without interacting with a driver or a monitor. This can be facilitated by adding methods to an object containing a virtual interface BFM handle (usually a configuration object) that call a task in the BFM that blocks until a hardware event occurs. A further refinement is to add a get_config() method which allows a component to retrieve a pointer to its configuration object based on its scope within the UVM testbench component hierarchy.

    BFM Methods

    Since BFMs are the only items which are allowed to access pins directly, the BFMs have hardware synchronization methods added to them which can then be called by code in a testbench such as configuration objects. Examples of hardware synchronization methods include:

    • wait_for_clock()
    • wait_for_reset()
    • wait_for_interrupt()
    • interrupt_cleared()

    These hardware synchronization methods are declared explicitly as automatic because static entities such as interfaces have implicitly static tasks. Since multiple threads/locations in a testbench way want to wait for a number of clock cycles or wait for a reset signal, we need to be able to invoke the tasks multiple times without overwriting the values used for each invocation.

    In general the monitor BFM should be targeted for adding the extra methods since the monitor BFM would be present in both active and passive modes.

    An example BFM:

    interface bidirect_bus_monitor_bfm (bus_if BUS);
     
    //
    // Task: wait_for_clock
    //
    // This method waits for n clock cycles. 
    task automatic wait_for_clock( int n = 1 ); 
     repeat( n ) @( posedge BUS.clk );
    endtask : wait_for_clock
     
    //
    // Task: wait_for_reset
    //
    // This method waits for the end of reset. 
    task automatic wait_for_reset();
     // Wait for reset to end
     @(posedge BUS.resetn);
    endtask : wait_for_reset
     
    //
    // Task: wait_for_error
    //
    task automatic wait_for_error;
     @(posedge error);
    endtask: wait_for_error
     
    //
    // Task: wait_for_no_error
    //
    task automatic wait_for_no_error;
     @(negedge error);
    endtask: wait_for_no_error
     
    endinterface : bidirect_bus_monitor_bfm

    Additions to the configuration object

    In order to support the use of a wait_for_interface_signal method, hardware synchronization methods have to be added to a configuration object. These hardware synchronization methods reference methods within the virtual interface BFM(s) which the configuration object contains handles for.

    An example:

    class bus_agent_config extends uvm_object;
     
    `uvm_object_utils(bus_agent_config)
     
    virtual bidirect_bus_monitor_bfm mon_bfm;  // This is the virtual interface with the methods to wait on
     
    function new(string name = "bus_agent_config");
     super.new(name);
    endfunction
     
    //
    // Task: wait_for_clock
    //
    // This method waits for n clock cycles. 
    task wait_for_clock( int n = 1 );
     mon_bfm.wait_for_clock(n);
    endtask
     
    //
    // Task: wait_for_reset
    //
    // This method waits for the end of reset. 
    task wait_for_reset();
      mon_bfm.wait_for_reset();
    endtask : wait_for_reset
     
    //
    // Task: wait_for_error
    //
    task wait_for_error();
      mon_bfm.wait_for_error();
    endtask : wait_for_error
     
    //
    // Task: wait_for_no_error
    // 
    task wait_for_no_error();
      mon_bfm.wait_for_no_error();
    endtask : wait_for_no_error
     
    endclass: bus_agent_config

    Using the wait_for_interface_signal method

    In order to use the wait_for_xxx() method, the sequence or component must first ensure that it has a valid pointer to the configuration object. The pointer may already have been set up during construction or it may require the sequence or component to call the get_config() static method. Since sequences are not part of the UVM component hierarchy, they need to reference it via the m_sequencer pointer.

    Once the local configuration object pointer is valid, the method can be called via the configuration object handle.

    A sequence example:

    class bus_seq extends uvm_sequence #(bus_seq_item);
     
    `uvm_object_utils(bus_seq)
     
    bus_seq_item req;
    bus_agent_config m_cfg;
     
    rand int limit = 40; // Controls the number of iterations
     
    function new(string name = "bus_seq");
      super.new(name);
    endfunction
     
    task body;
      int i = 5;
      req = bus_seq_item::type_id::create("req");
      // Get the configuration object
      if (m_cfg == null)
        if(!uvm_config_db #(bus_agent_config)::get(null, get_full_name(), "config", m_cfg)) begin
          `uvm_error("BODY", "bus_agent_config not found")
        end
     
     
      repeat(limit)
        begin
          start_item(req);
          // The address is constrained to be within the address of the GPIO function
          // within the DUT, The result will be a request item for a read or a write
          if(!req.randomize() with {addr inside {[32'h0100_0000:32'h0100_001C]};}) begin
            `uvm_error("body", "randomization failed for req")
          end
          finish_item(req);
          // Wait for interface clocks:
          m_cfg.wait_for_clock(i);
          i++;
          // The req handle points to the object that the driver has updated with response data
          uvm_report_info("seq_body", req.convert2string());
        end
    endtask: body
     
    endclass: bus_seq

    A component example:

    //
    // A coverage monitor that should ignore coverage collected during an error condition:
    //
     
    class transfer_link_coverage_monitor extends uvm_subscriber #(trans_link_item);
     
    `uvm_component_utils(transfer_link_coverage_monitor)
     
    T pkt;
     
    // Error monitor bit
    bit no_error;
    // Configuration:
    bus_agent_config m_cfg;
     
    covergroup tlcm_1;
     HDR: coverpoint pkt.hdr;
     SPREAD: coverpoint pkt.payload {
     bins spread[] {[0:1023], [1024:8095], [8096:$]}
     }
     cross HDR, SPREAD;
    endgroup: tlcm_1
     
    function new(string name = "transfer_link_coverage_monitor", uvm_component_parent = null);
     super.new(name, parent);
     tlcm_1 = new;
    endfunction
     
    // The purpose of the run method is to monitor the state of the error
    // line
    task run_phase( uvm_phase phase );
     no_error = 0;
     // Get the configuration
     if (m_cfg == null)
       if(!uvm_config_db #(bus_agent_config)::get(this, "", "bus_agent_config", m_cfg)) begin
        `uvm_error("run_phase", "Configuration error: unable to find bus_agent_config")
       end
     m_cfg.wait_for_reset(); // Nothing valid until reset is over
     no_error = 1;
     
     forever begin
      m_cfg.wait_for_error(); // Blocks until an error occurs
      no_error = 0;
      m_cfg.wait_for_no_error(); // Blocks until the error is removed
     end
    endtask: run_phase
     
    function write(T t);
     pkt = t;
     if(no_error == 1) begin // Don't sample if there is an error
      tlcm_1.sample();
     end
    endfunction: write
     
    endclass: transfer_link_coverage_monitor

    在interface中实现wait功能,在config中调用interface指针,在seq中get到config(或在coverage monitor中get到config)

    参考:

    Stimulus/Signal Wait | Verification Academy

  • 相关阅读:
    Laravel 通知
    LARAVEL 6 + VUE + SEMANTIC UI
    Laravel 从入门到精通教程【预备篇、基础篇】
    Laravel Vue.js 聊天室
    GIT代码管理: git remote add 【转载】
    Laravel Vuejs 实战:开发知乎 (45-47)用户设置
    Laravel Vuejs 实战:开发知乎 (42-44)用户头像
    如何在运行时更改JMeter的负载
    Jmeter Grafana Influxdb 环境搭建
    实时结果
  • 原文地址:https://www.cnblogs.com/zhiminyu/p/14251362.html
Copyright © 2011-2022 走看看