Individual tests extending from base test

Hello,

I have a basic question in all other tests ( apb_test_1, apb_test_2, apb_test_3 )
extending from apb_base_test. I have separate sequences for each test
apb_test_1 has apb_sequence_1 which need to be run in sequencer
apb_test_2 has apb_sequence_2 which need to be run in sequencer.

My question is since I am extending these tests from apb_base_test,
can I skip these
// 1. apb_env env; virtual dut_if if;
// 2. function new
// 3. build_phase
and directly write run_phase() method, and start the corresponding sequencer
OR
Do I need to write all 1,2,3 above?

JeffD

class apb_base_test extends uvm_test;
`uvm_component_utils(apb_base_test);
  
  apb_env  env;
  virtual dut_if vif;
  
  function new(string name = "apb_base_test", uvm_component parent = null);
    super.new(name, parent);
  endfunction

  function void build_phase(uvm_phase phase);
    env = apb_env::type_id::create("env", this);
    if (!uvm_config_db#(virtual dut_if)::get(this, "", "vif", vif)) begin
      `uvm_fatal("build_phase", "No virtual interface specified for this test instance")
    end 
    uvm_config_db#(virtual dut_if)::set( this, "env", "vif", vif);
  endfunction

  //Run phase - Create an abp_sequence and start it on the apb_sequencer
  task run_phase( uvm_phase phase );
    apb_sequence apb_seq;
    apb_seq = apb_sequence::type_id::create("apb_seq");
    phase.raise_objection( this, "Starting apb_base_seqin main phase" );
    $display("%t Starting sequence apb_seq run_phase",$time);
    apb_seq.start(env.agt.sqr);
    #100ns;
    phase.drop_objection( this , "Finished apb_seq in main phase" );
  endtask
  
endclass


class apb_test_1 extends apb_base_test;
  //  Since I am extending from apb_base_test above,   do I need to 
  //  1. apb_env env;  virtual dut_if if;
  //  2. function new 
  //  3. build_phase
  //  4. 
endclass

In reply to dvuvmsv:

When extending any class, you must define a new() if there are constructor arguments that need to be passed down.

You should definitely not re-declare env or vif. The whole point of inheritance is using the variable declared in the base class.

Whether or not you override build_phase or run_phase depends on how different each test is. If the only different is which sequence to start, than you can use the build_phase to set a factory override, and then you don’t need a different run_phase for each test.

class apb_test_1 extends apb_base_test;
 function new(string name = "apb_test_1", uvm_component parent = null);
    super.new(name, parent);
  endfunction
  function void build_phase(uvm_phase phase);
    set_type_override_by_type(apb_sequence::get_type(), apb_sequence_1::get_type());
    super.build_phase(phase);
  endfunction
endclass

Thank you Dave for your response. You gave an example for factory override
and that way we don’t need to have a run_phase. Just override the apb_sequence with apb_sequence_1

Otherwise we need to have the following with run_phase.

class apb_test_1 extends apb_base_test;

`uvm_component_utils(apb_test_1);

function new(string name = “apb_test_1”, uvm_component parent = null);
super.new(name, parent);
endfunction

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

task run_phase( uvm_phase phase );
apb_sequence_1 apb_seq_1;
apb_seq_1 = apb_sequence_1::type_id::create(“apb_seq_1”);
phase.raise_objection( this, “Starting apb_sequence_1 in main phase” );
$display(“%t Starting sequence apb_seq_1 run_phase”,$time);
apb_seq_1.start(env.agt.sqr);
#100ns;
phase.drop_objection( this , “Finished apb_seq_1 in main phase” );
endtask

endclass

Hi,

I need to specify a addr=32'100 and data=32'd200 using `uvm_do_with in a sequence.

Here I am not randomizing. When I run the test , I am not getting addr 32’d100 and data 32’d200. Is there anything wrong with this ?

class apb_transaction extends uvm_sequence_item;

`uvm_object_utils(apb_transaction)

//typedef for READ/Write transaction type
typedef enum {READ, WRITE} kind_e;
rand bit [31:0] addr; //Address
rand bit [31:0] data; //Data - For write or read response
rand kind_e pwrite; //command type

constraint c1{addr[31:0]>=32’d0; addr[31:0] <32’d256;};
constraint c2{data[31:0]>=32’d0; data[31:0] <32’d256;};

function new (string name = “apb_transaction”);
super.new(name);
endfunction

function string convert2string();
return $psprintf(“pwrite=%s paddr=%0h data=%0h”,pwrite,addr,data);
endfunction

endclass

class apb_sequence_2 extends uvm_sequence#(apb_transaction);
`uvm_object_utils(apb_sequence_2)

function new (string name = “”);
super.new(name);
endfunction

task body();
apb_transaction rw_trans_2;
repeat(1)
begin
rw_trans_2=new();
`uvm_do_with(rw_trans_2, {rw_trans_2.addr == 32’d100;
rw_trans_2.data == 32’d200;
rw_trans_2.pwrite == WRITE;
});

end

endtask

endclass

class apb_test_2 extends apb_base_test;

`uvm_component_utils(apb_test_2);

function new(string name = “apb_test_2”, uvm_component parent = null);
super.new(name, parent);
endfunction

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

task run_phase( uvm_phase phase );
apb_sequence_2 apb_seq_2;
apb_seq_2 = apb_sequence_2::type_id::create(“apb_seq_2”);
phase.raise_objection( this, “Starting apb_sequence_2 in main phase” );
$display(“%t Starting sequence apb_seq_2 run_phase”,$time);
apb_seq_2.start(env.agt.sqr);
#100ns;
phase.drop_objection( this , “Finished apb_seq_2 in main phase” );
endtask

endclass

JeffD

In reply to dvuvmsv:

I see 2 weaknesses in your code:
(1) constructing your seq_item

rw_trans_2=new();

It should be like this (using the create of the factory):

rw_trans_2 = apb_transaction::type_id::create("rw_trans_2");

(2) never use $display in your UVM code use instead `uvm_info

Both do not influence the seq_item generation.
But you do not show which test you are executing.

Thanks chr_sue for the suggestions.
I was able to get the specific address.
It was a %h vs %d issue where the data was correct,
but in a different format and I could’nt recognize

JeffD