//
// -------------------------------------------------------------
// 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 [docs]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 [docs]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 [docs]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 <read()> 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 <read()> 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 <write()> 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 <write()> 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 <do_pre_write()>.
// Deposit the specified value in the specified register HDL implementation.
// Call <do_post_write()>.
// Returns an indication of the success of the operation.
//
extern virtual task [docs]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 <do_pre_read()>.
// Peek the current value of the specified HDL implementation.
// Call <do_post_read()>.
// Returns the current value and an indication of the success of
// the operation.
//
// By default, calls <read_func()>.
//
extern virtual task [docs]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 [docs]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
// <wait_for_change()> is implemented to watch for changes
// in the HDL implementation of the specified field
//
extern virtual function bit [docs]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 [docs]start_update_thread(uvm_object element);
/*local*/ extern function void [docs]kill_update_thread(uvm_object element);
/*local*/ extern function bit [docs]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 [docs]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 [docs]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 [docs]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 [docs]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