Merging all register cover objects into one object

Hi,

I am declaring some coverage metrics for each register in a design.
the covergroups are created in the register class constructor.

when i run my simulations every cover group is contained inside it’s register class. this creates many cover items and makes it harder to present that way.

is there a way to make all of the register related covergroups to appear under one object? (i.e the register block)

Hi,

You can do it by adding the covergroup under the register block. So, you will be able to add the cross coverpoint into it as well.

Following is the example implementation code. It is based on a register model class auto-generated by code generator tools, and user create a derived class extends from the register block class (auto-generated register block class). Then use set_type_override_by_type to replace the base class with the derived one. With this, whenever there is a write or read happens to a register, the sample method will be automatically called.

You may find this cookbook very useful to understand the difference between sample and sample_values.


// Your original register model package.
// Normally autogenerated using register model generator such as
// Magillem-MRV, Agnisys, CSRCompiler, Cadence's blueprint etc
package myreg_pkg;

   import uvm_pkg::*;
   `include "uvm_macros.svh"

   // myreg_reg_c Register Definition
   class myreg_reg_c extends uvm_reg;
      `uvm_object_utils(myreg_reg_c)
      rand uvm_reg_field all;

      // This the autogeneated covergroup for each register
      covergroup fields_cg ();
         option.per_instance = 1;
         all_cp : coverpoint all.get()
            {bins all[16] = {['h0:'hFFFFFFFF]}; illegal_bins bad = default;}
      endgroup : fields_cg

      // Constructor
      function new(string name = "myreg_reg_c");
         super.new(name, 32, build_coverage(UVM_CVR_FIELD_VALS));
         if (has_coverage(UVM_CVR_FIELD_VALS))
            fields_cg = new();
      endfunction : new

      // Build
      virtual function void build();
         // create bitfield
         all = uvm_reg_field::type_id::create("all");
         // configure
         all.configure(
            .parent                 (this),
            .size                   (32),
            .lsb_pos                (0),
            .access                 ("RW"),
            .volatile               (0),
            .reset                  (32'b0),
            .has_reset              (1),
            .is_rand                (1),
            .individually_accessible(0));
      endfunction : build

      // This is how mostly the autogerated code implement the field's
      // coverage sampling.
      function void sample_values();
         super.sample_values();
         if (has_coverage(UVM_CVR_FIELD_VALS))
         begin
            `uvm_info(get_type_name(), "UVM_CVR_FIELD_VALS enabled", UVM_HIGH)
            if (fields_cg != null)
            begin
               fields_cg.sample();
               `uvm_info(get_type_name(), "fields_cg.sample called", UVM_HIGH)
            end
         end
      endfunction : sample_values

   endclass : myreg_reg_c

   class myblock_ral_c extends uvm_reg_block;
      rand myreg_reg_c myreg;
      function new(string name = "myblock_ral_c");
         super.new(name, build_coverage(UVM_CVR_ADDR_MAP+UVM_CVR_FIELD_VALS));
         `uvm_info(get_type_name(), $sformatf("has_coverage=%0b", has_coverage(UVM_CVR_FIELD_VALS)), UVM_NONE)
      endfunction: new

      virtual function void build();
         default_map = create_map("", 0, 4, UVM_BIG_ENDIAN, 0);
         myreg = myreg_reg_c::type_id::create("myreg",,get_full_name());
         myreg.configure(this, null);
         myreg.build();

         // Create the address map
         default_map = create_map("", 0, 4, UVM_LITTLE_ENDIAN, 1);
         default_map.add_reg(myreg, 'h0000,  "RW");
      endfunction : build

      `uvm_object_utils(myblock_ral_c)

      virtual function void sample(uvm_reg_addr_t offset, bit is_read, uvm_reg_map map);
         super.sample(offset, is_read, map);
         `uvm_info(get_type_name(), "sample called", UVM_HIGH)
      endfunction : sample

      virtual function void sample_values();
         super.sample_values();
         `uvm_info(get_type_name(), "sample_values called", UVM_HIGH)
      endfunction : sample_values

   endclass : myblock_ral_c

endpackage : myreg_pkg

module test();

   import uvm_pkg::*;
   `include "uvm_macros.svh"
   import myreg_pkg::*;

   // Create your derived class and add the covergroup which has all
   // of the coverpoints of your register fields and also add the cross
   // definition on the same covergroup 
   class myblock_ral_ext_c extends myblock_ral_c;
      `uvm_object_utils(myblock_ral_ext_c)
      // Here you put all of your fields coverpoints and crosses
      covergroup fields_cg;
         option.per_instance = 1;
         myreg_all_cp : coverpoint myreg.all.get()
            {bins all[16] = {['h0:'hFFFFFFFF]}; illegal_bins bad = default;}
//       mycross_cp : cross ...
      endgroup : fields_cg

      function new(string name = "myblock_ral_ext_c");
         super.new(name);
         `uvm_info(get_type_name(), $sformatf("has_coverage=%0b", has_coverage(UVM_CVR_FIELD_VALS)), UVM_NONE)
         if (has_coverage(UVM_CVR_FIELD_VALS))
            fields_cg = new();
      endfunction: new

      virtual function void build();
         super.build();
      endfunction : build

      virtual function void sample (
         uvm_reg_addr_t offset,
         bit            is_read,
         uvm_reg_map    map
      );
         super.sample(offset, is_read, map);
         `uvm_info(get_type_name(), "sample called", UVM_HIGH)
         if (has_coverage(UVM_CVR_FIELD_VALS))
         begin
            `uvm_info(get_type_name(), "UVM_CVR_FIELD_VALS enabled", UVM_HIGH)
            if (fields_cg != null)
            begin
               fields_cg.sample();
               `uvm_info(get_type_name(), "fields_cg.sample called", UVM_HIGH)
            end
         end
      endfunction : sample

      virtual function void sample_values();
         super.sample_values();
         `uvm_info(get_type_name(), "sample_values called", UVM_HIGH)
      endfunction : sample_values

   endclass : myblock_ral_ext_c

   // I am reusing the same register adapter's agent the being provided
   // under the examples of UVM install package just to make sure this
   // example code works. 
   // Please make sure you add +incdir+$UVM_HOME/examples/simple/registers/common
   //
   // !! Please don't use this agent, instead use the
   // dedicated bus protocol UVC which will be specific for your design.!!
   `include "reg_agent.sv"
   class mydut;
      static task rw(reg_rw rw);
      endtask
   endclass : mydut

   class mytest extends uvm_test;
      `uvm_component_utils(mytest)
      myblock_ral_c      m_ral;
      reg_agent#(mydut)    m_agent;
      uvm_reg_predictor#(reg_rw) m_predict;

      function new (string n = "mytest", uvm_component p = null);
         super.new(n, p);
         //
         // ! IMPORTANT !
         // Set the type override in the test's constructor.
         // Please dont call it under any child component
         //
         set_type_override_by_type(
            myblock_ral_c::get_type(),
            myblock_ral_ext_c::get_type());

         // Providing mechanism to control UVM register's coverage model
         // from plusargs
         begin
            uvm_reg_cvr_t _cov_models;
            _cov_models = UVM_NO_COVERAGE;
            if ($test$plusargs("UVM_CVR_ALL"))        _cov_models |= UVM_CVR_ALL;
            if ($test$plusargs("UVM_CVR_REG_BITS"))   _cov_models |= UVM_CVR_REG_BITS;
            if ($test$plusargs("UVM_CVR_ADDR_MAP"))   _cov_models |= UVM_CVR_ADDR_MAP;
            if ($test$plusargs("UVM_CVR_FIELD_VALS")) _cov_models |= UVM_CVR_FIELD_VALS;
            if ($test$plusargs("UVM_CVR_ALL"))        _cov_models |= UVM_CVR_ALL;
            uvm_reg::include_coverage("*", _cov_models);
         end
      endfunction : new

      function void build_phase(uvm_phase phase);
         super.build_phase(phase);
         m_ral = myblock_ral_c::type_id::create("m_ral", , get_full_name());
         m_ral.build();
         m_agent = reg_agent#(mydut)::type_id::create("m_agent", this);
         m_predict = uvm_reg_predictor#(reg_rw)::type_id::create("m_predict", this);
      endfunction : build_phase

      function void connect_phase(uvm_phase phase);
         reg2rw_adapter reg2rw  = new("reg2rw");
         m_ral.default_map.set_sequencer(m_agent.sqr, reg2rw);
         m_ral.lock_model();
         m_predict.map = m_ral.default_map;
         m_predict.adapter = reg2rw;
         m_agent.mon.ap.connect(m_predict.bus_in);
         m_ral.default_map.set_auto_predict(0);
      endfunction : connect_phase

      task run_phase(uvm_phase phase);
         uvm_status_e status;
         if (uvm_top.get_report_verbosity_level() >= UVM_HIGH)
            this.print();
         phase.raise_objection(this);
         repeat (10)
         begin
            #10ns;
            void'(m_ral.randomize());
            m_ral.update(status);
            m_ral.sample_values();
            if (uvm_top.get_report_verbosity_level() >= UVM_HIGH)
               m_ral.print();
         end
         phase.drop_objection(this);
      endtask : run_phase

   endclass : mytest

   initial $timeformat(-9, 3, " ns", 15);
   initial run_test("mytest");

endmodule : test

Hope this helps.
-Baser