noobuntu
noobuntu

Reputation: 913

Warning when setting uvm_reg values through a task

I am creating a framework where my verification team and I can write uvm test cases with ease. The basic idea is that my base (uvm_)sequence only contains the one line in its body task:

regs.update(status);

From my individual (uvm_)tests, I can set the register values using handy helper functions. For example, my tests would contain:

class base_test extends uvm_test;
    ........
    ........
    virtual function void set_registerA(....);
        regs.registerA1.set(....);
        regs.registerA2.set(....);
        regs.registerA3.set(....);
    endfunction

    virtual function void set_registerB(....);
        regs.registerB1.set(....);
        regs.registerB2.set(....);
        regs.registerB3.set(....);
    endfunction
endclass

class test1 extends base_test;
    virtual function void end_of_elaboration_phase(uvm_phase phase);
        set_registerA(....);
        set_registerB(....);
    endfunction
endclass

class test2 extends base_test;
    virtual function void end_of_elaboration_phase(uvm_phase phase);
        set_registerA(....);
        set_registerB(....);
    endfunction
endclass

Now I realize that end_of_elaboration phase may not be the best place to set the registers. My compiler gave me warnings that said "WARNING: Calling a task "set_registerA" in task "end_of_elaboration". So I changed it to execute in my run_phase:

class test1 extends base_test;
    virtual task run_phase(uvm_phase phase);
        super.run_phase(phase);
        set_registerA(....);
        set_registerB(....);
    endfunction
endclass

class test2 extends base_test;
    virtual task run_phase(uvm_phase phase);
        super.run_phase(phase);
        set_registerA(....);
        set_registerB(....);
    endfunction
endclass

I am unsure if this is the right methodology for what I am trying to do? Does calling super.run_phase cause problems? I don't see this done anywhere else.

Upvotes: 1

Views: 869

Answers (3)

Nikunj Hinsu
Nikunj Hinsu

Reputation: 19

You had figured out it correct uvm_end_of_elaboration_phase is mainly used to fine-tune our testbench, so it is not a good place to set your registers.

I would suggest Run-Time phases would be better place to set your registers, But instead of using common phase i.e. virtual task run_phase(uvm_phase phase);

We can split-it up into UVM predefined run-time phases which are

UVM Run Time Phases

Outta of which we can select "uvm_configure_phase" & "uvm_main_phase", So suggested pseudo code edit would be as,

  class base_test extends uvm_test;
    ........
    ........
    virtual function void set_registerA(....);
        regs.registerA1.set(....);
        regs.registerA2.set(....);
        regs.registerA3.set(....);
    endfunction

    virtual function void set_registerB(....);
        regs.registerB1.set(....);
        regs.registerB2.set(....);
        regs.registerB3.set(....);
    endfunction

   task main_phase (uvm_phase phase)
   // Copy your run_phase code over here
   endtask : main_phase

 endclass

class test1 extends base_test;
    virtual task configure_phase(uvm_phase phase);
        set_registerA(....);
        set_registerB(....);
    endtask

    virtual task main_phase(uvm_phase phase);
        super.main_phase(phase);
    endtask : main_phase
endclass

class test2 extends base_test;
    virtual task configure_phase(uvm_phase phase);
        set_registerA(....);
        set_registerB(....);
    endtask : configure_phase

    virtual task main_phase(uvm_phase phase);
        super.main_phase(phase);
    endtask : main_phase
endclass

Hope this solves your problem!!!

Upvotes: 1

Meir
Meir

Reputation: 299

2 possible solutions come to mind: 1. You could give up the idea of a base sequence, create different sequences & set the registers in the body() and then call update(). Or if you really want to use a base sequence you could set the registers in pre_body then in body call super.body which will do the update. From a methodology point of view I think that setting values to registers (which through the update really translates to reg.write()) belongs in the sequence not the test. 2. You could leave the setregs in the test If you start the sequence in the test main_phase, before doing seq.start(seqr), all the registers could be set

In order to use only 1 test with alternating sequences add in the test file:

function void build_phase(uvm_phase phase);
      string seq_name;
      uvm_sequence_base seq;
      uvm_factory factory= uvm_factory::get();

      super.build_phase(phase);

      $value$plusargs("SEQ_NAME=%s", seq_name); 
      .......    

 if(! $cast(seq, factory.create_object_by_name(seq_name)))
     `uvm_fatal("", "Failed to create sequence")
  if(seq == null)
     `uvm_fatal("", "no sequence created seq=null!!")

  uvm_config_db #(uvm_sequence_base)::set(this, "master.sequencer.main_phase" ,"default_sequence", seq);

then on the command line add: +SEQ_NAME=rand_seq

Upvotes: 1

Tudor Timi
Tudor Timi

Reputation: 7573

I personally don't like calling super.run_phase(...) because it can create problems if you want to implement something that was defined in a grandparent class. If you don't expect having a test inherit from a test inheriting from a test, then you shouldn't have any problems. The main idea is that the run_phase will almost always get overridden, but end_of_elaboration/start_of_simulation less so, which is why it would be a better candidate for more general things.

W.r.t. to your compile issue, check that you didn't create tasks instead of functions for your set_register* functions. Your compiler might be more lenient and allow you to start tasks inside functions (end_of_elaboration is a function), most probably by doing the equivalent of a fork...join_none

Upvotes: 1

Related Questions