jeremyr Posted August 27, 2021 Report Share Posted August 27, 2021 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 Quote Link to comment Share on other sites More sharing options...
Mark Strickland Posted September 9, 2021 Report Share Posted September 9, 2021 Hi Jeremy, Thanks for submitting this issue. I don't think you are missing anything. The UVM working group is looking into it. Mark Strickland (Accellera UVM Working Group Chair) Quote Link to comment Share on other sites More sharing options...
Vishal K Posted February 3 Report Share Posted February 3 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 Quote Link to comment Share on other sites More sharing options...
Recommended Posts
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.