//
// -------------------------------------------------------------
// Copyright 2004-2008 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: Memory Access Test Sequence
//
//
// class: uvm_mem_single_access_seq
//
// Verify the accessibility of a memory
// by writing through its default address map
// then reading it via the backdoor, then reversing the process,
// making sure that the resulting value matches the written value.
//
// If bit-type resource named
// "NO_REG_TESTS", "NO_MEM_TESTS", or "NO_MEM_ACCESS_TEST"
// in the "REG::" namespace
// matches the full name of the memory,
// the memory is not tested.
//
//| uvm_resource_db#(bit)::set({"REG::",regmodel.blk.mem0.get_full_name()},
//| "NO_MEM_TESTS", 1, this);
//
// Memories without an available backdoor
// cannot be tested.
//
// The DUT should be idle and not modify the memory during this test.
//
class [docs]uvm_mem_single_access_seq extends uvm_reg_sequence #(uvm_sequence #(uvm_reg_item));
// Variable: mem
//
// The memory to be tested
//
uvm_mem mem;
`uvm_object_utils(uvm_mem_single_access_seq)
function [docs]new(string name="uam_mem_single_access_seq");
super.new(name);
endfunction
virtual task [docs]body();
string mode;
uvm_reg_map maps[$];
int n_bits;
if (mem == null) begin
`uvm_error("uvm_mem_access_seq", "No register specified to run sequence on");
return;
end
// Memories with some attributes are not to be tested
if (uvm_resource_db#(bit)::get_by_name({"REG::",mem.get_full_name()},
"NO_REG_TESTS", 0) != null ||
uvm_resource_db#(bit)::get_by_name({"REG::",mem.get_full_name()},
"NO_MEM_TESTS", 0) != null ||
uvm_resource_db#(bit)::get_by_name({"REG::",mem.get_full_name()},
"NO_MEM_ACCESS_TEST", 0) != null)
return;
// Can only deal with memories with backdoor access
if (mem.get_backdoor() == null && !mem.has_hdl_path()) begin
`uvm_error("uvm_mem_access_seq", {"Memory '",mem.get_full_name(),
"' does not have a backdoor mechanism available"})
return;
end
n_bits = mem.get_n_bits();
// Memories may be accessible from multiple physical interfaces (maps)
mem.get_maps(maps);
// Walk the memory via each map
foreach (maps[j]) begin
uvm_status_e status;
uvm_reg_data_t val, exp, v;
`uvm_info("uvm_mem_access_seq", {"Verifying access of memory '",
mem.get_full_name(),"' in map '", maps[j].get_full_name(),
"' ..."}, UVM_LOW)
mode = mem.get_access(maps[j]);
// The access process is, for address k:
// - Write random value via front door
// - Read via backdoor and expect same random value if RW
// - Write complement of random value via back door
// - Read via front door and expect inverted random value
for (int k = 0; k < mem.get_size(); k++) begin
val = $random & uvm_reg_data_t'((1'b1<<n_bits)-1);
if (n_bits > 32)
val = uvm_reg_data_t'(val << 32) | $random;
if (mode == "RO") begin
mem.peek(status, k, exp);
if (status != UVM_IS_OK) begin
`uvm_error("uvm_mem_access_seq", $sformatf("Status was %s when reading \"%s[%0d]\" through backdoor.",
status.name(), mem.get_full_name(), k))
end
end
else exp = val;
mem.write(status, k, val, UVM_FRONTDOOR, maps[j], this);
if (status != UVM_IS_OK) begin
`uvm_error("uvm_mem_access_seq", $sformatf("Status was %s when writing \"%s[%0d]\" through map \"%s\".",
status.name(), mem.get_full_name(), k, maps[j].get_full_name()))
end
#1;
val = 'x;
mem.peek(status, k, val);
if (status != UVM_IS_OK) begin
`uvm_error("uvm_mem_access_seq", $sformatf("Status was %s when reading \"%s[%0d]\" through backdoor.",
status.name(), mem.get_full_name(), k))
end
else begin
if (val !== exp) begin
`uvm_error("uvm_mem_access_seq", $sformatf("Backdoor \"%s[%0d]\" read back as 'h%h instead of 'h%h.",
mem.get_full_name(), k, val, exp))
end
end
exp = ~exp & ((1'b1<<n_bits)-1);
mem.poke(status, k, exp);
if (status != UVM_IS_OK) begin
`uvm_error("uvm_mem_access_seq", $sformatf("Status was %s when writing \"%s[%0d-1]\" through backdoor.",
status.name(), mem.get_full_name(), k))
end
mem.read(status, k, val, UVM_FRONTDOOR, maps[j], this);
if (status != UVM_IS_OK) begin
`uvm_error("uvm_mem_access_seq", $sformatf("Status was %s when reading \"%s[%0d]\" through map \"%s\".",
status.name(), mem.get_full_name(), k, maps[j].get_full_name()))
end
else begin
if (mode == "WO") begin
if (val !== '0) begin
`uvm_error("uvm_mem_access_seq", $sformatf("Front door \"%s[%0d]\" read back as 'h%h instead of 'h%h.",
mem.get_full_name(), k, val, 0))
end
end
else begin
if (val !== exp) begin
`uvm_error("uvm_mem_access_seq", $sformatf("Front door \"%s[%0d]\" read back as 'h%h instead of 'h%h.",
mem.get_full_name(), k, val, exp))
end
end
end
end
end
endtask: body
endclass: uvm_mem_single_access_seq
//
// class: uvm_mem_access_seq
//
// Verify the accessibility of all memories in a block
// by executing the <uvm_mem_single_access_seq> sequence on
// every memory within it.
//
// If bit-type resource named
// "NO_REG_TESTS", "NO_MEM_TESTS", or "NO_MEM_ACCESS_TEST"
// in the "REG::" namespace
// matches the full name of the block,
// the block is not tested.
//
//| uvm_resource_db#(bit)::set({"REG::",regmodel.blk.get_full_name(),".*"},
//| "NO_MEM_TESTS", 1, this);
//
class [docs]uvm_mem_access_seq extends uvm_reg_sequence #(uvm_sequence #(uvm_reg_item));
// Variable: model
//
// The block to be tested. Declared in the base class.
//
//| uvm_reg_block model;
// Variable: mem_seq
//
// The sequence used to test one memory
//
protected uvm_mem_single_access_seq mem_seq;
`uvm_object_utils(uvm_mem_access_seq)
function [docs]new(string name="uvm_mem_access_seq");
super.new(name);
endfunction
// Task: body
//
// Execute the Memory Access sequence.
// Do not call directly. Use seq.start() instead.
//
virtual task [docs]body();
if (model == null) begin
`uvm_error("uvm_mem_access_seq", "No register model specified to run sequence on");
return;
end
uvm_report_info("STARTING_SEQ",{"\n\nStarting ",get_name()," sequence...\n"},UVM_LOW);
mem_seq = uvm_mem_single_access_seq::type_id::create("single_mem_access_seq");
this.reset_blk(model);
model.reset();
do_block(model);
endtask: body
// Task: do_block
//
// Test all of the memories in a given ~block~
//
protected virtual task do_block(uvm_reg_block blk);
uvm_mem mems[$];
if (uvm_resource_db#(bit)::get_by_name({"REG::",blk.get_full_name()},
"NO_REG_TESTS", 0) != null ||
uvm_resource_db#(bit)::get_by_name({"REG::",blk.get_full_name()},
"NO_MEM_TESTS", 0) != null ||
uvm_resource_db#(bit)::get_by_name({"REG::",blk.get_full_name()},
"NO_MEM_ACCESS_TEST", 0) != null )
return;
// Iterate over all memories, checking accesses
blk.get_memories(mems, UVM_NO_HIER);
foreach (mems[i]) begin
// Registers with some attributes are not to be tested
if (uvm_resource_db#(bit)::get_by_name({"REG::",mems[i].get_full_name()},
"NO_REG_TESTS", 0) != null ||
uvm_resource_db#(bit)::get_by_name({"REG::",mems[i].get_full_name()},
"NO_MEM_TESTS", 0) != null ||
uvm_resource_db#(bit)::get_by_name({"REG::",mems[i].get_full_name()},
"NO_MEM_ACCESS_TEST", 0) != null )
continue;
// Can only deal with memories with backdoor access
if (mems[i].get_backdoor() == null &&
!mems[i].has_hdl_path()) begin
`uvm_warning("uvm_mem_access_seq", $sformatf("Memory \"%s\" does not have a backdoor mechanism available",
mems[i].get_full_name()));
continue;
end
mem_seq.mem = mems[i];
mem_seq.start(null, this);
end
begin
uvm_reg_block blks[$];
blk.get_blocks(blks);
foreach (blks[i]) begin
do_block(blks[i]);
end
end
endtask: do_block
// Task: reset_blk
//
// Reset the DUT that corresponds to the specified block abstraction class.
//
// Currently empty.
// Will rollback the environment's phase to the ~reset~
// phase once the new phasing is available.
//
// In the meantime, the DUT should be reset before executing this
// test sequence or this method should be implemented
// in an extension to reset the DUT.
//
virtual task [docs]reset_blk(uvm_reg_block blk);
endtask
endclass: uvm_mem_access_seq