Using a central database to store parameters in SV


An interconnect is the backbone of an SoC as many cores, IPs and memory blocks are connected to it and hence is usually an important part of the verification plan. Each master and slave would probably be running on different clocks, have different data bus-widths and hence different requirements. From a testbench perspective, it would be interesting to think about how to organize all these design parameters so that any change in the design results in a lower effort to reflect that change in the testbench. This post will describe one way to do that in a System-Verilog based testbench.

The concept of a singleton object implemented in the core UVM libraries was explored in an earlier post on this site. Such an object can be used as a central database to store design parameters that can be queried by custom functions from the same class object. Let's imagine that each master and slave connected to the interconnect, are cars of different types and makes stored in a SV structure format which has a definition as given below.

typedef struct {
  string     brand;
  e_type     type;
  e_engine  engine;
  bit [15:0]   length;
  bit      has_lcd;
} st_car;

A structure list can be created to store all the details of different cars that can later be fed into the database.

st_car   car_list [10] = '{
   '{"honda", 4DOOR, V6, 450, ...}, 
   '{"bmw", COUPE, V8, 300, ... }

Next task is to create the central database.

class base_car;
  string     brand;
  e_type     type;
class car_db;
  static local car_db   m_inst;
  base_car          car_list [$];
  static function noc_spec get();
    if (m_inst == null) begin
      m_inst = new();
    return m_inst;
  // functions to query the list for different usage

An instance of the database can be obtained by calling the function get() and can be placed inside within the top environment.

class top_env;
  car_db   m_car_db;
  virtual function void build_env ();
    // Get database instance
    m_car_db = car_db::get();
    // For each row in the structure, create a class to store the row
    // and insert into the database queue
    foreach (car_list[i]) begin
      base_car  bc = new ("bc");
      bc.brand = car_list[i].brand;
      bc.type = car_list[i].type;
      m_car_db.car_list.push_back (bc);

The main advantage of doing this is the ability for any component to access the central database via a local instance. Another advantage is that all related custom functions to query the database can be encapsulated. Moreover, any change in design parameter for any of the above "cars", can easily be made in the structure list that was created earlier. You can also create new variables in the base_car class to store computed results from existing values.

And ofcourse, you can store all of this in uvm_config_db as a single class object if the testbench already uses UVM.

Importance of interconnect performance verificatio...
Working with register object configurations


No comments made yet. Be the first to submit a comment
Already Registered? Login Here
Saturday, 24 March 2018