Source code for uvm.reg.sequences.uvm_mem_walk_seq

#//
#// -------------------------------------------------------------
#//    Copyright 2004-2008 Synopsys, Inc.
#//    Copyright 2010 Mentor Graphics Corporation
#//    Copyright 2019-2020 Tuomas Poikela (tpoikela)
#//    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.
#// -------------------------------------------------------------
#//

import cocotb
from cocotb.triggers import Timer

from ..uvm_reg_sequence import UVMRegSequence
from ..uvm_reg_model import (UVM_FRONTDOOR, UVM_IS_OK, UVM_NO_HIER,
    UVM_STATUS_NAMES)
from ...macros import (uvm_info, uvm_error, uvm_object_utils)
from ...base.uvm_resource_db import UVMResourceDb
from ...base.sv import sv
from ...base.uvm_object_globals import UVM_LOW
from ...base.uvm_globals import uvm_zero_delay

#//------------------------------------------------------------------------------
#// Title: Memory Walking-Ones Test Sequences
#//
#// This section defines sequences for applying a "walking-ones"
#// algorithm on one or more memories.
#//------------------------------------------------------------------------------


#//------------------------------------------------------------------------------
#// Class: UVMMemSingleWalkSeq
#//
#// Runs the walking-ones algorithm on the memory given by the <mem> property,
#// which must be assigned prior to starting this sequence.
#//
#// If bit-type resource named
#// "NO_REG_TESTS", "NO_MEM_TESTS", or "NO_MEM_WALK_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);
#//
#// The walking ones algorithm is performed for each map in which the memory
#// is defined.
#//
#//| for (k = 0 thru memsize-1)
#//|   write addr=k data=~k
#//|   if (k > 0) {
#//|     read addr=k-1, expect data=~(k-1)
#//|     write addr=k-1 data=k-1
#//|   if (k == last addr)
#//|     read addr=k, expect data=~k
#//
#//------------------------------------------------------------------------------


