Connecting UVM TLM Port and Imp Port

Connecting TLM Port and Imp Port

TLM Port Imp Port
TLM Port Imp Port

Let’s consider an example consisting of two components component_a and component_b, and a transaction class.

  • component_a and component_b objects are created in the environment with the name comp_a and comp_b respectively
  • transaction class is randomized in comp_a and sent to the comp_b through TLM Communication mechanism

Below are the steps to implement a TLM Communication mechanism between comp_a and comp_b.

  1. Declare and Create TLM Port in comp_a
  2. Declare and Create TLM Imp Port in comp_b
  3. Connect TLM Port and Imp Port in env
  4. Call interface method in comp_a to send the transaction
  5. Implement an interface method in comp_b to receive the transaction

TLM TesetBench Components are,

———————————————————-
Name                    Type
———————————————————-
uvm_test_top        basic_test
env                    environment
comp_a         component_a
trans_out   uvm_blocking_put_port
comp_b         component_b
trans_in     uvm_blocking_put_imp
———————————————————-

Declare and Create TLM Port in comp_a

1. Declaring blocking put port with the name trans_out. As the comp_a sends the packet out of the component, so named as trans_out

uvm_blocking_put_port #(transaction) trans_out;

2. Creating the port

trans_out = new("trans_out", this);

3. comp_a code is as below,

class component_a extends uvm_component;
  
  uvm_blocking_put_port #(transaction) trans_out; //Step-1. Declaring blocking port
  
  `uvm_component_utils(component_a)
  
  //---------------------------------------
  // Constructor
  //---------------------------------------
  function new(string name, uvm_component parent);
    super.new(name, parent);
    trans_out = new("trans_out", this);  //Step-2. Creating the port
  endfunction : new
  //---------------------------------------
  // run_phase
  //---------------------------------------
  virtual task run_phase(uvm_phase phase);
  endtask : run_phase
endclass : component_a

Declare and Create TLM Port in comp_b

1. Declaring blocking put imp port with the name trans_in. As the comp_b receives the packet from another component, so named as trans_in

uvm_blocking_put_imp #(transaction,component_b) trans_in;

2. Creating the port

trans_in = new("trans_in", this);

3. comp_b code is as below,

class component_b extends uvm_component;
  
  transaction trans;
  uvm_blocking_put_imp #(transaction,component_b) trans_in;  //Step-1. Declaring blocking put imp port 
  `uvm_component_utils(component_b)
  
  //---------------------------------------
  // Constructor
  //---------------------------------------
  function new(string name, uvm_component parent);
    super.new(name, parent);
    trans_in = new("trans_in", this);  //Step-2. Creating the port
  endfunction : new
endclass : component_b

Connect TLM Port and Imp Port in env

1. Declare and Create the componet_a and component_b in environment class

component_a comp_a;
component_b comp_b;
comp_a = component_a::type_id::create("comp_a", this);
comp_b = component_b::type_id::create("comp_b", this);

2. Connect comp_a port and comp_b imp port

comp_a.trans_out.connect(comp_b.trans_in);

3. Place the connection code in the connect phase

function void connect_phase(uvm_phase phase);
  comp_a.trans_out.connect(comp_b.trans_in);
endfunction : connect_phase

4. Complete env code

