Wednesday, October 12, 2016

OVM - Agent, Monitor, Subscriber.


Monitors are for coverage collections and checkings.
A monitor is a passive component that can only observe.
A monitor (standard write method) must not modify the transaction or behavior.
A monitor write method must not block or consume any time.

OVM/UVM OOP Goal and Purpose:

  • Standard strutural way to build test environment with standard components
  • Reusable VIP
  • Layered sequences
  • Transaction-level communication
  • Separate tests from test bench
  • Configurable test bench


Connecting Monitor through Analysis_port
//
// can extends ovm_component too
// but choose a standard ovm_monitor helps in readability
//
class my_monitor extends ovm_monitor;
 
   `ovm_component_utils(my_monitor) 

   ovm_analysis_port #(my_transaction) aport;

   virtual dut_if dut_vi;

   function new ...

   function void build; 
      super.build();
      aport = new("aport", this);
   endfunction : build

   // Standard run task includes,
   // 1. monitor/sampling the pins on DUT, reading the 
   // 2. assembling the transaction
   // 3. send them to the rest of the verification environment
   task run; forever
      begin
         my_transaction tx; // handle to transaction

         // synchronize tx with clock used in DUT
         @(posedge dut_vi.clock);
         // factory call to create and populate the individual field with tx
         tx = my_transaction::type_id::create("tx"); 
         tx.cmd = dut_vi.cmd;
         tx.addr = dut_vi.addr;
         tx.data = dut_vi.data;

         // Sends tx through analysis port out to any subscribers registered
         // in ovm environment
         aport.write(tx);
      end
   endtask // run

endclass : my_monitor

class my_agent extends ovm_agent; 
   ...
   ovm_analysis_port #(my_transaction) aport;
   ...
   function void build;
      super.build();
      aport = new("aport", this);

      // use factory method to create child component for this parent
      my_sequencer_h = my_sequencer::type_id::create ... 
      my_driver_h    = my_driver ::type_id::create ... 
      my_monitor_h   = my_monitor ::type_id::create ...
   endfunction: build

   function void connect;
      ...
      // child to parent connection to the analysis port
      my_monitor_h.aport.connect( aport );

  endfunction: connect

// Top level verification environment
class my_env extends ovm_env;
   ...

   my_agent_h.aport.connect(
   my_subscriber_h.analysis_export );
   ...

   function void build;
      super.build();
      my_agent_h = my_agent ::type_id::create ... 
      my_subscriber_h = my_subscriber::type_id::create ...
   endfunction: build

   function void connect;
      my_agent_h.aport.connect( my_subscriber_h.analysis_export );
   endfunction: connect

endclass : my_agent

// A subscriber need to implement a "write" method/function
// log transactions
// collect coverage information
// check and compare to expected behaviors 
class my_subscriber extends ovm_subscriber #(my_transaction);

   `ovm_component_utils(my_subscriber) 
   ...

   function void write (my_transaction t);
      ...

      // Coverage registers 
      bit cmd;
      int addr;
      int data;

      covergroup cover_bus;
         coverpoint cmd;
         coverpoint addr { bins a[16] = {[0:255]}; } 
         coverpoint data { bins d[16] = {[0:255]}; }
      endgroup: cover_bus

   endfunction: write

   // use standard reporting to report the observation
   function void write(my_transaction t); ...
      cmd = t.cmd;
      addr = t.addr; data = t.data; 
      cover_bus.sample();

      ovm_report_info("ja", "Transaction received");
   //       ^           ^               ^
   //    Severity     Originator/ID    Text

   endfunction: write


endclass : my_subscriber




No comments:

Post a Comment