Driver data not getting propagated to the DUT

I wrote this code for “Introducing Transactions” class under Basic UVM course.

I am sending some sample address, command, and data from the driver. However, DUT is not
receiving the data. I pasted most relevant SV files in my TB at the top. Please help me point to the error.

**Here is the output
**__UVM_INFO @ 0: reporter [RNTST] Running test my_test…
$time = 105, addr = 0, data = 0, cmd = x

UVM_INFO @ 200: reporter [TEST_DONE] ‘run’ phase is ready to proceed to the ‘extract’ phase
UVM_INFO @ 200: reporter [UVM/REPORT/CATCHER]

**Here is the Code base
**__

DUT Interface —> dut_if.sv


interface dut_if;

logic clock, reset;
logic cmd;
int data, addr;

endinterface

DUT Config File

class dut_config extends uvm_object;

`uvm_object_utils(dut_config)

function new(string name = "dut_config");
    
endfunction

virtual dut_if dut_vif;
        
endclass

DUT module —> dut_module.sv

module dut(dut_if _if);

initial begin
    _if.clock = 0;
    
    #5 _if.clock = ~_if.clock;
    
    #100 $display("$time = %d, addr = %d, data = %d, cmd = %d \n", $time, _if.addr, _if.data, _if.cmd); 
end

always@(_if.data or _if.cmd or _if.addr) begin
    $display("$time = %d, addr = %d, data = %d, cmd = %d \n", $time, _if.addr, _if.data, _if.cmd);    
    
end

endmodule : dut

Driver → my_driver.svh

class my_driver extends uvm_driver#(my_transaction);

`uvm_component_utils(my_driver)

  dut_config dut_config_0;
    
//virtual interface dut_if dut_vif;

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

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