class environment extends uvm_env;
  
  //---------------------------------------
  // Components Instantiation
  //---------------------------------------
  //Step-1, Declaring the components
  component_a comp_a;
  component_b comp_b;
  
  `uvm_component_utils(environment)
  
  //---------------------------------------
  // Constructor
  //---------------------------------------
  function new(string name, uvm_component parent);
    super.new(name, parent);
  endfunction : new
  //---------------------------------------
  // build_phase - Create the components
  //---------------------------------------
  function void build_phase(uvm_phase phase);
    super.build_phase(phase);
    //Step-1, Creating the components
    comp_a = component_a::type_id::create("comp_a", this);
    comp_b = component_b::type_id::create("comp_b", this);
  endfunction : build_phase
  
  //---------------------------------------
  // Connect_phase
  //---------------------------------------
  function void connect_phase(uvm_phase phase);
    //Step-3, Connecting the ports
    comp_a.trans_out.connect(comp_b.trans_in);
  endfunction : connect_phase
endclass : environment

Call interface method in comp_a to send the transaction

1. Randomize the transaction packet and send to comp_b by calling put() method

void'(trans.randomize());
trans_out.put(trans);

2. Place the conde in run_phase

virtual task run_phase(uvm_phase phase);
  phase.raise_objection(this);
  
  trans = transaction::type_id::create("trans", this);
  void'(trans.randomize());
  trans_out.put(trans);
  
  phase.drop_objection(this);
endtask : run_phase

3. Complete code with uvm_info added

class component_a extends uvm_component;
  
  transaction trans;
  uvm_blocking_put_port #(transaction) trans_out;
  
  `uvm_component_utils(component_a)
  
  //---------------------------------------
  // Constructor
  //---------------------------------------
  function new(string name, uvm_component parent);
    super.new(name, parent);
    trans_out = new("trans_out", this);
  endfunction : new
  //---------------------------------------
  // run_phase
  //---------------------------------------
  virtual task run_phase(uvm_phase phase);
    phase.raise_objection(this);
    
    trans = transaction::type_id::create("trans", this);
    void'(trans.randomize()); // Step-1: randomize the trans
    `uvm_info(get_type_name(),$sformatf(" tranaction randomized"),UVM_LOW)
    trans.print();
    
    `uvm_info(get_type_name(),$sformatf(" Before calling port put method"),UVM_LOW)
    trans_out.put(trans); // Step-2: Calling put Method to send trans to comp_b
    `uvm_info(get_type_name(),$sformatf(" After  calling port put method"),UVM_LOW)
    
    phase.drop_objection(this);
  endtask : run_phase
endclass : component_a

Implement an interface method in comp_b to receive the transaction

1. In order to receive the transaction packet from imp port, explicit method has to be implemented
Implement put method with the input argument of transaction type

virtual task put(transaction trans);
  `uvm_info(get_type_name(),$sformatf(" Recived trans On IMP Port"),UVM_LOW)
  `uvm_info(get_type_name(),$sformatf(" Printing trans, \n %s",trans.sprint()),UVM_LOW)
endtask

2. Complete comp_b code

class component_b extends uvm_component;
  
  transaction trans;
  uvm_blocking_put_imp #(transaction,component_b) trans_in; 
  `uvm_component_utils(component_b)
  
  //---------------------------------------
  // Constructor
  //---------------------------------------
  function new(string name, uvm_component parent);
    super.new(name, parent);
    trans_in = new("trans_in", this);
  endfunction : new
  
  //---------------------------------------
  // Imp port put method
  //---------------------------------------
  virtual task put(transaction trans);
    `uvm_info(get_type_name(),$sformatf(" Recived trans On IMP Port"),UVM_LOW)
    `uvm_info(get_type_name(),$sformatf(" Printing trans, \n %s",trans.sprint()),UVM_LOW)
  endtask
endclass : component_b

Simulator Output

UVM_INFO @ 0: reporter [RNTST] Running test basic_test...
---------------------------------------------------
Name Type Size Value
---------------------------------------------------
uvm_test_top basic_test - @1839
 env environment - @1908
 comp_a component_a - @1940
 trans_out uvm_blocking_put_port - @1975
 comp_b component_b - @2008
 trans_in uvm_blocking_put_imp - @2043
---------------------------------------------------
UVM_INFO component_a.sv(29) @ 0: uvm_test_top.env.comp_a [component_a] tranaction randomized
---------------------------------
Name Type Size Value
---------------------------------
trans transaction - @1135
 addr integral 4 'he 
 wr_rd integral 1 'h0 
 wdata integral 8 'h4 
---------------------------------
UVM_INFO component_a.sv(32) @ 0: uvm_test_top.env.comp_a [component_a] Before calling port put method
UVM_INFO component_b.sv(24) @ 0: uvm_test_top.env.comp_b [component_b] Recived trans On IMP Port
UVM_INFO component_b.sv(25) @ 0: uvm_test_top.env.comp_b [component_b] Printing trans, 
 ---------------------------------
Name Type Size Value
---------------------------------
trans transaction - @1135
 addr integral 4 'he 
 wr_rd integral 1 'h0 
 wdata integral 8 'h4 
---------------------------------

UVM_INFO component_a.sv(34) @ 0: uvm_test_top.env.comp_a [component_a] After calling port put method
UVM_INFO /playground_lib/uvm-1.2/src/base/uvm_objection.svh(1271) @ 0: reporter [TEST_DONE] 
UVM_INFO /playground_lib/uvm-1.2/src/base/uvm_report_server.svh(847) @ 0: reporter [UVM/REPORT/SERVER]

