|HOME |ABOUT |ARTICLES |ACK |FEEDBACK |TOC |LINKS |BLOG |JOBS |


Tutorials



PHASE 6 DRIVER


Driver



In this phase we will develop the driver. Driver is defined by extending uvm_driver. Driver takes the transaction from the sequencer using seq_item_port. This transaction will be driven to DUT as per the interface specification. After driving the transaction to DUT, it sends the transaction to scoreboard using uvm_analysis_port.

In driver class, we will also define task for resetting DUT and configuring the DUT. After completing the driver class implementation, we will instantiate it in environment class and connect the sequencer to it. We will also update the test case and run the simulation to check the implementation which we did till now.






1) Define the driver class by extending uvm_driver;


`ifndef GUARD_DRIVER
`define GUARD_DRIVER

class Driver extends uvm_driver #(Packet);

endclass : Driver


2) Create a handle to configuration object. Using this object we can get DUT interfaces and DUT port addresses.


Configuration cfg;


3) Declare input and memory interfaces


virtual input_interface.IP input_intf;
virtual mem_interface.MEM mem_intf;


4) Declare uvm_analysis_port which is used to send packets to scoreboard.


uvm_analysis_port #(Packet) Drvr2Sb_port;


5) Declare component utilities macro.


`uvm_component_utils(Driver)


6) Define the constructor method. Pass the parent object to super class.


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


7) In the build method and construct Drvr2Sb_port object.


virtual function void build();
super.build();
Drvr2Sb_port = new("Drvr2Sb_port", this);
endfunction : build


8) In the end_of_elaboration() method, get the configuration object using get_config_object and update the virtual interfaces.


virtual function void end_of_elaboration();
uvm_object tmp;
super.end_of_elaboration();
assert(get_config_object("Configuration",tmp));
$cast(cfg,tmp);
this.input_intf = cfg.input_intf;
this.mem_intf = cfg.mem_intf;
endfunction : end_of_elaboration



9) Define the reset_dut() method which will be used for resetting the DUT.


virtual task reset_dut();
uvm_report_info(get_full_name(),"Start of reset_dut() method ",UVM_LOW);
mem_intf.mem_data <= 0;
mem_intf.mem_add <= 0;
mem_intf.mem_en <= 0;
mem_intf.mem_rd_wr <= 0;
input_intf.data_in <= 0;
input_intf.data_status <= 0;

input_intf.reset <= 1;
repeat (4) @ input_intf.clock;
input_intf.reset <= 0;

uvm_report_info(get_full_name(),"End of reset_dut() method ",UVM_LOW);
endtask : reset_dut



10) Define the cfg_dut() method which does the configuration due port address.


virtual task cfg_dut();
uvm_report_info(get_full_name(),"Start of cfg_dut() method ",UVM_LOW);
mem_intf.cb.mem_en <= 1;
@(mem_intf.cb);
mem_intf.cb.mem_rd_wr <= 1;

foreach (cfg.device_add[i]) begin

@(mem_intf.cb);
mem_intf.cb.mem_add <= i;
mem_intf.cb.mem_data <= cfg.device_add[i];
uvm_report_info(get_full_name(),$psprintf(" Port %0d Address %h ",i,cfg.device_add[i]),UVM_LOW);

end

@(mem_intf.cb);
mem_intf.cb.mem_en <=0;
mem_intf.cb.mem_rd_wr <= 0;
mem_intf.cb.mem_add <= 0;
mem_intf.cb.mem_data <= 0;

uvm_report_info(get_full_name(),"End of cfg_dut() method ",UVM_LOW);
endtask : cfg_dut


11) Define drive() method which will be used to drive the packet to DUT. In this method pack the packet fields using the pack_bytes() method of the transaction and drive the packed data to DUT interface.


virtual task drive(Packet pkt);
byte unsigned bytes[];
int pkt_len;
pkt_len = pkt.pack_bytes(bytes);
uvm_report_info(get_full_name(),"Driving packet ...",UVM_LOW);

foreach(bytes[i])
begin
@(input_intf.cb);
input_intf.data_status <= 1 ;
input_intf.data_in <= bytes[i];
end

@(input_intf.cb);
input_intf.data_status <= 0 ;
input_intf.data_in <= 0;
repeat(2) @(input_intf.cb);
endtask : drive


12) Now we will use the above 3 defined methods and update the run() method of uvm_driver.
First call the reset_dut() method and then cfg_dut(). After completing the configuration, in a forever loop get the transaction from seq_item_port and send it DUT using drive() method and also to scoreboard using Drvr2SB_port .


virtual task run();
Packet pkt;
@(input_intf.cb);
reset_dut();
cfg_dut();
forever begin
seq_item_port.get_next_item(pkt);
Drvr2Sb_port.write(pkt);
@(input_intf.cb);
drive(pkt);
@(input_intf.cb);
seq_item_port.item_done();
end
endtask : run


(S) Driver class source code

`ifndef GUARD_DRIVER
`define GUARD_DRIVER

class Driver extends uvm_driver #(Packet);

Configuration cfg;

virtual input_interface.IP input_intf;
virtual mem_interface.MEM mem_intf;

uvm_analysis_port #(Packet) Drvr2Sb_port;

`uvm_component_utils(Driver)

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

