Jump to content

Register write() clobbers simultaneous access in multi-threaded testbench


Recommended Posts

Hi,

I am facing a threading issue when a single register instance is accessed multiple times simultaneously.  Given two separate threads scheduled at the same time and each calling the uvm_reg::write() task, I see the first one to execute the call does correctly take the semaphore on uvm_reg::write().XatomicX(1) task call, and the second thread correctly blocks when it attempts uvm_reg::write().XatomicX(1) task.  The first thread, in the uvm_reg::do_write() task safely immediately returns on its uvm-reg::do_write().XatomicX(1) task call and correctly executes the bus transaction.  The problem arises when the uvm_reg::do_write() task returns the semaphore in its XatomicX(0) call.  This:

1 - immediately wakes Thread2 which takes the semaphore and assigns its process to the local m_process variable, then continues into the uvm_reg::do_write() and correctly executes its bus transaction;

2 - once Thread2 blocks while its bus transaction takes place, Thread1 returns from uvm_reg::do_write() and hits its uvm_reg::write().XatomicX(0) task call. 

At this point in time, Thread2 correctly owns the semaphore and has its process reference stored in uvm_reg::m_process.  However, when Thread1 calls XatomicX(0) just before returning from uvm_reg::write(), there is no check on why the semaphore is owned.

From UVM-1.2 uvm_reg.svh:

task uvm_reg::XatomicX(bit on);
   process m_reg_process;
   m_reg_process=process::self();
   
   if (on) begin
      // we don't care about this branch right now
   end
   else begin
      // Maybe a key was put back in by a spurious call to reset()
      void'(m_atomic.try_get(1));
      m_atomic.put(1);
      m_process = null;
   end
endtask: XatomicX

Because Thread2 correctly owns the semaphore AND there no checking done on ownership when bit on == 0, Thread1 is able to incorrectly put back the semaphore and invalidate the m_process reference.  (The spurious reset comment does not apply).

Because of my testbench setup, my test has to immediate write this same register with another value.  So, Thread1 preforms a second write() call on the same register.

This causes warnings to be emitted from the field because the register is currently busy (in the bus transaction):

function void uvm_reg_field::set(...);
   ...
   if (m_parent.is_busy()) begin
      `uvm_warning("UVM/FLD/SET/BSY",
                   $sformatf("Setting the value of field \"%s\" while containing register \"%s\" is being accessed may result in loss of desired field value. A race condition between threads concurrently accessing the register model is the likely cause of the problem.",
                             get_name(), m_parent.get_full_name()))
   end
   ...
endfunction

and it clobbers the register value in the RAL model.  Because Thread2 is currently busy on bus transaction, when it returns it may perform the do_predict call while Thread1 is busy on its bus transaction for the same register.  I'm not sure what will happen here.

I am thinking that the XatomicX should have a check on the process when bit on == 0, similar to when the bit on == 1, to ensure the clearer of the semaphore is the same owner who claimed it.  However, I am not sure how this would affect other testbenches.  For example, is it possible to split the write() task into separate threads when the driver returns responses separately (i.e., the uvm_reg_adapater.provides_responses == 1).  Basically, is it possible to start a register transaction in one thread (taking the semaphore) and end it in another transaction?  

Also, I see that there is a similar, though different solution than I'm suggesting, already posted (with an approved but not fixed mantis bug):

I also see that in my release of UVM-IEEE, the uvm_reg class has the exact same XatomicX locking mechanism implemented.

The only current solution I see that handles this outside of UVM and enables multi-threading access of the same register is with, yet another, semaphore that makes the internal uvm_reg semaphore all but moot.  However, this is not desirable since I need to enforce a guideline on my team rather than have it built-in.

Am I missing something?  Better approaches?

 

Thanks for your feedback!

Jeremy Ridgeway

Link to comment
Share on other sites

  • 2 weeks later...
  • 2 years later...

Dear Mark,

We are facing the similar issue and warning in multi-threaded environment with UVM reg model and multi threads making register write calls on different addresses and getting the uvm warning from uvm_reg_field as shown below. we are using uvm-1.1d_r2 library. Please let us know if eventually there was any update or resolution to this article and guidance how to address this. Currently we have to implement semaphore at our testbench level to address this but this is not a scalable solution.

 

function void uvm_reg_field::set(...);
   ...
   if (m_parent.is_busy()) begin
      `uvm_warning("UVM/FLD/SET/BSY",
                   $sformatf("Setting the value of field \"%s\" while containing register \"%s\" is being accessed may result in loss of desired field value. A race condition between threads concurrently accessing the register model is the likely cause of the problem.",
                             get_name(), m_parent.get_full_name()))
   end

 

thanks

Vishal Karna

 

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...