Click to execute on   

❮ Previous Next ❯

Blocking TLM Ports

Blocking TLM Port and Blocking Imp Port

This example shows the blocking nature of blocking port and imp port. This is a continuation of the previous example, Only delay has been added in the blocking put method of comp_b which will lead to a port.put() method call in comp_a to get blocked until the completion of the comp_b put method.

Blocking Port Imp Port
Blocking Port Imp Port

Code

Adding delay in comp_b put method

virtual task put(transaction trans);
  `uvm_info(get_type_name(),$sformatf(" Recived trans On IMP Port"),UVM_LOW)
  `uvm_info(get_type_name(),$sformatf(" Before injecting delay"),UVM_LOW)
  #100; //Delay
  `uvm_info(get_type_name(),$sformatf(" After  injecting delay"),UVM_LOW)
  `uvm_info(get_type_name(),$sformatf(" Printing trans, \n %s",trans.sprint()),UVM_LOW)
endtask

Simulator Output

UVM_INFO @ 0: reporter [RNTST] Running test basic_test...
---------------------------------------------------
Name Type Size Value
---------------------------------------------------
uvm_test_top basic_test - @1839
 env environment - @1908
 comp_a component_a - @1940
 trans_out uvm_blocking_put_port - @1975
 comp_b component_b - @2008
 trans_in uvm_blocking_put_imp - @2043
---------------------------------------------------
UVM_INFO component_a.sv(29) @ 0: uvm_test_top.env.comp_a [component_a] tranaction randomized
---------------------------------
Name Type Size Value
---------------------------------
trans transaction - @1135
 addr integral 4 'he 
 wr_rd integral 1 'h0 
 wdata integral 8 'h4 
---------------------------------
UVM_INFO component_a.sv(32) @ 0: uvm_test_top.env.comp_a [component_a] Before calling port put method
UVM_INFO component_b.sv(24) @ 0: uvm_test_top.env.comp_b [component_b] Recived trans On IMP Port
UVM_INFO component_b.sv(25) @ 0: uvm_test_top.env.comp_b [component_b] Before injecting delay
UVM_INFO component_b.sv(27) @ 100: uvm_test_top.env.comp_b [component_b] After injecting delay
UVM_INFO component_b.sv(28) @ 100: uvm_test_top.env.comp_b [component_b] Printing trans, 
 ---------------------------------
Name Type Size Value
---------------------------------
trans transaction - @1135
 addr integral 4 'he 
 wr_rd integral 1 'h0 
 wdata integral 8 'h4 
---------------------------------

UVM_INFO component_a.sv(34) @ 100: uvm_test_top.env.comp_a [component_a] After calling port put method
UVM_INFO /playground_lib/uvm-1.2/src/base/uvm_objection.svh(1271) @ 100: reporter [TEST_DONE]
UVM_INFO /playground_lib/uvm-1.2/src/base/uvm_report_server.svh(847) @ 100: reporter [UVM/REPORT/SERVER] 

Click to execute on   

Result Analysis

UVM_INFO component_a.sv(32) @ 0: uvm_test_top.env.comp_a [component_a] Before calling port put method
UVM_INFO component_b.sv(24) @ 0: uvm_test_top.env.comp_b [component_b] Recived trans On IMP Port
UVM_INFO component_b.sv(25) @ 0: uvm_test_top.env.comp_b [component_b] Before injecting delay
UVM_INFO component_b.sv(27) @ 100: uvm_test_top.env.comp_b [component_b] After injecting delay
UVM_INFO component_b.sv(28) @ 100: uvm_test_top.env.comp_b [component_b] Printing trans, 
 ---------------------------------
Name Type Size Value
---------------------------------
trans transaction - @1135
 addr integral 4 'he 
 wr_rd integral 1 'h0 
 wdata integral 8 'h4 
---------------------------------

UVM_INFO component_a.sv(34) @ 100: uvm_test_top.env.comp_a [component_a] After calling port put method

comp_a code,

32.    `uvm_info(get_type_name(),$sformatf(" Before calling port put method"),UVM_LOW)
33.    trans_out.put(trans); // Step-2: Calling put Method to send trans to comp_b
34.    `uvm_info(get_type_name(),$sformatf(" After  calling port put method"),UVM_LOW)

