blob: df4afab9ecf8d573f4b22ed580b052f9791bfcfa [file] [log] [blame]
/*
* Copyright (c) 2012 ARM Limited
* All rights reserved
*
* The license below extends only to copyright in the software and shall
* not be construed as granting a license to any other intellectual
* property including but not limited to intellectual property relating
* to a hardware implementation of the functionality of the software
* licensed hereunder. You may use the software subject to the license
* terms below provided that you ensure that this notice is replicated
* unmodified and in its entirety in all distributions of the software,
* modified or unmodified, in source code or in binary form.
*
* Copyright (c) 2002-2005 The Regents of The University of Michigan
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met: redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer;
* redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution;
* neither the name of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Authors: Nathan Binkert
* Steve Reinhardt
* Andreas Hansson
*/
#ifndef __BASE_ADDR_RANGE_HH__
#define __BASE_ADDR_RANGE_HH__
#include <vector>
#include "base/bitfield.hh"
#include "base/cprintf.hh"
#include "base/misc.hh"
#include "base/types.hh"
class AddrRange
{
private:
/// Private fields for the start and end of the range
/// Both _start and _end are part of the range.
Addr _start;
Addr _end;
/// The high bit of the slice that is used for interleaving
uint8_t intlvHighBit;
/// The number of bits used for interleaving, set to 0 to disable
uint8_t intlvBits;
/// The value to compare the slice addr[high:(high - bits + 1)]
/// with.
uint8_t intlvMatch;
public:
AddrRange()
: _start(1), _end(0), intlvHighBit(0), intlvBits(0), intlvMatch(0)
{}
AddrRange(Addr _start, Addr _end, uint8_t _intlv_high_bit,
uint8_t _intlv_bits, uint8_t _intlv_match)
: _start(_start), _end(_end), intlvHighBit(_intlv_high_bit),
intlvBits(_intlv_bits), intlvMatch(_intlv_match)
{}
AddrRange(Addr _start, Addr _end)
: _start(_start), _end(_end), intlvHighBit(0), intlvBits(0),
intlvMatch(0)
{}
/**
* Create an address range by merging a collection of interleaved
* ranges.
*
* @param ranges Interleaved ranges to be merged
*/
AddrRange(const std::vector<AddrRange>& ranges)
: _start(1), _end(0), intlvHighBit(0), intlvBits(0), intlvMatch(0)
{
if (!ranges.empty()) {
// get the values from the first one and check the others
_start = ranges.front()._start;
_end = ranges.front()._end;
intlvHighBit = ranges.front().intlvHighBit;
intlvBits = ranges.front().intlvBits;
if (ranges.size() != (ULL(1) << intlvBits))
fatal("Got %d ranges spanning %d interleaving bits\n",
ranges.size(), intlvBits);
uint8_t match = 0;
for (std::vector<AddrRange>::const_iterator r = ranges.begin();
r != ranges.end(); ++r) {
if (!mergesWith(*r))
fatal("Can only merge ranges with the same start, end "
"and interleaving bits\n");
if (r->intlvMatch != match)
fatal("Expected interleave match %d but got %d when "
"merging\n", match, r->intlvMatch);
++match;
}
// our range is complete and we can turn this into a
// non-interleaved range
intlvHighBit = 0;
intlvBits = 0;
}
}
/**
* Determine if the range is interleaved or not.
*
* @return true if interleaved
*/
bool interleaved() const { return intlvBits != 0; }
/**
* Determing the interleaving granularity of the range.
*
* @return The size of the regions created by the interleaving bits
*/
uint64_t granularity() const
{
return ULL(1) << (intlvHighBit - intlvBits + 1);
}
/**
* Determine the number of interleaved address stripes this range
* is part of.
*
* @return The number of stripes spanned by the interleaving bits
*/
uint32_t stripes() const { return ULL(1) << intlvBits; }
/**
* Get the size of the address range. For a case where
* interleaving is used we make the simplifying assumption that
* the size is a divisible by the size of the interleaving slice.
*/
Addr size() const
{
return (_end - _start + 1) >> intlvBits;
}
/**
* Determine if the range is valid.
*/
bool valid() const { return _start <= _end; }
/**
* Get the start address of the range.
*/
Addr start() const { return _start; }
/**
* Get a string representation of the range. This could
* alternatively be implemented as a operator<<, but at the moment
* that seems like overkill.
*/
std::string to_string() const
{
if (interleaved())
return csprintf("[%#llx : %#llx], [%d : %d] = %d", _start, _end,
intlvHighBit, intlvHighBit - intlvBits + 1,
intlvMatch);
else
return csprintf("[%#llx : %#llx]", _start, _end);
}
/**
* Determine if another range merges with the current one, i.e. if
* they are part of the same contigous range and have the same
* interleaving bits.
*
* @param r Range to evaluate merging with
* @return true if the two ranges would merge
*/
bool mergesWith(const AddrRange& r) const
{
return r._start == _start && r._end == _end &&
r.intlvHighBit == intlvHighBit &&
r.intlvBits == intlvBits;
}
/**
* Determine if another range intersects this one, i.e. if there
* is an address that is both in this range and the other
* range. No check is made to ensure either range is valid.
*
* @param r Range to intersect with
* @return true if the intersection of the two ranges is not empty
*/
bool intersects(const AddrRange& r) const
{
if (!interleaved()) {
return _start <= r._end && _end >= r._start;
}
// the current range is interleaved, split the check up in
// three cases
if (r.size() == 1)
// keep it simple and check if the address is within
// this range
return contains(r.start());
else if (!r.interleaved())
// be conservative and ignore the interleaving
return _start <= r._end && _end >= r._start;
else if (mergesWith(r))
// restrict the check to ranges that belong to the
// same chunk
return intlvMatch == r.intlvMatch;
else
panic("Cannot test intersection of interleaved range %s\n",
to_string());
}
/**
* Determine if this range is a subset of another range, i.e. if
* every address in this range is also in the other range. No
* check is made to ensure either range is valid.
*
* @param r Range to compare with
* @return true if the this range is a subset of the other one
*/
bool isSubset(const AddrRange& r) const
{
if (interleaved())
panic("Cannot test subset of interleaved range %s\n", to_string());
return _start >= r._start && _end <= r._end;
}
/**
* Determine if the range contains an address.
*
* @param a Address to compare with
* @return true if the address is in the range
*/
bool contains(const Addr& a) const
{
// check if the address is in the range and if there is either
// no interleaving, or with interleaving also if the selected
// bits from the address match the interleaving value
return a >= _start && a <= _end &&
(!interleaved() ||
(bits(a, intlvHighBit, intlvHighBit - intlvBits + 1) ==
intlvMatch));
}
/**
* Keep the operators away from SWIG.
*/
#ifndef SWIG
/**
* Less-than operator used to turn an STL map into a binary search
* tree of non-overlapping address ranges.
*
* @param r Range to compare with
* @return true if the start address is less than that of the other range
*/
bool operator<(const AddrRange& r) const
{
if (_start != r._start)
return _start < r._start;
else
// for now assume that the end is also the same, and that
// we are looking at the same interleaving bits
return intlvMatch < r.intlvMatch;
}
#endif // SWIG
};
inline AddrRange
RangeEx(Addr start, Addr end)
{ return AddrRange(start, end - 1); }
inline AddrRange
RangeIn(Addr start, Addr end)
{ return AddrRange(start, end); }
inline AddrRange
RangeSize(Addr start, Addr size)
{ return AddrRange(start, start + size - 1); }
#endif // __BASE_ADDR_RANGE_HH__