virtual function void build();
super.build();
Drvr2Sb_port = new("Drvr2Sb", this);
endfunction : build

virtual function void end_of_elaboration();
uvm_object tmp;
super.end_of_elaboration();
assert(get_config_object("Configuration",tmp));
$cast(cfg,tmp);
this.input_intf = cfg.input_intf;
this.mem_intf = cfg.mem_intf;
endfunction : end_of_elaboration

virtual task run();
Packet pkt;
@(input_intf.cb);
reset_dut();
cfg_dut();
forever begin
seq_item_port.get_next_item(pkt);
Drvr2Sb_port.write(pkt);
@(input_intf.cb);
drive(pkt);
@(input_intf.cb);
seq_item_port.item_done();
end
endtask : run

virtual task reset_dut();
uvm_report_info(get_full_name(),"Start of reset_dut() method ",UVM_LOW);
mem_intf.mem_data <= 0;
mem_intf.mem_add <= 0;
mem_intf.mem_en <= 0;
mem_intf.mem_rd_wr <= 0;
input_intf.data_in <= 0;
input_intf.data_status <= 0;

input_intf.reset <= 1;
repeat (4) @ input_intf.clock;
input_intf.reset <= 0;

uvm_report_info(get_full_name(),"End of reset_dut() method ",UVM_LOW);
endtask : reset_dut

virtual task cfg_dut();
uvm_report_info(get_full_name(),"Start of cfg_dut() method ",UVM_LOW);
mem_intf.cb.mem_en <= 1;
@(mem_intf.cb);
mem_intf.cb.mem_rd_wr <= 1;

foreach (cfg.device_add[i]) begin

@(mem_intf.cb);
mem_intf.cb.mem_add <= i;
mem_intf.cb.mem_data <= cfg.device_add[i];
uvm_report_info(get_full_name(),$psprintf(" Port %0d Address %h ",i,cfg.device_add[i]),UVM_LOW);

end

@(mem_intf.cb);
mem_intf.cb.mem_en <=0;
mem_intf.cb.mem_rd_wr <= 0;
mem_intf.cb.mem_add <= 0;
mem_intf.cb.mem_data <= 0;

uvm_report_info(get_full_name(),"End of cfg_dut() method ",UVM_LOW);
endtask : cfg_dut

virtual task drive(Packet pkt);
byte unsigned bytes[];
int pkt_len;
pkt_len = pkt.pack_bytes(bytes);
uvm_report_info(get_full_name(),"Driving packet ...",UVM_LOW);

foreach(bytes[i])
begin
@(input_intf.cb);
input_intf.data_status <= 1 ;
input_intf.data_in <= bytes[i];
end

@(input_intf.cb);
input_intf.data_status <= 0 ;
input_intf.data_in <= 0;
repeat(2) @(input_intf.cb);
endtask : drive

endclass : Driver

`endif

Environment Updates



We will take the instance of Sequencer and Driver and connect them in Environment class.






1) Declare handles to Driver and Sequencer.


Sequencer Seqncr;
Driver Drvr;


2) In build method, construct Seqncr and Drvr object using create() method.


Drvr = Driver::type_id::create("Drvr",this);
Seqncr = Sequencer::type_id::create("Seqncr",this);


2) In connect() method connect the sequencer seq_item_port to drivers seq_item_export.


Drvr.seq_item_port.connect(Seqncr.seq_item_export);

(S)Environment class code

`ifndef GUARD_ENV
`define GUARD_ENV

class Environment extends uvm_env;

`uvm_component_utils(Environment)

Sequencer Seqncr;
Driver Drvr;

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

virtual function void build();
super.build();
uvm_report_info(get_full_name(),"START of build ",UVM_LOW);

Drvr = Driver::type_id::create("Drvr",this);
Seqncr = Sequencer::type_id::create("Seqncr",this);

uvm_report_info(get_full_name(),"END of build ",UVM_LOW);
endfunction

virtual function void connect();
super.connect();
uvm_report_info(get_full_name(),"START of connect ",UVM_LOW);

Drvr.seq_item_port.connect(Seqncr.seq_item_export);

uvm_report_info(get_full_name(),"END of connect ",UVM_LOW);
endfunction


endclass : Environment