Line 32 and 34 are before and after calling the trans_out.put() method. In the log, we can see that line number 32 got executed at 0ns time, whereas line 34 got executed at 100ns. This shows that trans_out.put() got blocked for 100ns. This shows the blocking nature of blocking the port and imp port.
❮ Previous Next ❯

UVM tb top

UVM tb architecture

TestBench top is the module, it connects the DUT and Verification environment components.

Typical Testbench_top contains,

  • DUT instance
  • interface instance
  • run_test() method
  • virtual interface set config_db
  • clock and reset generation logic
  • wave dump logic
uvm tb top
uvm tb top
module tbench_top;
  
  //clock and reset signal declaration
  bit clk;
  bit reset;
  
  //clock generation
  always #5 clk = ~clk;
  
  //reset Generation
  initial begin
    reset = 1;
    #5 reset =0;
  end
  
  //creatinng instance of interface, inorder to connect DUT and testcase
  mem_if intf(clk,reset);
  
  //DUT instance, interface signals are connected to the DUT ports
  memory DUT (
    .clk(intf.clk),
    .reset(intf.reset),
    .addr(intf.addr),
    .wr_en(intf.wr_en),
    .rd_en(intf.rd_en),
    .wdata(intf.wdata),
    .rdata(intf.rdata)
   );
  
  //enabling the wave dump
  initial begin 
    uvm_config_db#(virtual mem_if)::set(uvm_root::get(),"*","mem_intf",intf);
    $dumpfile("dump.vcd"); $dumpvars;
  end
  
  initial begin 
    run_test();
  end
endmodule

❮ Previous Next ❯

UVM Test

UVM Test

The user-defined test is derived from uvm_test, uvm_test is inherited from uvm_component.

  • The test defines the test scenario for the testbench
  • test class contains the environment, configuration properties, class overrides etc
  • A sequence/sequences are created and started in the test

The UVM testbench is activated when the run_test() method is called, the global run_test() task should be specified inside an initial block.

initial begin
  run_test();
end

There can be many user-defined test cases.Among multiple test cases, a particular test case can be selected and execute on two methods,
1. by specifying the test name as an argument to run_test();
example: run_test("mem_model_test");
2. by providing the UVM_TESTNAME command line argument
example: <SIMULATION_COMMANDS> +UVM_TESTNAME=mem_model_test

Writing Test

1. The test is written by extending the UVM_TEST,

class mem_model_test extends uvm_test;

  `uvm_component_utils(mem_model_test)

  function new(string name = "mem_model_test",uvm_component parent=null);
    super.new(name,parent);
  endfunction : new

endclass : mem_model_test

2. Declare env and sequence,

  mem_model_env env;
  mem_sequence  seq;

3. Create env and sequence,

  env = mem_model_env::type_id::create("env",this);
  seq = mem_sequence::type_id::create("seq");

4. Start the sequence,

  seq.start(env.mem_agnt.sequencer);

 Complete Test code,

class mem_model_test extends uvm_test;

  `uvm_component_utils(mem_model_test)

  mem_model_env env;
  mem_sequence  seq;

  function new(string name = "mem_model_test",uvm_component parent=null);
    super.new(name,parent);
  endfunction : new

  virtual function void build_phase(uvm_phase phase);
    super.build_phase(phase);

    env = mem_model_env::type_id::create("env", this);
    seq = mem_sequence::type_id::create("seq");
  endfunction : build_phase

  task run_phase(uvm_phase phase);
    seq.start(env.mem_agnt.sequencer);
  endtask : run_phase

endclass : mem_model_test

❮ Previous Next ❯

UVM Env

UVM Environment

The user-defined environment is derived from uvm_env, uvm_env is inherited from uvm_component.

The environment is the container class, It contains one or more agents, as well as other components such as the scoreboard, top-level monitor, and checker.

Writing Environment

1. The environment is written by extending UVM_ENV,