function void connect_phase(uvm_phase phase);

    if(!uvm_config_db#(dut_config)::get(this, "", "dut_config", dut_config_0))
        `uvm_fatal(get_type_name(), "Could not instantiate dut_config in my_driver")
endfunction


task run_phase(uvm_phase phase);
    my_transaction tx;
    @(posedge dut_config_0.dut_vif.clock);
    seq_item_port.get_next_item(tx);
    
    dut_config_0.dut_vif.addr = tx.addr;
    dut_config_0.dut_vif.cmd= tx.cmd;
    dut_config_0.dut_vif.data = tx.data;
       @(posedge dut_config_0.dut_vif.clock);
   
    seq_item_port.item_done();

endtask
endclass

Top Module → top.sv

module top; 

import uvm_pkg::*;
import my_pkg::*;

dut_if dut_if1();

dut dut_inst(._if(dut_if1));

initial 
begin
    uvm_config_db#(virtual dut_if)::set(null, "uvm_test_top", "dut_vif", dut_if1);
    run_test("my_test");
end

endmodule : top

Top level Test —> my_test.svh

class my_test extends uvm_test;

`uvm_component_utils(my_test)

 my_env my_env_h;
 dut_config dut_config_0;

 function new(string name, uvm_component parent);
    super.new(name, parent);

    my_env_h = my_env::type_id::create("my_env_h", this);

 endfunction

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

     dut_config_0  = new();
     
    if(!uvm_config_db#(virtual dut_if)::get(this, "", "dut_vif", dut_config_0.dut_vif))
        `uvm_fatal(get_type_name(), "dut_if has not been instantiated")
    
    uvm_config_db#(dut_config)::set(this, "*", "dut_config", dut_config_0);
 endfunction

task run_phase(uvm_phase phase);
    phase.raise_objection(this);
    
    #200;
    phase.drop_objection(this);
    
    

endtask

endclass : my_test

Env File → my_env.svh

class my_env extends uvm_env;

`uvm_component_utils(my_env)

my_agent my_agent_h;

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

function void build_phase(uvm_phase phase);
    super.build_phase(phase);
    my_agent_h = my_agent::type_id::create("my_agent_h", this);
endfunction

task run_phase(uvm_phase phase);

endtask 

endclass : my_env

Agent → my_agent.svh

class my_agent extends uvm_agent;
   
    `uvm_component_utils(my_agent)
    
    
    my_driver my_driver_h;
    my_sequencer my_sequencer_h;
    my_monitor my_monitor_h;
    
    function new(string name, uvm_component parent);
        super.new(name, parent);
    endfunction
    
    function void build_phase(uvm_phase phase);
        super.build_phase(phase);
        
        if(is_active == UVM_ACTIVE) begin
            my_driver_h = my_driver::type_id::create("my_driver_h", this);
            my_sequencer_h = my_sequencer::type_id::create("my_sequencer_h", this);
        end
        
        my_monitor_h = my_monitor::type_id::create("my_monitor_h", this);
    endfunction
   
   function void connect_phase(uvm_phase phase);
       if(is_active == UVM_ACTIVE)
            my_driver_h.seq_item_port.connect(my_sequencer_h.seq_item_export);
   endfunction
 endclass

Sequence —> my_sequence.svh

class my_sequence extends uvm_sequence#(my_transaction);
    
`uvm_object_utils(my_sequence)    
    
function new(string name = "");
    super.new(name);    
endfunction

task body();
    forever begin
       my_transaction tx = my_transaction::type_id::create("tx");
       
       start_item(tx);
       if(!tx.randomize()) 
           `uvm_fatal(get_type_name(), "Randomization of my_transaction instance failed")
        
       finish_item(tx); 
    end    
endtask

endclass

Sequence Item


class my_transaction extends uvm_sequence_item;
  
  `uvm_object_utils(my_transaction)
   
   rand bit cmd;
    rand int addr;
    rand int data;
    
   function new(string name = "");
    super.new(name);    
   endfunction
   
   constraint c_addr {addr >= 0; addr <256;}
   
   constraint c_data {addr >= 0; addr <256;}
endclass
typedef uvm_sequencer #(my_transaction) my_sequencer;

In reply to Coppola:

Would be great if you could put your example to EDAPlayground (edaplayground.com) to have an executable piece of code.
Only a few remarks:
(1) in your DUT you have your clock generator, but you generating only 1 edge.
(2) In the constructor of your config bals the constructor call to the base class is missimng. It should be

class dut_config extends uvm_object;
`uvm_object_utils(dut_config) 
function new(string name = "dut_config");
  super.new(name);
endfunction 
virtual dut_if dut_vif;
endclass

In reply to chr_sue:

Thanks. I was indeed missing the clock. However, even after calling base class constructor and giving clock edges, i am not seeing change in my addr, data, and cmd.

I understand my code might be too cumbersome. Will explore using EDAPlayground .

Thx!!!

UVM_INFO @ 0: reporter [RNTST] Running test my_test…
$time = 5, addr = 0, data = 0, cmd = x

$time = 10, addr = 0, data = 0, cmd = x

$time = 15, addr = 0, data = 0, cmd = x

$time = 20, addr = 0, data = 0, cmd = x

$time = 25, addr = 0, data = 0, cmd = x

$time = 30, addr = 0, data = 0, cmd = x

In reply to Coppola:

Also, you never start your sequence

In reply to Coppola:

In reply to chr_sue:
Thanks. I was indeed missing the clock. However, even after calling base class constructor and giving clock edges, i am not seeing change in my addr, data, and cmd.
I understand my code might be too cumbersome. Will explore using EDAPlayground .
Thx!!!
UVM_INFO @ 0: reporter [RNTST] Running test my_test…
$time = 5, addr = 0, data = 0, cmd = x
$time = 10, addr = 0, data = 0, cmd = x
$time = 15, addr = 0, data = 0, cmd = x
$time = 20, addr = 0, data = 0, cmd = x
$time = 25, addr = 0, data = 0, cmd = x
$time = 30, addr = 0, data = 0, cmd = x

The data you see are the initial values of your class memebers. As Dave says you do not start the sequence. You should do this in your test.

In reply to chr_sue:

Thanks for the prompt replies. Once i started sequence in the test, i see the transaction flowing from driver to DUT.

task run_phase(uvm_phase phase);
    my_sequence seq;
    seq = my_sequence::type_id::create("seq");

    phase.raise_objection(this);
---
    seq.start(my_env_h.my_agent_h.my_sequencer_h);

    #200;

    phase.drop_objection(this);
----
----

endtask