[docs]class UVMMemSingleWalkSeq(UVMRegSequence): # (uvm_sequence #(uvm_reg_item)) # // Function: new # // # // Creates a new instance of the class with the given name. # def __init__(self, name="UVMMemWalkSeq"): super().__init__(name) # // Variable: mem # // # // The memory to test; must be assigned prior to starting sequence. self.mem = None # endfunction # // Task: body # // # // Performs the walking-ones algorithm on each map of the memory # // specified in <mem>.
[docs] async def body(self): maps = [] # uvm_reg_map [$] n_bits = 0 mem = self.mem if mem is None: uvm_error("UVMMemWalkSeq", "No memory specified to run sequence on") return # Memories with some attributes are not to be tested if (UVMResourceDb.get_by_name("REG::" + mem.get_full_name(), "NO_REG_TESTS", 0) is not None or UVMResourceDb.get_by_name("REG::" + mem.get_full_name(), "NO_MEM_TESTS", 0) is not None or UVMResourceDb.get_by_name("REG::" + mem.get_full_name(), "NO_MEM_WALK_TEST", 0) is not None): return 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 for j in range(len(maps)): status = 0 val = 0 exp = 0 # v = 0 # Only deal with RW memories if mem.get_access(maps[j]) != "RW": continue uvm_info("UVMMemWalkSeq", sv.sformatf("Walking memory %s (n_bits: %d) in map \"%s\"...", mem.get_full_name(), n_bits, maps[j].get_full_name()), UVM_LOW) # The walking process is, for address k: # - Write ~k # - Read k-1 and expect ~(k-1) if k > 0 # - Write k-1 at k-1 # - Read k and expect ~k if k == last address for k in range(mem.get_size()): status = [] await mem.write(status, k, ~k, UVM_FRONTDOOR, maps[j], self) status = status[0] if status != UVM_IS_OK: uvm_error("UVMMemWalkSeq", sv.sformatf( "Status was %s when writing \"%s[%0d]\" through map \"%s\".", status.name(), mem.get_full_name(), k, maps[j].get_full_name())) if k > 0: status = [] val = [] await mem.read(status, k-1, val, UVM_FRONTDOOR, maps[j], self) status = status[0] if status != UVM_IS_OK: uvm_error("UVMMemWalkSeq", sv.sformatf( "Status was %s when reading \"%s[%0d]\" through map \"%s\".", UVM_STATUS_NAMES[status], mem.get_full_name(), k, maps[j].get_full_name())) else: exp = ~(k-1) & ((1 << n_bits)-1) val = val[0] if val != exp: uvm_error("UVMMemWalkSeq", sv.sformatf("\"%s[%0d-1]\" read back as 'h%h instead of 'h%h.", mem.get_full_name(), k, val, exp)) status = [] await mem.write(status, k-1, k-1, UVM_FRONTDOOR, maps[j], self) status = status[0] if status != UVM_IS_OK: uvm_error("UVMMemWalkSeq", sv.sformatf( "Status was %s when writing \"%s[%0d-1]\" through map \"%s\".", UVM_STATUS_NAMES[status], mem.get_full_name(), k, maps[j].get_full_name())) if k == mem.get_size() - 1: status = [] val = [] await mem.read(status, k, val, UVM_FRONTDOOR, maps[j], self) status = status[0] if status != UVM_IS_OK: uvm_error("UVMMemWalkSeq", sv.sformatf( "Status was %s when reading \"%s[%0d]\" through map \"%s\".", UVM_STATUS_NAMES[status], mem.get_full_name(), k, maps[j].get_full_name())) else: exp = ~(k) & ((1<<n_bits)-1) val = val[0] if val != exp: uvm_error("UVMMemWalkSeq", sv.sformatf("\"%s[%0d]\" read back as 'h%h instead of 'h%h.", mem.get_full_name(), k, val, exp))
uvm_object_utils(UVMMemSingleWalkSeq) #//------------------------------------------------------------------------------ #// Class: UVMMemWalkSeq #// #// Verifies the all memories in a block #// by executing the <UVMMemSingleWalkSeq> sequence on #// every memory within it. #// #// If bit-type resource named #// "NO_REG_TESTS", "NO_MEM_TESTS", or "NO_MEM_WALK_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); #// #//------------------------------------------------------------------------------
[docs]class UVMMemWalkSeq(UVMRegSequence): # (uvm_sequence #(uvm_reg_item)) def __init__(self, name="UVMMemWalkSeq"): super().__init__(name) # // Variable: model # // # // The block to be tested. Declared in the base class. # // # //| uvm_reg_block model; self.model = None # // Variable: mem_seq # // # // The sequence used to test one memory # // self.mem_seq = None # # // Task: body # // # // Executes the mem walk sequence, one block at a time. # // Do not call directly. Use seq.start() instead. # //
[docs] async def body(self): if self.model is None: uvm_error("UVMMemWalkSeq", "No register model specified to run sequence on") return uvm_info("STARTING_SEQ","\n\nStarting " + self.get_name() + " sequence...\n",UVM_LOW) self.mem_seq = UVMMemSingleWalkSeq.type_id.create("single_mem_walk_seq") await self.reset_blk(self.model) self.model.reset() await self.do_block(self.model)
# // Task: do_block # // # // Test all of the memories in a given ~block~ # //
[docs] async def do_block(self, blk): mems = [] # uvm_mem[$] if (UVMResourceDb.get_by_name("REG::" + blk.get_full_name(), "NO_REG_TESTS", 0) is not None or UVMResourceDb.get_by_name("REG::" + blk.get_full_name(), "NO_MEM_TESTS", 0) is not None or UVMResourceDb.get_by_name("REG::" + blk.get_full_name(), "NO_MEM_ACCESS_TEST", 0) is not None): return # Iterate over all memories, checking accesses blk.get_memories(mems, UVM_NO_HIER) for i in range(len(mems)): # Memories with some attributes are not to be tested if (UVMResourceDb.get_by_name("REG::" + mems[i].get_full_name(), "NO_REG_TESTS", 0) is not None or UVMResourceDb.get_by_name("REG::" + mems[i].get_full_name(), "NO_MEM_TESTS", 0) is not None or UVMResourceDb.get_by_name("REG::" + mems[i].get_full_name(), "NO_MEM_WALK_TEST", 0) is not None): continue self.mem_seq.mem = mems[i] await self.mem_seq.start(None, self) blks = [] # uvm_reg_block [$] blk.get_blocks(blks) for i in range(len(blks)): await self.do_block(blks[i])
# // 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. # //
[docs] async def reset_blk(self, blk): await uvm_zero_delay()
uvm_object_utils(UVMMemWalkSeq)