class mem_model_env extends uvm_env;
  
  `uvm_component_utils(mem_model_env)
    
  // new - constructor
  function new(string name, uvm_component parent);
    super.new(name, parent);
  endfunction : new

endclass : mem_model_env

2. Declare the agent,

  mem_agent mem_agnt;

3. Create an agent,

  mem_agnt = mem_agent::type_id::create("mem_agnt", this);

Complete environment code,

class mem_model_env extends uvm_env;

  mem_agent mem_agnt;
  
  `uvm_component_utils(mem_model_env)
    
  // new - constructor
  function new(string name, uvm_component parent);
    super.new(name, parent);
  endfunction : new

  // build_phase
  function void build_phase(uvm_phase phase);
    super.build_phase(phase);
    mem_agnt = mem_agent::type_id::create("mem_agnt", this);
  endfunction : build_phase

endclass : mem_model_env

❮ Previous Next ❯

UVM Scoreboard Example

UVM Scoreboard

The user-defined scoreboard is extended from uvm_scoreboard, uvm_scoreboard is inherited by uvm_component.

Writing Scoreboard

The scoreboard is written by extending the UVM_SCOREBOARD.

class mem_scoreboard extends uvm_scoreboard;

  `uvm_component_utils(mem_scoreboard)

  // new - constructor
  function new (string name, uvm_component parent);
    super.new(name, parent);
  endfunction : new

endclass : mem_scoreboard
  • the scoreboard will check the correctness of the DUT by comparing the DUT output with the expected values
  • the scoreboard will receive the transactions from the Monitors implemented inside agents
  • Monitor and scoreboard will communicate via TLM ports and exports

Scoreboard shall compare the DUT output values with,

  1. The golden reference values
  2. The values Generated from the reference model
UVM Scoreboard
UVM Scoreboard

Declare and Create TLM Analysis port, ( to receive transaction pkt from Monitor).

//Declaring port
uvm_analysis_imp#(mem_seq_item, mem_scoreboard) item_collected_export;

//creating port
item_collected_export = new("item_collected_export", this);

analysis export of Scoreboard is connected to Monitor port

monitor.item_collected_port.connect(scoreboard.item_collected_export);

uvm scoreboard write function

write method of the scoreboard will receive the transaction packet from the monitor, on calling write method from the monitor.

uvm scoreboard write function
uvm scoreboard write function
  //calling write method from monitor
  item_collected_port.write(pkt);
 
  //scoreboard write function
  virtual function void write(mem_seq_item pkt);
    pkt.print();
  endfunction : write

UVM scoreboard code

Below is the complete scoreboard code.

class mem_scoreboard extends uvm_scoreboard;

  `uvm_component_utils(mem_scoreboard)
  uvm_analysis_imp#(mem_seq_item, mem_scoreboard) item_collected_export;

  // new - constructor
  function new (string name, uvm_component parent);
    super.new(name, parent);
  endfunction : new

  function void build_phase(uvm_phase phase);
    super.build_phase(phase);
    item_collected_export = new("item_collected_export", this);
  endfunction: build_phase
  
  // write
  virtual function void write(mem_seq_item pkt);
    $display("SCB:: Pkt recived");
    pkt.print();
  endfunction : write

endclass : mem_scoreboard

❮ Previous Next ❯

UVM Agent

UVM Agent

  • a user-defined agent is extended from uvm_agent, uvm_agent is inherited by uvm_component
  • An agent typically contains a driver, a sequencer, and a monitor
  • Agents can be configured either active or passive

Active agent

  • Active agents generate stimulus and drive to DUT
  • An active agent shall consists of all the three components driver, sequencer, and monitor
UVM Active agent
UVM Active agent

Passive agent

Passive agents sample DUT signals but do not drive them
A passive agent consists of only the monitor

UVM Passive agent
UVM Passive agent

An agent can be configured as ACTIVE/PASSIVE by using a set config method, the default agent will be ACTIVE. the set config can be done in the env or test.

   set_config_int("path_to_agent", "is_active", UVM_ACTIVE);
   set_config_int("path_to_agent", "is_active", UVM_PASSIVE);

get_is_active() Method

get_is_active() Returns UVM_ACTIVE if the agent is acting as an active agent and UVM_PASSIVE if the agent acting as a passive agent.

Writing UVM Agent

1. An agent is written by extending UVM_agent,