`endif

Testcase Updates



We will update the testcase and run the simulation.

1)In the build() method, update the configuration address in the configuration object which in top module.


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

cfg.device_add[0] = 0;
cfg.device_add[1] = 1;
cfg.device_add[2] = 2;
cfg.device_add[3] = 3;


2) In the build() method itself, using set_config_object , configure the configuration object with the one which is in top module.
with this, the configuration object in Sequencer and Driver will be pointing to the one which in top module.


set_config_object("t_env.*","Configuration",cfg);


3) In the build method, using set_config_string, configure the default_sequence of the sequencer to use the sequence which we defined.


set_config_string("*.Seqncr", "default_sequence", "Seq_device0_and_device1");


4) Set the sequencer count value to 2 .


set_config_int("*.Seqncr", "count",2);


5) Update the run() method to print the Sequencer details.


t_env.Seqncr.print();

(S)Testcase code

class test1 extends uvm_test;

`uvm_component_utils(test1)

Environment t_env ;

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

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

cfg.device_add[0] = 0;
cfg.device_add[1] = 1;
cfg.device_add[2] = 2;
cfg.device_add[3] = 3;

set_config_object("t_env.*","Configuration",cfg);
set_config_string("*.Seqncr", "default_sequence", "Seq_device0_and_device1");
set_config_int("*.Seqncr", "count",2);

endfunction

virtual task run ();

t_env.Seqncr.print();

#3000ns;
global_stop_request();
endtask : run

endclass : test1


(S)Download the source code


uvm_switch_6.tar
Browse the code in uvm_switch_6.tar


(S)Command to run the simulation


VCS Users : make vcs
Questa Users: make questa



(S)Log report after simulation

UVM_INFO @ 0 [RNTST] Running test test1...
UVM_INFO @ 0: uvm_test_top.t_env [uvm_test_top.t_env] START of build
UVM_INFO @ 0: uvm_test_top.t_env [uvm_test_top.t_env] END of build
UVM_INFO @ 0: uvm_test_top.t_env [uvm_test_top.t_env] START of connect
UVM_INFO @ 0: uvm_test_top.t_env [uvm_test_top.t_env] END of connect
----------------------------------------------------------------------
Name Type Size Value
----------------------------------------------------------------------
Seqncr Sequencer - Seqncr@14
--rsp_export uvm_analysis_export - rsp_export@16
--seq_item_export uvm_seq_item_pull_+ - seq_item_export@40
--default_sequence string 19 uvm_random_sequence
--count integral 32 -1
--max_random_count integral 32 'd10
--sequences array 5 -
----[0] string 19 uvm_random_sequence
----[1] string 23 uvm_exhaustive_sequ+
----[2] string 19 uvm_simple_sequence
----[3] string 23 Seq_device0_and_dev+
----[4] string 19 Seq_constant_length
--max_random_depth integral 32 'd4
--num_last_reqs integral 32 'd1
--num_last_rsps integral 32 'd1
----------------------------------------------------------------------
UVM_INFO @ 30: uvm_test_top.t_env.Drvr [uvm_test_top.t_env.Drvr]
Start of reset_dut() method
UVM_INFO @ 70: uvm_test_top.t_env.Drvr [uvm_test_top.t_env.Drvr]
End of reset_dut() method
UVM_INFO @ 70: uvm_test_top.t_env.Drvr [uvm_test_top.t_env.Drvr]
Start of cfg_dut() method
UVM_INFO @ 110: uvm_test_top.t_env.Drvr [uvm_test_top.t_env.Drvr]
Port 0 Address 00
UVM_INFO @ 130: uvm_test_top.t_env.Drvr [uvm_test_top.t_env.Drvr]
Port 1 Address 01
UVM_INFO @ 150: uvm_test_top.t_env.Drvr [uvm_test_top.t_env.Drvr]
Port 2 Address 02
UVM_INFO @ 170: uvm_test_top.t_env.Drvr [uvm_test_top.t_env.Drvr]
Port 3 Address 03
UVM_INFO @ 190: uvm_test_top.t_env.Drvr [uvm_test_top.t_env.Drvr]
End of cfg_dut() method
UVM_INFO @ 210: uvm_test_top.t_env.Drvr [uvm_test_top.t_env.Drvr]
Driving packet ...
UVM_INFO @ 590: uvm_test_top.t_env.Drvr [uvm_test_top.t_env.Drvr]
Driving packet ...
UVM_INFO @ 970: uvm_test_top.t_env.Drvr [uvm_test_top.t_env.Drvr]
Driving packet ...

--- UVM Report Summary ---

** Report counts by severity
UVM_INFO : 16
UVM_WARNING : 0
UVM_ERROR : 0
UVM_FATAL : 0

Index
Introduction
Specification
Verification Plan
Phase 1 Top
Phase 2 Configuration
Phase 3 Environment N Testcase
Phase 4 Packet
Phase 5 Sequencer N Sequence
Phase 6 Driver
Phase 7 Receiver
Phase 8 Scoreboard

Report a Bug or Comment on This section - Your input is what keeps Testbench.in improving with time!





<< PREVIOUS PAGE

TOP

NEXT PAGE >>

copyright 2007-2017 :: all rights reserved www.testbench.in::Disclaimer