Driving Individual Pins

Hi, Is there a way to drive individual pins on the DUT instead of

task run_phase(uvm_phase phase);
  super.run_phase(phase);
  phase.raise_objection(this);
  #20
  drv_a=drv_a_seq::type_id::create("drv_a");
  drv_b=drv_b_seq::type_id::create("drv_b");
  drv_a.randomize() with {a inside {[10:10]}; };
  drv_b.randomize() with {b inside {[20:20]}; };
  drv_a.start(env_i.agt.seqr);
  drv_b.start(env_i.agt.seqr);
  #50;
  phase.drop_objection(this);
endtask

My TB Below:

`timescale 1ns/1ns

`include “uvm_macros.svh”
import uvm_pkg::*;

///////////////////////////////// Sequence Item ////////////////////////////

class seq_item extends uvm_sequence_item;

rand int data_in;
string name;

function new(input string path = "data_in");
  super.new(path);
endfunction

`uvm_object_utils_begin(seq_item);
`uvm_field_int(data_in,UVM_DEFAULT)
`uvm_field_string(name,UVM_DEFAULT)
`uvm_object_utils_end

endclass

///////////////////////////////// Sequencer ////////////////////////////////

class reset_seqr extends uvm_sequencer #(seq_item);

`uvm_component_utils_begin(reset_seqr);
`uvm_component_utils_end;

function new(input string path = "reset_seqr", uvm_component parent = null);
  super.new(path,parent);
endfunction

endclass

///////////////////////////////// Sequence /////////////////////////////////

class drv_a_seq extends uvm_sequence;

rand int a;

`uvm_object_utils_begin(drv_a_seq);
  `uvm_field_int(a,UVM_DEFAULT);
`uvm_object_utils_end

function new(input string path = "drv_a");
  super.new(path);
endfunction

virtual task body();
  reset_seqr intf_seqr;
  seq_item seq_item_i;
  intf_seqr = p_sequencer.pick_sequencer("reset_seqr");
  `uvm_do_on_with(seq_item_i,intf_seqr,{name == "a"; data_in == a;})
endtask

endclass

class drv_b_seq extends uvm_sequence;

rand int b;

`uvm_object_utils_begin(drv_b_seq);
  `uvm_field_int(b,UVM_DEFAULT)
`uvm_object_utils_end

function new(input string path = "drv_b");
  super.new(path);
endfunction

virtual task body();
  reset_seqr intf_seqr;
  seq_item seq_item_i;
  intf_seqr = p_sequencer.pick_sequencer("reset_seqr");
  `uvm_do_on_with(seq_item_i,intf_seqr,{name == "b"; data_in == b;})
endtask

endclass

///////////////////////////////// Driver ////////////////////////////////////

class driver extends uvm_driver;

  seq_item seq_item;
  virtual half_adder_if ha_if;

  `uvm_component_utils(driver);

  function new(input string path = "driver", uvm_component parent = null);
    super.new(path,parent);    
  endfunction

  virtual function void build_phase(uvm_phase phase);
    super.build_phase(phase);
      if(!uvm_config_db #(virtual half_adder_if)::get(this,"","ha_if",ha_if))
      `uvm_fatal("DRV","Unable to get an interface handle");
  endfunction

  virtual task run_phase(uvm_phase phase);
    forever begin
      seq_item_port.get_next_item(seq_item);
      case(seq_item.name)
        "a": begin
           ha_if.a <= seq_item.data_in;
           `uvm_info("DRV",$sformatf("Transaction Sent To DUT Pin=%0s, Data=%0d",seq_item.name,seq_item.data_in),UVM_NONE);
        end

        "b": begin
           ha_if.b <= seq_item.data_in;
           `uvm_info("DRV",$sformatf("Transaction Sent To DUT Pin=%0s, Data=%0d",seq_item.name,seq_item.data_in),UVM_NONE);
        end
      endcase
      seq_item_port.item_done();
      #10;
    end
  endtask

endclass

///////////////////////////////// Agent /////////////////////////////////////

class agent extends uvm_agent;

`uvm_component_utils(agent);

reset_seqr seqr;
driver drv;

function new(input string path = "agent", uvm_component parent = null);
  super.new(path,parent);
endfunction

virtual function void build_phase(uvm_phase phase);
  super.build_phase(phase);
  drv = driver::type_id::create("drv",this);
  seqr = reset_seqr::type_id::create("seqr",this);
endfunction

virtual function void connect_phase(uvm_phase phase);
  
  super.connect_phase(phase);
  drv.seq_item_port.connect(seqr.seq_item_export);
  
endfunction

endclass

///////////////////////////////// Env ///////////////////////////////////////

class env extends uvm_env;

`uvm_component_utils(env);
    
function new(input string path = "env", uvm_component parent = null);
  super.new(path,parent);  
endfunction

agent agt;

virtual function void build_phase(uvm_phase phase);
  super.build_phase(phase);
  agt = agent::type_id::create("agt",this);
endfunction

virtual function void connect_phase(uvm_phase phase);
  super.connect_phase(phase);
endfunction

endclass

///////////////////////////////// Test //////////////////////////////////////

class test extends uvm_test;

`uvm_component_utils(test);

function new(input string path = "test", uvm_component parent = null);
  super.new(path,parent);
endfunction
  
drv_a_seq drv_a;
drv_b_seq drv_b;

env env_i;

virtual function void build_phase(uvm_phase phase);
  super.build_phase(phase);
  env_i = env::type_id::create("env_i",this);
endfunction


task run_phase(uvm_phase phase);
  super.run_phase(phase);
  phase.raise_objection(this);
  #20
  `uvm_do_with(drv_a,{a == 10;});
  `uvm_do_with(drv_b,{b == 20;});
  #50;
  phase.drop_objection(this);
  
endtask

endclass

///////////////////////////////// TB TOP ////////////////////////////////////

module tb_top();

half_adder_if ha_if();

half_adder dut(
  .a (ha_if.a),
  .b (ha_if.b),
  .sum (ha_if.sum)
);

initial begin
  $dumpfile("dump.vcd");
  $dumpvars;
end

initial begin
  uvm_config_db #(virtual half_adder_if)::set(null,"uvm_test_top.env_i.agt.*","ha_if",ha_if);
  run_test("test");
end

endmodule

Can you explain what you mean by “drive individual pins on the DUT”?

In UVM, a driver will translate sequence items into pin-level transactions. You don’t control individual pins.

There are other methodologies you can use which will allow you to control individual pins, but UVM is not appropriate for this.

Instead of task run_phase(uvm_phase phase);
super.run_phase(phase);
phase.raise_objection(this);
#20
drv_a=drv_a_seq::type_id::create(“drv_a”);
drv_b=drv_b_seq::type_id::create(“drv_b”);
drv_a.randomize() with {a inside {[10:10]}; };
drv_b.randomize() with {b inside {[20:20]}; };
drv_a.start(env_i.agt.seqr);
drv_b.start(env_i.agt.seqr);
#50;
phase.drop_objection(this);
endtask

I would like to do

task run_phase(uvm_phase phase);
super.run_phase(phase);
phase.raise_objection(this);
#20
uvm_do_with(drv_a,{a == 10;}); uvm_do_with(drv_b,{b == 20;});
#50;
phase.drop_objection(this);
endtask

This is more cleaner way of driving instead of creating, randomizing and starting the sequencer.

Using the `uvm_do_* macros is not recommended, as it removes some of the controls that you may want to do with your sequences.

Using create/randomize/start gives better control and is the recommended approach.

Hi Charles,
Could you please elaborate which other methodologies aside of UVM could be used for it?