class mem_agent extends uvm_agent;

  // UVM automation macros for general components
  `uvm_component_utils(mem_agent)

  // constructor
  function new (string name, uvm_component parent);
    super.new(name, parent);
  endfunction : new

endclass : mem_agent

2. Declare driver, sequencer and monitor instance,

  //declaring agent components
  mem_driver    driver;
  mem_sequencer sequencer;
  mem_monitor   monitor;

3. Depending on Agent type, create agent components in the build phase,
driver and sequencer will be created only for the active agent.

  // build_phase
  function void build_phase(uvm_phase phase);
    super.build_phase(phase);

    if(get_is_active() == UVM_ACTIVE) begin
      driver = mem_driver::type_id::create("driver", this);
      sequencer = mem_sequencer::type_id::create("sequencer", this);
    end

    monitor = mem_monitor::type_id::create("monitor", this);
  endfunction : build_phase

4. Connect the driver seq_item_port to sequencer seq_item_export for communication between driver and sequencer in the connect phase.

  // connect_phase
  function void connect_phase(uvm_phase phase);
    if(get_is_active() == UVM_ACTIVE) begin
      driver.seq_item_port.connect(sequencer.seq_item_export);
    end
  endfunction : connect_phase

 Complete Agent code,

class mem_agent extends uvm_agent;
  //declaring agent components
  mem_driver    driver;
  mem_sequencer sequencer;
  mem_monitor   monitor;

  // UVM automation macros for general components
  `uvm_component_utils(mem_agent)

  // constructor
  function new (string name, uvm_component parent);
    super.new(name, parent);
  endfunction : new

  // build_phase
  function void build_phase(uvm_phase phase);
    super.build_phase(phase);

    if(get_is_active() == UVM_ACTIVE) begin
      driver = mem_driver::type_id::create("driver", this);
      sequencer = mem_sequencer::type_id::create("sequencer", this);
    end

    monitor = mem_monitor::type_id::create("monitor", this);
  endfunction : build_phase

  // connect_phase
  function void connect_phase(uvm_phase phase);
    if(get_is_active() == UVM_ACTIVE) begin
      driver.seq_item_port.connect(sequencer.seq_item_export);
    end
  endfunction : connect_phase

endclass : mem_agent

❮ Previous Next ❯

UVM Monitor

 UVM Monitor

  • The user-defined monitor is extended from uvm_monitor, uvm_monitor is inherited by uvm_component
  • A monitor is a passive entity that samples the DUT signals through the virtual interface and converts the signal level activity to the transaction level
  • Monitor samples DUT signals but does not drive them

The monitor should have an analysis port (TLM port) and a virtual interface handle that points to DUT signals.

Writing Monitor :

1. The monitor is written by extending the UVM_MONITOR,

class mem_monitor extends uvm_monitor;

  `uvm_component_utils(mem_monitor)

  // new - constructor
  function new (string name, uvm_component parent);
    super.new(name, parent);
    trans_collected = new();
    item_collected_port = new("item_collected_port", this);
  endfunction : new

endclass : mem_monitor

2. Declare virtual interface,

  // Virtual Interface
  virtual mem_if vif;

3. Connect interface to Virtual interface by using get method,

  function void build_phase(uvm_phase phase);
    super.build_phase(phase);
    if(!uvm_config_db#(virtual mem_if)::get(this, "", "vif", vif))
       `uvm_fatal("NOVIF",{"virtual interface must be set for: ",get_full_name(),".vif"});
  endfunction: build_phase

4. Declare analysis port,

  uvm_analysis_port #(mem_seq_item) item_collected_port;

5. Declare seq_item handle, Used as a place holder for sampled signal activity,

  mem_seq_item trans_collected;

6. Add Sampling logic in run_phase,

7. After sampling, by using the write method send the sampled transaction packet to the scoreboard,

  item_collected_port.write(trans_collected);

 Complete monitor code,

class mem_monitor extends uvm_monitor;

  // Virtual Interface
  virtual mem_if vif;

  uvm_analysis_port #(mem_seq_item) item_collected_port;

  // Placeholder to capture transaction information.
  mem_seq_item trans_collected;

  `uvm_component_utils(mem_monitor)

  // new - constructor
  function new (string name, uvm_component parent);
    super.new(name, parent);
    trans_collected = new();
    item_collected_port = new("item_collected_port", this);
  endfunction : new

  function void build_phase(uvm_phase phase);
    super.build_phase(phase);
    if(!uvm_config_db#(virtual mem_if)::get(this, "", "vif", vif))
       `uvm_fatal("NOVIF",{"virtual interface must be set for: ",get_full_name(),".vif"});
  endfunction: build_phase

  // run phase
  virtual task run_phase(uvm_phase phase);
    item_collected_port.write(trans_collected);
  endtask : run_phase

