Reputation: 867
I need to monitor a status of a register. I have created a UVM sequence to read the register and store them locally. Now in my test code, I need to access these registers. Here is a sudo code:
typedef struct {
int a;
} my_regs;
class my_seq extends uvm_sequence;
// register to uvm db
reg_map map;
my_regs regs;
uvm_status_e status;
task build_phase(uvm_phase phase);
endtask
task run_phase(uvm_phase phase);
map.CORE.reg_a.read(status, regs.a, UVM_BACKDOOR)
endtask
endclass
class test_reg extends uvm_test;
// register to uvm db
my_seq seq;
my_regs regs;
task build_phase(uvm_phase phase);
seq = my_seq::type_id::create("reg_seq", this);
regs = seq.regs;
endtask
task run_phase(uvm_phase phase);
reg_seq.start(null);
// read reg values from seq??????
if(rqgs.a>1)
//do some thing
endtask
endclass
As you can see, I am constantly starting sequence so that I dont miss any updates. I believe the start task in sequence does not create a new object so the values inside the object should remain constant between the start calls.
Assuming that I dont read regs values from seq every time, the test class's regs will not get updates from seq. Meaning that the regs = seq.regs; does not create an actual reference to the seq.regs. I want to know why is that and how can I create an absolute reference to that object? (so that I dont waste simulation cycles on reading and updating the regs values in test class). Also please advise me if there is a better way of doing this.
Upvotes: 1
Views: 1096
Reputation: 792
Firstly a minor fix. A sequence does not have a build or run phases. They unlike other uvm_components are not started automatically [ using the phasing system]. A sequence has a body task which is overridden to implement the functionality ( in this case is reading the register ) . So the code from the run_phase needs to be moved to a body function.
class my_seq extends uvm_sequence;
// register to uvm db
reg_map map;
my_regs regs;
uvm_status_e status;
function new(string name="my_seq");
super.new(name);
endfunction
task body ();
map.CORE.reg_a.read(status, regs.a, UVM_BACKDOOR);
endtask
endclass
Once the sequence is invoked it will read the value from the RTL register and update the "a" field in regs in the class my_seq.
regs = seq.regs; //
regs ( in the test ) will provide a permanent link to the regs field within the sequence. So any time the sequence reads the register and updates the regs field the variable regs in test_reg will see the change , But it means the register has to be read from the RTL. The test_reg would need to implement a loop to read the register periodically ( by calling the sequence my_seq) . This is because the variable regs or the register field map.CORE.reg_a is not a direct link to the register within the RTL.
You will need to spend simulation cycles reading the RTL register , as the uvm_register is only a mirror/copy which updates only when a read is issued.
The question is how are the register be accessed by the firmware ? If the register is accessed via a poling mechanism its better to mimic the same in the test case.
task run_phase(uvm_phase phase);
task_done = 0;
while ( !task_done )
begin
// wait for some delay as backdoor access takes 0 simulation time
reg_seq.start(null); // regs is updates
// read reg values from seq - done
if(regs.a>1) // check for bit to be set
begin
task_done = 1;
//do some thing
end
// else continue to poll register
end
end task
Alternatively we could wait for the RTL signal to change and then issue the read ( this method is not desirable as we are accessing RTL signals from the test bench. )
task run_phase(uvm_phase phase);
wait ( RTL.module.reg.CORE.reg_a == 1 ) ;
reg_seq.start(null); // regs file is updates
// read reg values from seq - done
if(regs.a>1) // check for bit to be set
//do some thing
endtask
Upvotes: 2