//
// -------------------------------------------------------------
// Copyright 2004-2009 Synopsys, Inc.
// Copyright 2010 Mentor Graphics Corporation
// 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.
// -------------------------------------------------------------
//
//------------------------------------------------------------------------------
// Title: Virtual Register Field Classes
//
// This section defines the virtual field and callback classes.
//
// A virtual field is set of contiguous bits in one or more memory locations.
// The semantics and layout of virtual fields comes from
// an agreement between the software and the hardware,
// not any physical structures in the DUT.
//
//------------------------------------------------------------------------------
typedef class [docs]uvm_vreg_field_cbs;
//------------------------------------------------------------------------------
// Class: uvm_vreg_field
//
// Virtual field abstraction class
//
// A virtual field represents a set of adjacent bits that are
// logically implemented in consecutive memory locations.
//
//------------------------------------------------------------------------------
class [docs]uvm_vreg_field extends uvm_object;
`uvm_object_utils(uvm_vreg_field)
`uvm_register_cb(uvm_vreg_field, uvm_vreg_field_cbs)
local uvm_vreg parent;
local int unsigned lsb;
local int unsigned size;
local string fname;
local int lineno;
local bit read_in_progress;
local bit write_in_progress;
//
// Group: initialization
//
//
// Function: new
// Create a new virtual field instance
//
// This method should not be used directly.
// The uvm_vreg_field::type_id::create() method should be used instead.
//
extern function [docs]new(string name = "uvm_vreg_field");
//
// Function: configure
// Instance-specific configuration
//
// Specify the ~parent~ virtual register of this virtual field, its
// ~size~ in bits, and the position of its least-significant bit
// within the virtual register relative to the least-significant bit
// of the virtual register.
//
extern function void [docs]configure(uvm_vreg parent,
int unsigned size,
int unsigned lsb_pos);
//
// Group: Introspection
//
//
// Function: get_name
// Get the simple name
//
// Return the simple object name of this virtual field
//
//
// Function: get_full_name
// Get the hierarchical name
//
// Return the hierarchal name of this virtual field
// The base of the hierarchical name is the root block.
//
extern virtual function string [docs]get_full_name();
//
// FUNCTION: get_parent
// Get the parent virtual register
//
extern virtual function uvm_vreg [docs]get_parent();
extern virtual function uvm_vreg [docs]get_register();
//
// FUNCTION: get_lsb_pos_in_register
// Return the position of the virtual field
///
// Returns the index of the least significant bit of the virtual field
// in the virtual register that instantiates it.
// An offset of 0 indicates a field that is aligned with the
// least-significant bit of the register.
//
extern virtual function int unsigned [docs]get_lsb_pos_in_register();
//
// FUNCTION: get_n_bits
// Returns the width, in bits, of the virtual field.
//
extern virtual function int unsigned [docs]get_n_bits();
//
// FUNCTION: get_access
// Returns the access policy of the virtual field register
// when written and read via an address map.
//
// If the memory implementing the virtual field
// is mapped in more than one address map,
// an address ~map~ must be specified.
// If access restrictions are present when accessing a memory
// through the specified address map, the access mode returned
// takes the access restrictions into account.
// For example, a read-write memory accessed
// through an address map with read-only restrictions would return "RO".
//
extern virtual function string [docs]get_access(uvm_reg_map map = null);
//
// Group: HDL Access
//
//
// TASK: write
// Write the specified value in a virtual field
//
// Write ~value~ in the DUT memory location(s) that implements
// the virtual field that corresponds to this
// abstraction class instance using the specified access
// ~path~.
//
// If the memory implementing the virtual register array
// containing this virtual field
// is mapped in more than one address map,
// an address ~map~ must be
// specified if a physical access is used (front-door access).
//
// The operation is eventually mapped into
// memory read-modify-write operations at the location
// where the virtual register
// specified by ~idx~ in the virtual register array is implemented.
// If a backdoor is available for the memory implementing the
// virtual field, it will be used for the memory-read operation.
//
extern virtual task [docs]write(input longint unsigned idx,
output uvm_status_e status,
input uvm_reg_data_t value,
input uvm_path_e path = UVM_DEFAULT_PATH,
input uvm_reg_map map = null,
input uvm_sequence_base parent = null,
input uvm_object extension = null,
input string fname = "",
input int lineno = 0);
//
// TASK: read
// Read the current value from a virtual field
//
// Read from the DUT memory location(s) that implements
// the virtual field that corresponds to this
// abstraction class instance using the specified access
// ~path~, and return the readback ~value~.
//
// If the memory implementing the virtual register array
// containing this virtual field
// is mapped in more than one address map,
// an address ~map~ must be
// specified if a physical access is used (front-door access).
//
// The operation is eventually mapped into
// memory read operations at the location(s)
// where the virtual register
// specified by ~idx~ in the virtual register array is implemented.
//
extern virtual task [docs]read(input longint unsigned idx,
output uvm_status_e status,
output uvm_reg_data_t value,
input uvm_path_e path = UVM_DEFAULT_PATH,
input uvm_reg_map map = null,
input uvm_sequence_base parent = null,
input uvm_object extension = null,
input string fname = "",
input int lineno = 0);
//
// TASK: poke
// Deposit the specified value in a virtual field
//
// Deposit ~value~ in the DUT memory location(s) that implements
// the virtual field that corresponds to this
// abstraction class instance using the specified access
// ~path~.
//
// The operation is eventually mapped into
// memory peek-modify-poke operations at the location
// where the virtual register
// specified by ~idx~ in the virtual register array is implemented.
//
extern virtual task [docs]poke(input longint unsigned idx,
output uvm_status_e status,
input uvm_reg_data_t value,
input uvm_sequence_base parent = null,
input uvm_object extension = null,
input string fname = "",
input int lineno = 0);
//
// TASK: peek
// Sample the current value from a virtual field
//
// Sample from the DUT memory location(s) that implements
// the virtual field that corresponds to this
// abstraction class instance using the specified access
// ~path~, and return the readback ~value~.
//
// If the memory implementing the virtual register array
// containing this virtual field
// is mapped in more than one address map,
// an address ~map~ must be
// specified if a physical access is used (front-door access).
//
// The operation is eventually mapped into
// memory peek operations at the location(s)
// where the virtual register
// specified by ~idx~ in the virtual register array is implemented.
//
extern virtual task [docs]peek(input longint unsigned idx,
output uvm_status_e status,
output uvm_reg_data_t value,
input uvm_sequence_base parent = null,
input uvm_object extension = null,
input string fname = "",
input int lineno = 0);
//
// Group: Callbacks
//
//
// TASK: pre_write
// Called before virtual field write.
//
// If the specified data value, access ~path~ or address ~map~ are modified,
// the updated data value, access path or address map will be used
// to perform the virtual register operation.
//
// The virtual field callback methods are invoked before the callback methods
// on the containing virtual register.
// The registered callback methods are invoked after the invocation
// of this method.
// The pre-write virtual register and field callbacks are executed
// before the corresponding pre-write memory callbacks
//
virtual task [docs]pre_write(longint unsigned idx,
ref uvm_reg_data_t wdat,
ref uvm_path_e path,
ref uvm_reg_map map);
endtask: pre_write
//
// TASK: post_write
// Called after virtual field write
//
// If the specified ~status~ is modified,
// the updated status will be
// returned by the virtual register operation.
//
// The virtual field callback methods are invoked after the callback methods
// on the containing virtual register.
// The registered callback methods are invoked before the invocation
// of this method.
// The post-write virtual register and field callbacks are executed
// after the corresponding post-write memory callbacks
//
virtual task [docs]post_write(longint unsigned idx,
uvm_reg_data_t wdat,
uvm_path_e path,
uvm_reg_map map,
ref uvm_status_e status);
endtask: post_write
//
// TASK: pre_read
// Called before virtual field read.
//
// If the specified access ~path~ or address ~map~ are modified,
// the updated access path or address map will be used to perform
// the virtual register operation.
//
// The virtual field callback methods are invoked after the callback methods
// on the containing virtual register.
// The registered callback methods are invoked after the invocation
// of this method.
// The pre-read virtual register and field callbacks are executed
// before the corresponding pre-read memory callbacks
//
virtual task [docs]pre_read(longint unsigned idx,
ref uvm_path_e path,
ref uvm_reg_map map);
endtask: pre_read
//
// TASK: post_read
// Called after virtual field read.
//
// If the specified readback data ~rdat~ or ~status~ is modified,
// the updated readback data or status will be
// returned by the virtual register operation.
//
// The virtual field callback methods are invoked after the callback methods
// on the containing virtual register.
// The registered callback methods are invoked before the invocation
// of this method.
// The post-read virtual register and field callbacks are executed
// after the corresponding post-read memory callbacks
//
virtual task [docs]post_read(longint unsigned idx,
ref uvm_reg_data_t rdat,
uvm_path_e path,
uvm_reg_map map,
ref uvm_status_e status);
endtask: post_read
extern virtual function void [docs]do_print (uvm_printer printer);
extern virtual function string [docs]convert2string;
extern virtual function uvm_object [docs]clone();
extern virtual function void [docs]do_copy (uvm_object rhs);
extern virtual function bit [docs]do_compare (uvm_object rhs,
uvm_comparer comparer);
extern virtual function void [docs]do_pack (uvm_packer packer);
extern virtual function void [docs]do_unpack (uvm_packer packer);
endclass: uvm_vreg_field
//------------------------------------------------------------------------------
// Class: uvm_vreg_field_cbs
//
// Pre/post read/write callback facade class
//
//------------------------------------------------------------------------------
class [docs]uvm_vreg_field_cbs extends uvm_callback;
string fname;
int lineno;
function [docs]new(string name = "uvm_vreg_field_cbs");
super.new(name);
endfunction
//
// Task: pre_write
// Callback called before a write operation.
//
// The registered callback methods are invoked before the invocation
// of the virtual register pre-write callbacks and
// after the invocation of the <uvm_vreg_field::pre_write()> method.
//
// The written value ~wdat~, access ~path~ and address ~map~,
// if modified, modifies the actual value, access path or address map
// used in the register operation.
//
virtual task [docs]pre_write(uvm_vreg_field field,
longint unsigned idx,
ref uvm_reg_data_t wdat,
ref uvm_path_e path,
ref uvm_reg_map map);
endtask: pre_write
//
// TASK: post_write
// Called after a write operation
//
// The registered callback methods are invoked after the invocation
// of the virtual register post-write callbacks and
// before the invocation of the <uvm_vreg_field::post_write()> method.
//
// The ~status~ of the operation,
// if modified, modifies the actual returned status.
//
virtual task [docs]post_write(uvm_vreg_field field,
longint unsigned idx,
uvm_reg_data_t wdat,
uvm_path_e path,
uvm_reg_map map,
ref uvm_status_e status);
endtask: post_write
//
// TASK: pre_read
// Called before a virtual field read.
//
// The registered callback methods are invoked after the invocation
// of the virtual register pre-read callbacks and
// after the invocation of the <uvm_vreg_field::pre_read()> method.
//
// The access ~path~ and address ~map~,
// if modified, modifies the actual access path or address map
// used in the register operation.
//
virtual task [docs]pre_read(uvm_vreg_field field,
longint unsigned idx,
ref uvm_path_e path,
ref uvm_reg_map map);
endtask: pre_read
//
// TASK: post_read
// Called after a virtual field read.
//
// The registered callback methods are invoked after the invocation
// of the virtual register post-read callbacks and
// before the invocation of the <uvm_vreg_field::post_read()> method.
//
// The readback value ~rdat~ and the ~status~ of the operation,
// if modified, modifies the actual returned readback value and status.
//
virtual task [docs]post_read(uvm_vreg_field field,
longint unsigned idx,
ref uvm_reg_data_t rdat,
uvm_path_e path,
uvm_reg_map map,
ref uvm_status_e status);
endtask: post_read
endclass: uvm_vreg_field_cbs
//
// Type: uvm_vreg_field_cb
// Convenience callback type declaration
//
// Use this declaration to register virtual field callbacks rather than
// the more verbose parameterized class
//
typedef uvm_callbacks#(uvm_vreg_field, uvm_vreg_field_cbs) [docs]uvm_vreg_field_cb;
//
// Type: uvm_vreg_field_cb_iter
// Convenience callback iterator type declaration
//
// Use this declaration to iterate over registered virtual field callbacks
// rather than the more verbose parameterized class
//
typedef uvm_callback_iter#(uvm_vreg_field, uvm_vreg_field_cbs) [docs]uvm_vreg_field_cb_iter;
function uvm_vreg_field::new(string name="uvm_vreg_field");
super.new(name);
endfunction: new
function void uvm_vreg_field::configure(uvm_vreg parent,
int unsigned size,
int unsigned lsb_pos);
this.parent = parent;
if (size == 0) begin
`uvm_error("RegModel", $sformatf("Virtual field \"%s\" cannot have 0 bits", this.get_full_name()));
size = 1;
end
if (size > `UVM_REG_DATA_WIDTH) begin
`uvm_error("RegModel", $sformatf("Virtual field \"%s\" cannot have more than %0d bits",
this.get_full_name(),
`UVM_REG_DATA_WIDTH));
size = `UVM_REG_DATA_WIDTH;
end
this.size = size;
this.lsb = lsb_pos;
this.parent.add_field(this);
endfunction: configure
function string uvm_vreg_field::get_full_name();
get_full_name = {this.parent.get_full_name(), ".", this.get_name()};
endfunction: get_full_name
function uvm_vreg uvm_vreg_field::get_register();
get_register = this.parent;
endfunction: get_register
function uvm_vreg uvm_vreg_field::get_parent();
get_parent = this.parent;
endfunction: get_parent
function int unsigned uvm_vreg_field::get_lsb_pos_in_register();
get_lsb_pos_in_register = this.lsb;
endfunction: get_lsb_pos_in_register
function int unsigned uvm_vreg_field::get_n_bits();
get_n_bits = this.size;
endfunction: get_n_bits
function string uvm_vreg_field::get_access(uvm_reg_map map = null);
if (this.parent.get_memory() == null) begin
`uvm_error("RegModel", $sformatf("Cannot call uvm_vreg_field::get_rights() on unimplemented virtual field \"%s\"",
this.get_full_name()));
return "RW";
end
return this.parent.get_access(map);
endfunction: get_access
task uvm_vreg_field::write(input longint unsigned idx,
output uvm_status_e status,
input uvm_reg_data_t value,
input uvm_path_e path = UVM_DEFAULT_PATH,
input uvm_reg_map map = null,
input uvm_sequence_base parent = null,
input uvm_object extension = null,
input string fname = "",
input int lineno = 0);
uvm_reg_data_t tmp;
uvm_reg_data_t segval;
uvm_reg_addr_t segoff;
uvm_status_e st;
int flsb, fmsb, rmwbits;
int segsiz, segn;
uvm_mem mem;
uvm_path_e rm_path;
uvm_vreg_field_cb_iter cbs = new(this);
this.fname = fname;
this.lineno = lineno;
write_in_progress = 1'b1;
mem = this.parent.get_memory();
if (mem == null) begin
`uvm_error("RegModel", $sformatf("Cannot call uvm_vreg_field::write() on unimplemented virtual register \"%s\"",
this.get_full_name()));
status = UVM_NOT_OK;
return;
end
if (path == UVM_DEFAULT_PATH) begin
uvm_reg_block blk = this.parent.get_block();
path = blk.get_default_path();
end
status = UVM_IS_OK;
this.parent.XatomicX(1);
if (value >> this.size) begin
`uvm_warning("RegModel", $sformatf("Writing value 'h%h that is greater than field \"%s\" size (%0d bits)", value, this.get_full_name(), this.get_n_bits()));
value &= value & ((1<<this.size)-1);
end
tmp = 0;
this.pre_write(idx, value, path, map);
for (uvm_vreg_field_cbs cb = cbs.first(); cb != null;
cb = cbs.next()) begin
cb.fname = this.fname;
cb.lineno = this.lineno;
cb.pre_write(this, idx, value, path, map);
end
segsiz = mem.get_n_bytes() * 8;
flsb = this.get_lsb_pos_in_register();
segoff = this.parent.get_offset_in_memory(idx) + (flsb / segsiz);
// Favor backdoor read to frontdoor read for the RMW operation
rm_path = UVM_DEFAULT_PATH;
if (mem.get_backdoor() != null) rm_path = UVM_BACKDOOR;
// Any bits on the LSB side we need to RMW?
rmwbits = flsb % segsiz;
// Total number of memory segment in this field
segn = (rmwbits + this.get_n_bits() - 1) / segsiz + 1;
if (rmwbits > 0) begin
uvm_reg_addr_t segn;
mem.read(st, segoff, tmp, rm_path, map, parent, , extension, fname, lineno);
if (st != UVM_IS_OK && st != UVM_HAS_X) begin
`uvm_error("RegModel",
$sformatf("Unable to read LSB bits in %s[%0d] to for RMW cycle on virtual field %s.",
mem.get_full_name(), segoff, this.get_full_name()));
status = UVM_NOT_OK;
this.parent.XatomicX(0);
return;
end
value = (value << rmwbits) | (tmp & ((1<<rmwbits)-1));
end
// Any bits on the MSB side we need to RMW?
fmsb = rmwbits + this.get_n_bits() - 1;
rmwbits = (fmsb+1) % segsiz;
if (rmwbits > 0) begin
if (segn > 0) begin
mem.read(st, segoff + segn - 1, tmp, rm_path, map, parent,, extension, fname, lineno);
if (st != UVM_IS_OK && st != UVM_HAS_X) begin
`uvm_error("RegModel",
$sformatf("Unable to read MSB bits in %s[%0d] to for RMW cycle on virtual field %s.",
mem.get_full_name(), segoff+segn-1,
this.get_full_name()));
status = UVM_NOT_OK;
this.parent.XatomicX(0);
return;
end
end
value |= (tmp & ~((1<<rmwbits)-1)) << ((segn-1)*segsiz);
end
// Now write each of the segments
tmp = value;
repeat (segn) begin
mem.write(st, segoff, tmp, path, map, parent,, extension, fname, lineno);
if (st != UVM_IS_OK && st != UVM_HAS_X) status = UVM_NOT_OK;
segoff++;
tmp = tmp >> segsiz;
end
this.post_write(idx, value, path, map, status);
for (uvm_vreg_field_cbs cb = cbs.first(); cb != null;
cb = cbs.next()) begin
cb.fname = this.fname;
cb.lineno = this.lineno;
cb.post_write(this, idx, value, path, map, status);
end
this.parent.XatomicX(0);
`uvm_info("RegModel", $sformatf("Wrote virtual field \"%s\"[%0d] via %s with: 'h%h",
this.get_full_name(), idx,
(path == UVM_FRONTDOOR) ? "frontdoor" : "backdoor",
value),UVM_MEDIUM);
write_in_progress = 1'b0;
this.fname = "";
this.lineno = 0;
endtask: write
task uvm_vreg_field::read(input longint unsigned idx,
output uvm_status_e status,
output uvm_reg_data_t value,
input uvm_path_e path = UVM_DEFAULT_PATH,
input uvm_reg_map map = null,
input uvm_sequence_base parent = null,
input uvm_object extension = null,
input string fname = "",
input int lineno = 0);
uvm_reg_data_t tmp;
uvm_reg_data_t segval;
uvm_reg_addr_t segoff;
uvm_status_e st;
int flsb, lsb;
int segsiz, segn;
uvm_mem mem;
uvm_vreg_field_cb_iter cbs = new(this);
this.fname = fname;
this.lineno = lineno;
read_in_progress = 1'b1;
mem = this.parent.get_memory();
if (mem == null) begin
`uvm_error("RegModel", $sformatf("Cannot call uvm_vreg_field::read() on unimplemented virtual register \"%s\"",
this.get_full_name()));
status = UVM_NOT_OK;
return;
end
if (path == UVM_DEFAULT_PATH) begin
uvm_reg_block blk = this.parent.get_block();
path = blk.get_default_path();
end
status = UVM_IS_OK;
this.parent.XatomicX(1);
value = 0;
this.pre_read(idx, path, map);
for (uvm_vreg_field_cbs cb = cbs.first(); cb != null;
cb = cbs.next()) begin
cb.fname = this.fname;
cb.lineno = this.lineno;
cb.pre_read(this, idx, path, map);
end
segsiz = mem.get_n_bytes() * 8;
flsb = this.get_lsb_pos_in_register();
segoff = this.parent.get_offset_in_memory(idx) + (flsb / segsiz);
lsb = flsb % segsiz;
// Total number of memory segment in this field
segn = (lsb + this.get_n_bits() - 1) / segsiz + 1;
// Read each of the segments, MSB first
segoff += segn - 1;
repeat (segn) begin
value = value << segsiz;
mem.read(st, segoff, tmp, path, map, parent, , extension, fname, lineno);
if (st != UVM_IS_OK && st != UVM_HAS_X) status = UVM_NOT_OK;
segoff--;
value |= tmp;
end
// Any bits on the LSB side we need to get rid of?
value = value >> lsb;
// Any bits on the MSB side we need to get rid of?
value &= (1<<this.get_n_bits()) - 1;
this.post_read(idx, value, path, map, status);
for (uvm_vreg_field_cbs cb = cbs.first(); cb != null;
cb = cbs.next()) begin
cb.fname = this.fname;
cb.lineno = this.lineno;
cb.post_read(this, idx, value, path, map, status);
end
this.parent.XatomicX(0);
`uvm_info("RegModel", $sformatf("Read virtual field \"%s\"[%0d] via %s: 'h%h",
this.get_full_name(), idx,
(path == UVM_FRONTDOOR) ? "frontdoor" : "backdoor",
value),UVM_MEDIUM);
read_in_progress = 1'b0;
this.fname = "";
this.lineno = 0;
endtask: read
task uvm_vreg_field::poke(input longint unsigned idx,
output uvm_status_e status,
input uvm_reg_data_t value,
input uvm_sequence_base parent = null,
input uvm_object extension = null,
input string fname = "",
input int lineno = 0);
uvm_reg_data_t tmp;
uvm_reg_data_t segval;
uvm_reg_addr_t segoff;
uvm_status_e st;
int flsb, fmsb, rmwbits;
int segsiz, segn;
uvm_mem mem;
uvm_path_e rm_path;
this.fname = fname;
this.lineno = lineno;
mem = this.parent.get_memory();
if (mem == null) begin
`uvm_error("RegModel", $sformatf("Cannot call uvm_vreg_field::poke() on unimplemented virtual register \"%s\"",
this.get_full_name()));
status = UVM_NOT_OK;
return;
end
status = UVM_IS_OK;
this.parent.XatomicX(1);
if (value >> this.size) begin
`uvm_warning("RegModel", $sformatf("Writing value 'h%h that is greater than field \"%s\" size (%0d bits)", value, this.get_full_name(), this.get_n_bits()));
value &= value & ((1<<this.size)-1);
end
tmp = 0;
segsiz = mem.get_n_bytes() * 8;
flsb = this.get_lsb_pos_in_register();
segoff = this.parent.get_offset_in_memory(idx) + (flsb / segsiz);
// Any bits on the LSB side we need to RMW?
rmwbits = flsb % segsiz;
// Total number of memory segment in this field
segn = (rmwbits + this.get_n_bits() - 1) / segsiz + 1;
if (rmwbits > 0) begin
uvm_reg_addr_t segn;
mem.peek(st, segoff, tmp, "", parent, extension, fname, lineno);
if (st != UVM_IS_OK && st != UVM_HAS_X) begin
`uvm_error("RegModel",
$sformatf("Unable to read LSB bits in %s[%0d] to for RMW cycle on virtual field %s.",
mem.get_full_name(), segoff, this.get_full_name()));
status = UVM_NOT_OK;
this.parent.XatomicX(0);
return;
end
value = (value << rmwbits) | (tmp & ((1<<rmwbits)-1));
end
// Any bits on the MSB side we need to RMW?
fmsb = rmwbits + this.get_n_bits() - 1;
rmwbits = (fmsb+1) % segsiz;
if (rmwbits > 0) begin
if (segn > 0) begin
mem.peek(st, segoff + segn - 1, tmp, "", parent, extension, fname, lineno);
if (st != UVM_IS_OK && st != UVM_HAS_X) begin
`uvm_error("RegModel",
$sformatf("Unable to read MSB bits in %s[%0d] to for RMW cycle on virtual field %s.",
mem.get_full_name(), segoff+segn-1,
this.get_full_name()));
status = UVM_NOT_OK;
this.parent.XatomicX(0);
return;
end
end
value |= (tmp & ~((1<<rmwbits)-1)) << ((segn-1)*segsiz);
end
// Now write each of the segments
tmp = value;
repeat (segn) begin
mem.poke(st, segoff, tmp, "", parent, extension, fname, lineno);
if (st != UVM_IS_OK && st != UVM_HAS_X) status = UVM_NOT_OK;
segoff++;
tmp = tmp >> segsiz;
end
this.parent.XatomicX(0);
`uvm_info("RegModel", $sformatf("Wrote virtual field \"%s\"[%0d] with: 'h%h",
this.get_full_name(), idx, value),UVM_MEDIUM);
this.fname = "";
this.lineno = 0;
endtask: poke
task uvm_vreg_field::peek(input longint unsigned idx,
output uvm_status_e status,
output uvm_reg_data_t value,
input uvm_sequence_base parent = null,
input uvm_object extension = null,
input string fname = "",
input int lineno = 0);
uvm_reg_data_t tmp;
uvm_reg_data_t segval;
uvm_reg_addr_t segoff;
uvm_status_e st;
int flsb, lsb;
int segsiz, segn;
uvm_mem mem;
this.fname = fname;
this.lineno = lineno;
mem = this.parent.get_memory();
if (mem == null) begin
`uvm_error("RegModel", $sformatf("Cannot call uvm_vreg_field::peek() on unimplemented virtual register \"%s\"",
this.get_full_name()));
status = UVM_NOT_OK;
return;
end
status = UVM_IS_OK;
this.parent.XatomicX(1);
value = 0;
segsiz = mem.get_n_bytes() * 8;
flsb = this.get_lsb_pos_in_register();
segoff = this.parent.get_offset_in_memory(idx) + (flsb / segsiz);
lsb = flsb % segsiz;
// Total number of memory segment in this field
segn = (lsb + this.get_n_bits() - 1) / segsiz + 1;
// Read each of the segments, MSB first
segoff += segn - 1;
repeat (segn) begin
value = value << segsiz;
mem.peek(st, segoff, tmp, "", parent, extension, fname, lineno);
if (st != UVM_IS_OK && st != UVM_HAS_X) status = UVM_NOT_OK;
segoff--;
value |= tmp;
end
// Any bits on the LSB side we need to get rid of?
value = value >> lsb;
// Any bits on the MSB side we need to get rid of?
value &= (1<<this.get_n_bits()) - 1;
this.parent.XatomicX(0);
`uvm_info("RegModel", $sformatf("Peeked virtual field \"%s\"[%0d]: 'h%h", this.get_full_name(), idx, value),UVM_MEDIUM);
this.fname = "";
this.lineno = 0;
endtask: peek
function void uvm_vreg_field::do_print (uvm_printer printer);
super.do_print(printer);
printer.print_generic("initiator", parent.get_type_name(), -1, convert2string());
endfunction
function string uvm_vreg_field::convert2string();
string res_str;
string t_str;
bit with_debug_info = 1'b0;
$sformat(convert2string, {"%s[%0d-%0d]"},
this.get_name(),
this.get_lsb_pos_in_register() + this.get_n_bits() - 1,
this.get_lsb_pos_in_register());
if (read_in_progress == 1'b1) begin
if (fname != "" && lineno != 0)
$sformat(res_str, "%s:%0d ",fname, lineno);
convert2string = {convert2string, "\n", res_str, "currently executing read method"};
end
if ( write_in_progress == 1'b1) begin
if (fname != "" && lineno != 0)
$sformat(res_str, "%s:%0d ",fname, lineno);
convert2string = {convert2string, "\n", res_str, "currently executing write method"};
end
endfunction
//TODO - add fatal messages
function uvm_object uvm_vreg_field::clone();
return null;
endfunction
function void uvm_vreg_field::do_copy (uvm_object rhs);
endfunction
function bit uvm_vreg_field::do_compare (uvm_object rhs,
uvm_comparer comparer);
return 0;
endfunction
function void uvm_vreg_field::do_pack (uvm_packer packer);
endfunction
function void uvm_vreg_field::do_unpack (uvm_packer packer);
endfunction