endclass : mem_monitor

❮ Previous Next ❯

UVM Configuration Database

UVM Config db

The configuration database provides access to a centralized database, where type specific information can be stored and received. config_db can contain scalar objects, class handles, queues, lists, or even virtual interfaces.

The database has both a name table and a type table and each resource is entered into both. Resources are stored in a database so that each resource can be retrieved by name or by type, and the database is globally accessible.

uvm config db get and set

uvm_config_db::set and uvm_config_db::get methods are used to store and retrieve the information from the database respectively.

uvm config db set method

void uvm_config_db#(type T = int)::set(uvm_component cntxt, string inst_name, string field_name, T value);

Where,

  • T  is the type of element being configured. Type can be scalar objects, class handles, queues, lists, or even virtual interfaces)
  • cntxt is the hierarchical starting point of where the database entry is accessible.
  • inst_name is a hierarchical path that limits the accessibility of the database entry.

example:

top.env.agent.monitor
top.*               – all of the scopes whose top-level component is top.
top.env.*.monitor   – all of the scopes in env that end in the monitor;

  • field_name is the label used as a lookup for the database entry
  • value is the value to be stored in the database

uvm_config_db set example

Below example shows, setting the interface handle intf, type mem_if, label mem_intf with global scope.

  mem_if intf(clk,reset);  //interface instance
  uvm_config_db#(virtual mem_if)::set(null,"*","mem_intf",intf);  //set method
uvm config db get and set
uvm config db get and set

The above diagrams illustrate how a resource whose name is mem_intf and type is mem_if is stored in the pool.

uvm config db get method

bit uvm_config_db#(type T=int)::get(uvm_component cntxt, string inst_name, string field_name, ref T value);
  • value is the variable to which the value is to be retrieved from the database

* The other fields are the same as in set method.
The method returns 1 if it is successful and 0 if there is no such resource of this type in the database.

uvm_config_db get example

Below example shows. Using the get method to get a virtual interface handle from a database and assigns it to mem_vif. If the get method fails, the fatal message will be displayed.

    virtual interface mem_if mem_vif;    //virtual interface declaration
    if( !uvm_config_db#(virtual mem_if)::get(this,"*", "mem_intf", mem_vif))
      `uvm_fatal(get_full_name(),{"virtual interface must be set for:",".mem_vif"} ); //get method

❮ Previous Next ❯

UVM Interview Questions

UVM Interview Questions


Below are the most frequently asked
 UVM Interview Questions,

    1. What is uvm_transaction, uvm_seq_item, uvm_object, uvm_component?
    2. What is the advantage of  `uvm_component_utils() and `uvm_object_utils() ?
    3. What is the difference between `uvm_do and `uvm_ran_send?
    4. diff between uvm_transaction and uvm_seq_item?
    5. What is the difference between uvm _virtual_sequencer and uvm_sequencer?
    6. What are the benefits of using UVM?
    7. What is the super keyword? What is the need of calling super.build() and super.connect()?
    8. Is uvm is independent of systemverilog ?
    9. Can we have a user-defined phase in UVM?
    10. What is p_sequencer?
    11. What is the uvm RAL model? why it is required?
    12. What is the difference between new() and create?
    13. What is an analysis port?
    14. What is TLM FIFO?
    15. How the sequence starts?
    16. What is the difference between UVM RAL model backdoor write/read and front door write/read?
    17. What is an objection?
    18. What is the advantage of `uvm_pre_body and `uvm_post_body?
    19. What is the difference between Active mode and Passive mode?
    20. What is the difference between copy and clone?
    21. What is the UVM factory?
    22. What are the types of sequencer? Explain each?
    23. What are the different phases of uvm_component? Explain each?
    24. How set_config_* works?
    25. What are the advantages of the uvm RAL model?
    26. What is the different between set_config_* and uvm_config_db?
    27. What are the different override types?
    28. What is virtual sequence and virtual sequencer?
    29. Explain the end of the simulation in UVM?
    30. How to declare multiple imports?
    31. What is the symbolic representation of port, export and analysis port?
    32. What is the difference in usage of $finish and global stop request in UVM?
    33. Why we need to register class with the uvm factory?
    34. can we use set_config and get_config in sequence?
    35. What is the uvm_heartbeat ?
    36. how to access DUT signal in uvm_component/uvm_object?