//
// -------------------------------------------------------------
// Copyright 2010 Synopsys, Inc.
// Copyright 2010 Cadence Design Systems, Inc.
// Copyright 2011 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.
// -------------------------------------------------------------
//
typedef class [docs]uvm_reg_indirect_ftdr_seq;
//-----------------------------------------------------------------
// CLASS: uvm_reg_indirect_data
// Indirect data access abstraction class
//
// Models the behavior of a register used to indirectly access
// a register array, indexed by a second ~address~ register.
//
// This class should not be instantiated directly.
// A type-specific class extension should be used to
// provide a factory-enabled constructor and specify the
// ~n_bits~ and coverage models.
//-----------------------------------------------------------------
class [docs]uvm_reg_indirect_data extends uvm_reg;
protected uvm_reg m_idx;
protected uvm_reg m_tbl[];
// Function: new
// Create an instance of this class
//
// Should not be called directly,
// other than via super.new().
// The value of ~n_bits~ must match the number of bits
// in the indirect register array.
function [docs]new(string name = "uvm_reg_indirect",
int unsigned n_bits,
int has_cover);
super.new(name,n_bits,has_cover);
endfunction: new
virtual function void [docs]build();
endfunction: build
// Function: configure
// Configure the indirect data register.
//
// The ~idx~ register specifies the index,
// in the ~reg_a~ register array, of the register to access.
// The ~idx~ must be written to first.
// A read or write operation to this register will subsequently
// read or write the indexed register in the register array.
//
// The number of bits in each register in the register array must be
// equal to ~n_bits~ of this register.
//
// See <uvm_reg::configure()> for the remaining arguments.
function void [docs]configure (uvm_reg idx,
uvm_reg reg_a[],
uvm_reg_block blk_parent,
uvm_reg_file regfile_parent = null);
super.configure(blk_parent, regfile_parent, "");
m_idx = idx;
m_tbl = reg_a;
// Not testable using pre-defined sequences
uvm_resource_db#(bit)::set({"REG::", get_full_name()},
"NO_REG_TESTS", 1);
// Add a frontdoor to each indirectly-accessed register
// for every address map this register is in.
foreach (m_maps[map]) begin
add_frontdoors(map);
end
endfunction
/*local*/ virtual function void [docs]add_map(uvm_reg_map map);
super.add_map(map);
add_frontdoors(map);
endfunction
local function void add_frontdoors(uvm_reg_map map);
foreach (m_tbl[i]) begin
uvm_reg_indirect_ftdr_seq fd;
if (m_tbl[i] == null) begin
`uvm_error(get_full_name(),
$sformatf("Indirect register #%0d is NULL", i));
continue;
end
fd = new(m_idx, i, this);
if (m_tbl[i].is_in_map(map))
m_tbl[i].set_frontdoor(fd, map);
else
map.add_reg(m_tbl[i], -1, "RW", 1, fd);
end
endfunction
virtual function void [docs]do_predict (uvm_reg_item rw,
uvm_predict_e kind = UVM_PREDICT_DIRECT,
uvm_reg_byte_en_t be = -1);
if (m_idx.get() >= m_tbl.size()) begin
`uvm_error(get_full_name(), $sformatf("Address register %s has a value (%0d) greater than the maximum indirect register array size (%0d)", m_idx.get_full_name(), m_idx.get(), m_tbl.size()));
rw.status = UVM_NOT_OK;
return;
end
//NOTE limit to 2**32 registers
begin
int unsigned idx = m_idx.get();
m_tbl[idx].do_predict(rw, kind, be);
end
endfunction
virtual function uvm_reg_map [docs]get_local_map(uvm_reg_map map, string caller="");
return m_idx.get_local_map(map,caller);
endfunction
//
// Just for good measure, to catch and short-circuit non-sensical uses
//
virtual function void [docs]add_field (uvm_reg_field field);
`uvm_error(get_full_name(), "Cannot add field to an indirect data access register");
endfunction
virtual function void [docs]set (uvm_reg_data_t value,
string fname = "",
int lineno = 0);
`uvm_error(get_full_name(), "Cannot set() an indirect data access register");
endfunction
virtual function uvm_reg_data_t [docs]get(string fname = "",
int lineno = 0);
`uvm_error(get_full_name(), "Cannot get() an indirect data access register");
return 0;
endfunction
virtual function uvm_reg [docs]get_indirect_reg(string fname = "",
int lineno = 0);
int unsigned idx = m_idx.get_mirrored_value();
return(m_tbl[idx]);
endfunction
virtual function bit [docs]needs_update();
return 0;
endfunction
virtual task [docs]write(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 int prior = -1,
input uvm_object extension = null,
input string fname = "",
input int lineno = 0);
if (path == UVM_DEFAULT_PATH) begin
uvm_reg_block blk = get_parent();
path = blk.get_default_path();
end
if (path == UVM_BACKDOOR) begin
`uvm_warning(get_full_name(), "Cannot backdoor-write an indirect data access register. Switching to frontdoor.");
path = UVM_FRONTDOOR;
end
// Can't simply call super.write() because it'll call set()
begin
uvm_reg_item rw;
XatomicX(1);
rw = uvm_reg_item::type_id::create("write_item",,get_full_name());
rw.element = this;
rw.element_kind = UVM_REG;
rw.kind = UVM_WRITE;
rw.value[0] = value;
rw.path = path;
rw.map = map;
rw.parent = parent;
rw.prior = prior;
rw.extension = extension;
rw.fname = fname;
rw.lineno = lineno;
do_write(rw);
status = rw.status;
XatomicX(0);
end
endtask
virtual task [docs]read(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 int prior = -1,
input uvm_object extension = null,
input string fname = "",
input int lineno = 0);
if (path == UVM_DEFAULT_PATH) begin
uvm_reg_block blk = get_parent();
path = blk.get_default_path();
end
if (path == UVM_BACKDOOR) begin
`uvm_warning(get_full_name(), "Cannot backdoor-read an indirect data access register. Switching to frontdoor.");
path = UVM_FRONTDOOR;
end
super.read(status, value, path, map, parent, prior, extension, fname, lineno);
endtask
virtual task [docs]poke(output uvm_status_e status,
input uvm_reg_data_t value,
input string kind = "",
input uvm_sequence_base parent = null,
input uvm_object extension = null,
input string fname = "",
input int lineno = 0);
`uvm_error(get_full_name(), "Cannot poke() an indirect data access register");
status = UVM_NOT_OK;
endtask
virtual task [docs]peek(output uvm_status_e status,
output uvm_reg_data_t value,
input string kind = "",
input uvm_sequence_base parent = null,
input uvm_object extension = null,
input string fname = "",
input int lineno = 0);
`uvm_error(get_full_name(), "Cannot peek() an indirect data access register");
status = UVM_NOT_OK;
endtask
virtual task [docs]update(output uvm_status_e status,
input uvm_path_e path = UVM_DEFAULT_PATH,
input uvm_reg_map map = null,
input uvm_sequence_base parent = null,
input int prior = -1,
input uvm_object extension = null,
input string fname = "",
input int lineno = 0);
status = UVM_IS_OK;
endtask
virtual task [docs]mirror(output uvm_status_e status,
input uvm_check_e check = UVM_NO_CHECK,
input uvm_path_e path = UVM_DEFAULT_PATH,
input uvm_reg_map map = null,
input uvm_sequence_base parent = null,
input int prior = -1,
input uvm_object extension = null,
input string fname = "",
input int lineno = 0);
status = UVM_IS_OK;
endtask
endclass : uvm_reg_indirect_data
class [docs]uvm_reg_indirect_ftdr_seq extends uvm_reg_frontdoor;
local uvm_reg m_addr_reg;
local uvm_reg m_data_reg;
local int m_idx;
function [docs]new(uvm_reg addr_reg,
int idx,
uvm_reg data_reg);
super.new("uvm_reg_indirect_ftdr_seq");
m_addr_reg = addr_reg;
m_idx = idx;
m_data_reg = data_reg;
endfunction: new
virtual task [docs]body();
uvm_reg_item rw;
$cast(rw,rw_info.clone());
rw.element = m_addr_reg;
rw.kind = UVM_WRITE;
rw.value[0]= m_idx;
m_addr_reg.XatomicX(1);
m_data_reg.XatomicX(1);
m_addr_reg.do_write(rw);
if (rw.status == UVM_NOT_OK)
return;
$cast(rw,rw_info.clone());
rw.element = m_data_reg;
if (rw_info.kind == UVM_WRITE)
m_data_reg.do_write(rw);
else begin
m_data_reg.do_read(rw);
rw_info.value[0] = rw.value[0];
end
m_addr_reg.XatomicX(0);
m_data_reg.XatomicX(0);
rw_info.status = rw.status;
endtask
endclass