// // ------------------------------------------------------------- // Copyright 2004-2009 Synopsys, Inc. // Copyright 2010-2011 Mentor Graphics Corporation // Copyright 2010 Cadence Design Systems, Inc. // All Rights Reserved Worldwide // // Licensed under the Apache License, Version 2.0 (the // "License"); you may not use this file except in // compliance with the License. You may obtain a copy of // the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in // writing, software distributed under the License is // distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR // CONDITIONS OF ANY KIND, either express or implied. See // the License for the specific language governing // permissions and limitations under the License. // ------------------------------------------------------------- // typedef class uvm_reg_cbs; //------------------------------------------------------------------------------ // Class: uvm_reg_backdoor // // Base class for user-defined back-door register and memory access. // // This class can be extended by users to provide user-specific back-door access // to registers and memories that are not implemented in pure SystemVerilog // or that are not accessible using the default DPI backdoor mechanism. //------------------------------------------------------------------------------ class uvm_reg_backdoor extends uvm_object; // Function: new // // Create an instance of this class // // Create an instance of the user-defined backdoor class // for the specified register or memory // function new(string name = ""); super.new(name); endfunction: new // Task: do_pre_read // // Execute the pre-read callbacks // // This method ~must~ be called as the first statement in // a user extension of the method. // protected task do_pre_read(uvm_reg_item rw); pre_read(rw); `uvm_do_obj_callbacks(uvm_reg_backdoor, uvm_reg_cbs, this, pre_read(rw)) endtask // Task: do_post_read // // Execute the post-read callbacks // // This method ~must~ be called as the last statement in // a user extension of the method. // protected task do_post_read(uvm_reg_item rw); uvm_callback_iter#(uvm_reg_backdoor, uvm_reg_cbs) iter = new(this); for(uvm_reg_cbs cb = iter.last(); cb != null; cb=iter.prev()) cb.decode(rw.value); `uvm_do_obj_callbacks(uvm_reg_backdoor,uvm_reg_cbs,this,post_read(rw)) post_read(rw); endtask // Task: do_pre_write // // Execute the pre-write callbacks // // This method ~must~ be called as the first statement in // a user extension of the method. // protected task do_pre_write(uvm_reg_item rw); uvm_callback_iter#(uvm_reg_backdoor, uvm_reg_cbs) iter = new(this); pre_write(rw); `uvm_do_obj_callbacks(uvm_reg_backdoor,uvm_reg_cbs,this,pre_write(rw)) for(uvm_reg_cbs cb = iter.first(); cb != null; cb = iter.next()) cb.encode(rw.value); endtask // Task: do_post_write // // Execute the post-write callbacks // // This method ~must~ be called as the last statement in // a user extension of the method. // protected task do_post_write(uvm_reg_item rw); `uvm_do_obj_callbacks(uvm_reg_backdoor,uvm_reg_cbs,this,post_write(rw)) post_write(rw); endtask // Task: write // // User-defined backdoor write operation. // // Call . // Deposit the specified value in the specified register HDL implementation. // Call . // Returns an indication of the success of the operation. // extern virtual task write(uvm_reg_item rw); // Task: read // // User-defined backdoor read operation. // // Overload this method only if the backdoor requires the use of task. // // Call . // Peek the current value of the specified HDL implementation. // Call . // Returns the current value and an indication of the success of // the operation. // // By default, calls . // extern virtual task read(uvm_reg_item rw); // Function: read_func // // User-defined backdoor read operation. // // Peek the current value in the HDL implementation. // Returns the current value and an indication of the success of // the operation. // extern virtual function void read_func(uvm_reg_item rw); // Function: is_auto_updated // // Indicates if wait_for_change() method is implemented // // Implement to return TRUE if and only if // is implemented to watch for changes // in the HDL implementation of the specified field // extern virtual function bit is_auto_updated(uvm_reg_field field); // Task: wait_for_change // // Wait for a change in the value of the register or memory // element in the DUT. // // When this method returns, the mirror value for the register // corresponding to this instance of the backdoor class will be updated // via a backdoor read operation. // extern virtual local task wait_for_change(uvm_object element); /*local*/ extern function void start_update_thread(uvm_object element); /*local*/ extern function void kill_update_thread(uvm_object element); /*local*/ extern function bit has_update_threads(); // Task: pre_read // // Called before user-defined backdoor register read. // // The registered callback methods are invoked after the invocation // of this method. // virtual task pre_read(uvm_reg_item rw); endtask // Task: post_read // // Called after user-defined backdoor register read. // // The registered callback methods are invoked before the invocation // of this method. // virtual task post_read(uvm_reg_item rw); endtask // Task: pre_write // // Called before user-defined backdoor register write. // // The registered callback methods are invoked after the invocation // of this method. // // The written value, if modified, modifies the actual value that // will be written. // virtual task pre_write(uvm_reg_item rw); endtask // Task: post_write // // Called after user-defined backdoor register write. // // The registered callback methods are invoked before the invocation // of this method. // virtual task post_write(uvm_reg_item rw); endtask string fname; int lineno; `ifdef UVM_USE_PROCESS_CONTAINER local process_container_c m_update_thread[uvm_object]; `else local process m_update_thread[uvm_object]; `endif `uvm_object_utils(uvm_reg_backdoor) `uvm_register_cb(uvm_reg_backdoor, uvm_reg_cbs) endclass: uvm_reg_backdoor //------------------------------------------------------------------------------ // IMPLEMENTATION //------------------------------------------------------------------------------ // is_auto_updated function bit uvm_reg_backdoor::is_auto_updated(uvm_reg_field field); return 0; endfunction // wait_for_change task uvm_reg_backdoor::wait_for_change(uvm_object element); `uvm_fatal("RegModel", "uvm_reg_backdoor::wait_for_change() method has not been overloaded"); endtask // start_update_thread function void uvm_reg_backdoor::start_update_thread(uvm_object element); uvm_reg rg; if (this.m_update_thread.exists(element)) begin this.kill_update_thread(element); end if (!$cast(rg,element)) return; // only regs supported at this time fork begin uvm_reg_field fields[$]; `ifdef UVM_USE_PROCESS_CONTAINER this.m_update_thread[element] = new(process::self()); `else this.m_update_thread[element] = process::self(); `endif rg.get_fields(fields); forever begin uvm_status_e status; uvm_reg_data_t val; uvm_reg_item r_item = new("bd_r_item"); r_item.element = rg; r_item.element_kind = UVM_REG; this.read(r_item); val = r_item.value[0]; if (r_item.status != UVM_IS_OK) begin `uvm_error("RegModel", $sformatf("Backdoor read of register '%s' failed.", rg.get_name())); end foreach (fields[i]) begin if (this.is_auto_updated(fields[i])) begin r_item.value[0] = (val >> fields[i].get_lsb_pos()) & ((1 << fields[i].get_n_bits())-1); fields[i].do_predict(r_item); end end this.wait_for_change(element); end end join_none endfunction // kill_update_thread function void uvm_reg_backdoor::kill_update_thread(uvm_object element); if (this.m_update_thread.exists(element)) begin `ifdef UVM_USE_PROCESS_CONTAINER this.m_update_thread[element].p.kill(); `else this.m_update_thread[element].kill(); `endif this.m_update_thread.delete(element); end endfunction // has_update_threads function bit uvm_reg_backdoor::has_update_threads(); return this.m_update_thread.num() > 0; endfunction // write task uvm_reg_backdoor::write(uvm_reg_item rw); `uvm_fatal("RegModel", "uvm_reg_backdoor::write() method has not been overloaded"); endtask // read task uvm_reg_backdoor::read(uvm_reg_item rw); do_pre_read(rw); read_func(rw); do_post_read(rw); endtask // read_func function void uvm_reg_backdoor::read_func(uvm_reg_item rw); `uvm_fatal("RegModel", "uvm_reg_backdoor::read_func() method has not been overloaded"); rw.status = UVM_NOT_OK; endfunction