Reputation: 913
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
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
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
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
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