maskarih
maskarih

Reputation: 867

Reference to UVM Sequence

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

Answers (1)

Rahul Menon
Rahul Menon

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

Related Questions