Files
gem5/src/base/addr_range.test.cc
Gabe Black e9b7f08abb base,python: Expand AddrRange exclude and add subtraction operators.
Expand exclude to work with an AddrRange or AddrRangeList, define
versions to exclude both from an AddrRangeList, and make all available
through subtraction operators. Add -= operators for AddrRangeList with
another AddrRangeList or AddrRange.

Change-Id: Ic48f0c45a4809dbc51e1d3133e8319134aabe29e
Reviewed-on: https://gem5-review.googlesource.com/c/public/gem5/+/50347
Tested-by: kokoro <noreply+kokoro@google.com>
Reviewed-by: Daniel Carvalho <odanrc@yahoo.com.br>
Maintainer: Daniel Carvalho <odanrc@yahoo.com.br>
2021-09-20 20:52:05 +00:00

1572 lines
44 KiB
C++

/*
* Copyright (c) 2019 The Regents of the University of California
* Copyright (c) 2018-2019, 2021 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.
*
* 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.
*/
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include <cmath>
#include "base/addr_range.hh"
#include "base/bitfield.hh"
using namespace gem5;
using testing::ElementsAre;
TEST(AddrRangeTest, ValidRange)
{
AddrRange r;
EXPECT_FALSE(r.valid());
}
/*
* This following tests check the behavior of AddrRange when initialized with
* a start and end address. The expected behavior is that the first address
* within the range will be the start address, and the last address in the
* range will be the (end - 1) address.
*/
TEST(AddrRangeTest, EmptyRange)
{
AddrRange r(0x0, 0x0);
/*
* Empty ranges are valid.
*/
EXPECT_TRUE(r.valid());
EXPECT_EQ(0x0, r.start());
EXPECT_EQ(0x0, r.end());
EXPECT_EQ(0, r.size());
/*
* With no masks, granularity equals the size of the range.
*/
EXPECT_EQ(0, r.granularity());
/*
* With no masks, "interleaved()" returns false.
*/
EXPECT_FALSE(r.interleaved());
/*
* With no masks, "stripes()" returns 1ULL.
*/
EXPECT_EQ(1ULL, r.stripes());
EXPECT_EQ("[0:0]", r.to_string());
}
TEST(AddrRangeTest, RangeSizeOfOne)
{
AddrRange r(0x0, 0x1);
EXPECT_TRUE(r.valid());
EXPECT_EQ(0x0, r.start());
EXPECT_EQ(0x1, r.end());
EXPECT_EQ(1, r.size());
EXPECT_EQ(1, r.granularity());
EXPECT_FALSE(r.interleaved());
EXPECT_EQ(1ULL, r.stripes());
EXPECT_EQ("[0:0x1]", r.to_string());
}
TEST(AddrRangeTest, Range16Bit)
{
AddrRange r(0xF000, 0xFFFF);
EXPECT_TRUE(r.valid());
EXPECT_EQ(0xF000, r.start());
EXPECT_EQ(0xFFFF, r.end());
EXPECT_EQ(0x0FFF, r.size());
EXPECT_EQ(0x0FFF, r.granularity());
EXPECT_FALSE(r.interleaved());
EXPECT_EQ(1ULL, r.stripes());
EXPECT_EQ("[0xf000:0xffff]", r.to_string());
}
TEST(AddrRangeTest, InvalidRange)
{
AddrRange r(0x1, 0x0);
EXPECT_FALSE(r.valid());
}
TEST(AddrRangeTest, LessThan)
{
/*
* The less-than override is a bit unintuitive and does not have a
* corresponding greater than. It compares the AddrRange.start() values.
* If they are equal, the "intlvMatch" values are compared. This is
* zero when AddRange is initialized with a just a start and end address.
*/
AddrRange r1(0xF000, 0xFFFF);
AddrRange r2(0xF001, 0xFFFF);
AddrRange r3(0xF000, 0xFFFF);
EXPECT_TRUE(r1 < r2);
EXPECT_FALSE(r2 < r1);
EXPECT_FALSE(r1 < r3);
EXPECT_FALSE(r3 < r1);
}
TEST(AddrRangeTest, EqualToNotEqualTo)
{
AddrRange r1(0x1234, 0x5678);
AddrRange r2(0x1234, 0x5678);
AddrRange r3(0x1234, 0x5679);
EXPECT_TRUE(r1 == r2);
EXPECT_FALSE(r1 == r3);
EXPECT_FALSE(r1 != r2);
EXPECT_TRUE(r1 != r3);
EXPECT_TRUE(r2 == r1);
EXPECT_FALSE(r3 == r1);
EXPECT_FALSE(r2 != r1);
EXPECT_TRUE(r3 != r1);
}
TEST(AddrRangeTest, MergesWith)
{
/*
* AddrRange.mergesWith will return true if the start, end, and masks
* are the same.
*/
AddrRange r1(0x10, 0x1F);
AddrRange r2(0x10, 0x1F);
EXPECT_TRUE(r1.mergesWith(r2));
EXPECT_TRUE(r2.mergesWith(r1));
}
TEST(AddrRangeTest, DoesNotMergeWith)
{
AddrRange r1(0x10, 0x1E);
AddrRange r2(0x10, 0x1F);
EXPECT_FALSE(r1.mergesWith(r2));
EXPECT_FALSE(r2.mergesWith(r1));
}
TEST(AddrRangeTest, IntersectsCompleteOverlap)
{
AddrRange r1(0x21, 0x30);
AddrRange r2(0x21, 0x30);
EXPECT_TRUE(r1.intersects(r2));
EXPECT_TRUE(r2.intersects(r1));
}
TEST(AddrRangeTest, IntersectsAddressWithin)
{
AddrRange r1(0x0, 0xF);
AddrRange r2(0x1, 0xE);
EXPECT_TRUE(r1.intersects(r2));
EXPECT_TRUE(r2.intersects(r1));
}
TEST(AddrRangeTest, IntersectsPartialOverlap)
{
AddrRange r1(0x0F0, 0x0FF);
AddrRange r2(0x0F5, 0xF00);
EXPECT_TRUE(r1.intersects(r2));
EXPECT_TRUE(r2.intersects(r1));
}
TEST(AddrRangeTest, IntersectsNoOverlap)
{
AddrRange r1(0x00, 0x10);
AddrRange r2(0x11, 0xFF);
EXPECT_FALSE(r1.intersects(r2));
EXPECT_FALSE(r2.intersects(r1));
}
TEST(AddrRangeTest, IntersectsFirstLastAddressOverlap)
{
AddrRange r1(0x0, 0xF);
AddrRange r2(0xF, 0xF0);
/*
* The "end address" is not in the range. Therefore, if
* r1.end() == r2.start(), the ranges do not intersect.
*/
EXPECT_FALSE(r1.intersects(r2));
EXPECT_FALSE(r2.intersects(r1));
}
TEST(AddrRangeTest, isSubsetCompleteOverlap)
{
AddrRange r1(0x10, 0x20);
AddrRange r2(0x10, 0x20);
EXPECT_TRUE(r1.isSubset(r2));
EXPECT_TRUE(r2.isSubset(r1));
}
TEST(AddrRangeTest, isSubsetNoOverlap)
{
AddrRange r1(0x10, 0x20);
AddrRange r2(0x20, 0x22);
EXPECT_FALSE(r1.isSubset(r2));
EXPECT_FALSE(r2.isSubset(r1));
}
TEST(AddrRangeTest, isSubsetTrueSubset)
{
AddrRange r1(0x10, 0x20);
AddrRange r2(0x15, 0x17);
EXPECT_TRUE(r2.isSubset(r1));
EXPECT_FALSE(r1.isSubset(r2));
}
TEST(AddrRangeTest, isSubsetPartialSubset)
{
AddrRange r1(0x20, 0x30);
AddrRange r2(0x26, 0xF0);
EXPECT_FALSE(r1.isSubset(r2));
EXPECT_FALSE(r2.isSubset(r1));
}
TEST(AddrRangeTest, isSubsetInterleavedCompleteOverlap)
{
AddrRange r1(0x00, 0x100, {0x40}, 0);
AddrRange r2(0x00, 0x40);
EXPECT_TRUE(r2.isSubset(r1));
}
TEST(AddrRangeTest, isSubsetInterleavedNoOverlap)
{
AddrRange r1(0x00, 0x100, {0x40}, 1);
AddrRange r2(0x00, 0x40);
EXPECT_FALSE(r2.isSubset(r1));
}
TEST(AddrRangeTest, isSubsetInterleavedPartialOverlap)
{
AddrRange r1(0x00, 0x100, {0x40}, 0);
AddrRange r2(0x10, 0x50);
EXPECT_FALSE(r2.isSubset(r1));
}
TEST(AddrRangeTest, Contains)
{
AddrRange r(0xF0, 0xF5);
EXPECT_FALSE(r.contains(0xEF));
EXPECT_TRUE(r.contains(0xF0));
EXPECT_TRUE(r.contains(0xF1));
EXPECT_TRUE(r.contains(0xF2));
EXPECT_TRUE(r.contains(0xF3));
EXPECT_TRUE(r.contains(0xF4));
EXPECT_FALSE(r.contains(0xF5));
EXPECT_FALSE(r.contains(0xF6));
}
TEST(AddrRangeTest, ContainsInAnEmptyRange)
{
AddrRange r(0x1, 0x1);
EXPECT_FALSE(r.contains(0x1));
}
TEST(AddrRangeTest, RemoveIntlvBits)
{
AddrRange r(0x01, 0x10);
/*
* When there are no masks, AddrRange.removeIntlBits just returns the
* address parameter.
*/
Addr a(56);
a = r.removeIntlvBits(a);
EXPECT_EQ(56, a);
}
TEST(AddrRangeTest, addIntlvBits)
{
AddrRange r(0x01, 0x10);
/*
* As with AddrRange.removeIntlBits, when there are no masks,
* AddrRange.addIntlvBits just returns the address parameter.
*/
Addr a(56);
a = r.addIntlvBits(a);
EXPECT_EQ(56, a);
}
TEST(AddrRangeTest, OffsetInRange)
{
AddrRange r(0x01, 0xF0);
EXPECT_EQ(0x04, r.getOffset(0x5));
}
TEST(AddrRangeTest, OffsetOutOfRangeAfter)
{
/*
* If the address is less than the range, MaxAddr is returned.
*/
AddrRange r(0x01, 0xF0);
EXPECT_EQ(MaxAddr, r.getOffset(0xF0));
}
TEST(AddrRangeTest, OffsetOutOfRangeBefore)
{
AddrRange r(0x05, 0xF0);
EXPECT_EQ(MaxAddr, r.getOffset(0x04));
}
/*
* The following tests check the behavior of AddrRange when initialized with
* a start and end address, as well as masks to distinguish interleaving bits.
*/
TEST(AddrRangeTest, LsbInterleavingMask)
{
Addr start = 0x00;
Addr end = 0xFF;
std::vector<Addr> masks;
/*
* The address is in range if the LSB is set, i.e. is the value is odd.
*/
masks.push_back(1);
uint8_t intlv_match = 1;
AddrRange r(start, end, masks, intlv_match);
EXPECT_TRUE(r.valid());
EXPECT_EQ(start, r.start());
EXPECT_EQ(end, r.end());
/*
* With interleaving, it's assumed the size is equal to
* start - end >> [number of masks].
*/
EXPECT_EQ(0x7F, r.size());
/*
* The Granularity, the size of regions created by the interleaving bits,
* which, in this case, is one.
*/
EXPECT_EQ(1, r.granularity());
EXPECT_TRUE(r.interleaved());
EXPECT_EQ(2ULL, r.stripes());
EXPECT_EQ("[0:0xff] a[0]^\b=1", r.to_string());
}
TEST(AddrRangeTest, TwoInterleavingMasks)
{
Addr start = 0x0000;
Addr end = 0xFFFF;
std::vector<Addr> masks;
/*
* There are two marks, the two LSBs.
*/
masks.push_back(1);
masks.push_back((1 << 1));
uint8_t intlv_match = (1 << 1) | 1;
AddrRange r(start, end, masks, intlv_match);
EXPECT_TRUE(r.valid());
EXPECT_EQ(start, r.start());
EXPECT_EQ(end, r.end());
EXPECT_EQ(0x3FFF, r.size());
EXPECT_TRUE(r.interleaved());
EXPECT_EQ(4ULL, r.stripes());
EXPECT_EQ("[0:0xffff] a[0]^\b=1 a[1]^\b=1", r.to_string());
}
TEST(AddrRangeTest, ComplexInterleavingMasks)
{
Addr start = 0x0000;
Addr end = 0xFFFF;
std::vector<Addr> masks;
masks.push_back((1 << 1) | 1);
masks.push_back((1ULL << 63) | (1ULL << 62));
uint8_t intlv_match = 0;
AddrRange r(start, end, masks, intlv_match);
EXPECT_TRUE(r.valid());
EXPECT_EQ(start, r.start());
EXPECT_EQ(end, r.end());
EXPECT_EQ(0x3FFF, r.size());
EXPECT_TRUE(r.interleaved());
EXPECT_EQ(4ULL, r.stripes());
EXPECT_EQ("[0:0xffff] a[0]^a[1]^\b=0 a[62]^a[63]^\b=0", r.to_string());
}
TEST(AddrRangeTest, InterleavingAddressesMergesWith)
{
Addr start1 = 0x0000;
Addr end1 = 0xFFFF;
std::vector<Addr> masks;
masks.push_back((1 << 29) | (1 << 20) | (1 << 10) | 1);
masks.push_back((1 << 2));
uint8_t intlv_match1 = 0;
AddrRange r1(start1, end1, masks, intlv_match1);
Addr start2 = 0x0000;
Addr end2 = 0xFFFF;
uint8_t intlv_match2 = 1; // intlv_match may differ.
AddrRange r2(start2, end2, masks, intlv_match2);
EXPECT_TRUE(r1.mergesWith(r2));
EXPECT_TRUE(r2.mergesWith(r1));
}
TEST(AddrRangeTest, InterleavingAddressesDoNotMergeWith)
{
Addr start1 = 0x0000;
Addr end1 = 0xFFFF;
std::vector<Addr> masks1;
masks1.push_back((1 << 29) | (1 << 20) | (1 << 10) | 1);
masks1.push_back((1 << 2));
uint8_t intlv_match1 = 0;
AddrRange r1(start1, end1, masks1, intlv_match1);
Addr start2 = 0x0000;
Addr end2 = 0xFFFF;
std::vector<Addr> masks2;
masks2.push_back((1 << 29) | (1 << 20) | (1 << 10) | 1);
masks2.push_back((1 << 3)); // Different mask here.
uint8_t intlv_match2 = 1; // intlv_match may differ.
AddrRange r2(start2, end2, masks2, intlv_match2);
EXPECT_FALSE(r1.mergesWith(r2));
EXPECT_FALSE(r2.mergesWith(r1));
}
TEST(AddrRangeTest, InterleavingAddressesDoNotIntersect)
{
/*
* Range 1: all the odd addresses between 0x0000 and 0xFFFF.
*/
Addr start1 = 0x0000;
Addr end1 = 0xFFFF;
std::vector<Addr> masks1;
masks1.push_back(1);
uint8_t intlv_match1 = 1;
AddrRange r1(start1, end1, masks1, intlv_match1);
/*
* Range 2: all the even addresses between 0x0000 and 0xFFFF. These
* addresses should thereby not intersect.
*/
Addr start2 = 0x0000;
Addr end2 = 0xFFFF;
std::vector<Addr> masks2;
masks2.push_back(1);
uint8_t intv_match2 = 0;
AddrRange r2(start2, end2, masks2, intv_match2);
EXPECT_FALSE(r1.intersects(r2));
EXPECT_FALSE(r2.intersects(r1));
}
TEST(AddrRangeTest, InterleavingAddressesIntersectsViaMerging)
{
Addr start1 = 0x0000;
Addr end1 = 0xFFFF;
std::vector<Addr> masks1;
masks1.push_back((1 << 29) | (1 << 20) | (1 << 10) | 1);
masks1.push_back((1 << 2));
uint8_t intlv_match1 = 0;
AddrRange r1(start1, end1, masks1, intlv_match1);
Addr start2 = 0x0000;
Addr end2 = 0xFFFF;
std::vector<Addr> masks2;
masks2.push_back((1 << 29) | (1 << 20) | (1 << 10) | 1);
masks2.push_back((1 << 2));
uint8_t intlv_match2 = 0;
AddrRange r2(start2, end2, masks2, intlv_match2);
EXPECT_TRUE(r1.intersects(r2));
EXPECT_TRUE(r2.intersects(r1));
}
TEST(AddrRangeTest, InterleavingAddressesDoesNotIntersectViaMerging)
{
Addr start1 = 0x0000;
Addr end1 = 0xFFFF;
std::vector<Addr> masks1;
masks1.push_back((1 << 29) | (1 << 20) | (1 << 10) | 1);
masks1.push_back((1 << 2));
uint8_t intlv_match1 = 0;
AddrRange r1(start1, end1, masks1, intlv_match1);
Addr start2 = 0x0000;
Addr end2 = 0xFFFF;
std::vector<Addr> masks2;
masks2.push_back((1 << 29) | (1 << 20) | (1 << 10) | 1);
masks2.push_back((1 << 2));
/*
* These addresses can merge, but their intlv_match values differ. They
* therefore do not intersect.
*/
uint8_t intlv_match2 = 1;
AddrRange r2(start2, end2, masks2, intlv_match2);
EXPECT_FALSE(r1.intersects(r2));
EXPECT_FALSE(r2.intersects(r1));
}
/*
* The following tests were created to test more complex cases where
* interleaving addresses may intersect. However, the "intersects" function
* does not cover all cases (a "Cannot test intersection..." exception will
* be thrown outside of very simple checks to see if an intersection occurs).
* The tests below accurately test whether two ranges intersect but, for now,
* code has yet to be implemented to utilize these tests. They are therefore
* disabled, but may be enabled at a later date if/when the "intersects"
* function is enhanced.
*/
TEST(AddrRangeTest, DISABLED_InterleavingAddressesIntersect)
{
/*
* Range 1: all the odd addresses between 0x0000 and 0xFFFF.
*/
Addr start1 = 0x0000;
Addr end1 = 0xFFFF;
std::vector<Addr> masks1;
masks1.push_back(1);
uint8_t intlv_match1 = 0;
AddrRange r1(start1, end1, masks1, intlv_match1);
/*
* Range 2: all the addresses divisible by 4 between 0x0000 and
* 0xFFFF. These addresses should thereby intersect.
*/
Addr start2 = 0x0000;
Addr end2 = 0xFFFF;
std::vector<Addr> masks2;
masks2.push_back(1 << 2);
uint8_t intlv_match2 = 1;
AddrRange r2(start2, end2, masks2, intlv_match2);
EXPECT_TRUE(r1.intersects(r2));
EXPECT_TRUE(r2.intersects(r1));
}
TEST(AddrRangeTest, DISABLED_InterleavingAddressesIntersectsOnOneByteAddress)
{
/*
* Range: all the odd addresses between 0x0000 and 0xFFFF.
*/
Addr start = 0x0000;
Addr end = 0xFFFF;
std::vector<Addr> masks;
masks.push_back(1);
uint8_t intlv_match = 1;
AddrRange r1(start, end, masks, intlv_match);
AddrRange r2(0x0000, 0x0001);
EXPECT_FALSE(r1.intersects(r2));
EXPECT_FALSE(r2.intersects(r1));
}
TEST(AddrRangeTest,
DISABLED_InterleavingAddressesDoesNotIntersectOnOneByteAddress)
{
/*
* Range: all the odd addresses between 0x0000 and 0xFFFF.
*/
Addr start = 0x0000;
Addr end = 0xFFFF;
std::vector<Addr> masks;
masks.push_back(1);
uint8_t intlv_match = 1;
AddrRange r1(start, end, masks, intlv_match);
AddrRange r2(0x0001, 0x0002);
EXPECT_TRUE(r1.intersects(r2));
EXPECT_TRUE(r2.intersects(r1));
}
/*
* The following three tests were created to test the addr_range.isSubset
* function for Interleaving address ranges. However, for now, this
* functionality has not been implemented. These tests are therefore disabled.
*/
TEST(AddrRangeTest, DISABLED_InterleavingAddressIsSubset)
{
// Range 1: all the even addresses between 0x0000 and 0xFFFF.
Addr start1 = 0x0000;
Addr end1 = 0xFFFF;
std::vector<Addr> masks1;
masks1.push_back(1);
uint8_t intlv_match1 = 0;
AddrRange r1(start1, end1, masks1, intlv_match1);
// Range 2: all the even addresses between 0xF000 and 0x0FFF, this is
// a subset of Range 1.
Addr start2 = 0xF000;
Addr end2 = 0x0FFF;
std::vector<Addr> masks2;
masks2.push_back(1);
uint8_t intlv_match2 = 0;
AddrRange r2(start2, end2, masks2, intlv_match2);
EXPECT_TRUE(r1.isSubset(r2));
EXPECT_TRUE(r2.isSubset(r1));
}
TEST(AddrRangeTest, DISABLED_InterleavingAddressIsNotSubset)
{
//Range 1: all the even addresses between 0x0000 and 0xFFFF.
Addr start1 = 0x0000;
Addr end1 = 0xFFFF;
std::vector<Addr> masks1;
masks1.push_back(1);
uint8_t intlv_match1 = 0;
AddrRange r1(start1, end1, masks1, intlv_match1);
// Range 2: all the odd addresses between 0xF000 and 0x0FFF, this is
//a subset of Range 1.
Addr start2 = 0xF000;
Addr end2 = 0x0FFF;
std::vector<Addr> masks2;
masks2.push_back(1);
uint8_t intlv_match2 = 1;
AddrRange r2(start2, end2, masks2, intlv_match2);
EXPECT_FALSE(r1.isSubset(r2));
EXPECT_FALSE(r2.isSubset(r1));
}
TEST(AddrRangeTest, DISABLED_InterleavingAddressContains)
{
/*
* Range: all the address between 0x0 and 0xFF which have both the 1st
* and 5th bits 1, or both are 0
*/
Addr start = 0x00;
Addr end = 0xFF;
std::vector<Addr> masks;
masks.push_back((1 << 4) | 1);
uint8_t intlv_match = 0;
AddrRange r(start, end, masks, intlv_match);
for (Addr addr = start; addr < end; addr++) {
if (((addr & 1) && ((1 << 4) & addr)) || // addr[0] && addr[4]
(!(addr & 1) && !((1 << 4) & addr))) { //!addr[0] && !addr[4]
EXPECT_TRUE(r.contains(addr));
} else {
EXPECT_FALSE(r.contains(addr));
}
}
}
TEST(AddrRangeTest, InterleavingAddressAddRemoveInterlvBits)
{
Addr start = 0x00000;
Addr end = 0x10000;
std::vector<Addr> masks;
masks.push_back(1);
uint8_t intlv_match = 1;
AddrRange r(start, end, masks, intlv_match);
Addr input = 0xFFFF;
Addr output = r.removeIntlvBits(input);
/*
* The removeIntlvBits function removes the LSB from each mask from the
* input address. For example, two masks:
* 00000001 and,
* 10000100
* with an input address of:
* 10101010
*
* we would remove bit at position 0, and at position 2, resulting in:
* 00101011
*
* In this test there is is one mask, with a LSB at position 0.
* Therefore, removing the interleaving bits is equivilant to bitshifting
* the input to the right.
*/
EXPECT_EQ(input >> 1, output);
/*
* The addIntlvBits function will re-insert bits at the removed locations
*/
EXPECT_EQ(input, r.addIntlvBits(output));
}
TEST(AddrRangeTest, InterleavingAddressAddRemoveInterlvBitsTwoMasks)
{
Addr start = 0x00000;
Addr end = 0x10000;
std::vector<Addr> masks;
masks.push_back((1 << 3) | (1 << 2) | (1 << 1) | 1);
masks.push_back((1 << 11) | (1 << 10) | (1 << 9) | (1 << 8));
uint8_t intlv_match = 1;
AddrRange r(start, end, masks, intlv_match);
Addr input = (1 << 9) | (1 << 8) | 1;
/*
* (1 << 8) and 1 are interleaving bits to be removed.
*/
Addr output = r.removeIntlvBits(input);
/*
* The bit, formally at position 9, is now at 7.
*/
EXPECT_EQ((1 << 7), output);
/*
* Re-adding the interleaving.
*/
EXPECT_EQ(input, r.addIntlvBits(output));
}
TEST(AddrRangeTest, AddRemoveInterleavBitsAcrossRange)
{
/*
* This purpose of this test is to ensure that removing then adding
* interleaving bits has no net effect.
* E.g.:
* addr_range.addIntlvBits(add_range.removeIntlvBits(an_address)) should
* always return an_address.
*/
Addr start = 0x00000;
Addr end = 0x10000;
std::vector<Addr> masks;
masks.push_back(1 << 2);
masks.push_back(1 << 3);
masks.push_back(1 << 7);
masks.push_back(1 << 11);
uint8_t intlv_match = 0xF;
AddrRange r(start, end, masks, intlv_match);
for (Addr i = 0; i < 0xFFF; i++) {
Addr removedBits = r.removeIntlvBits(i);
/*
* As intlv_match = 0xF, all the interleaved bits should be set.
*/
EXPECT_EQ(i | (1 << 2) | (1 << 3) | (1 << 7) | (1 << 11),
r.addIntlvBits(removedBits));
}
}
TEST(AddrRangeTest, AddRemoveInterleavBitsAcrossContiguousRange)
{
/*
* This purpose of this test is to ensure that removing then adding
* interleaving bits has no net effect.
* E.g.:
* addr_range.addIntlvBits(add_range.removeIntlvBits(an_address)) should
* always return an_address.
*/
Addr start = 0x00000;
Addr end = 0x10000;
std::vector<Addr> masks;
masks.push_back(1 << 2);
masks.push_back(1 << 3);
masks.push_back(1 << 4);
uint8_t intlv_match = 0x7;
AddrRange r(start, end, masks, intlv_match);
for (Addr i = 0; i < 0xFFF; i++) {
Addr removedBits = r.removeIntlvBits(i);
/*
* As intlv_match = 0x7, all the interleaved bits should be set.
*/
EXPECT_EQ(i | (1 << 2) | (1 << 3) | (1 << 4),
r.addIntlvBits(removedBits));
}
}
TEST(AddrRangeTest, InterleavingAddressesGetOffset)
{
Addr start = 0x0002;
Addr end = 0xFFFF;
std::vector<Addr> masks;
masks.push_back((1 << 4) | (1 << 2));
uint8_t intlv_match = 0;
AddrRange r(start, end, masks, intlv_match);
Addr value = ((1 << 10) | (1 << 9) | (1 << 8) | (1 << 2) | (1 << 1) | 1);
Addr value_interleaving_bits_removed =
((1 << 9) | (1 << 8) | (1 << 7) | (1 << 1) | 1);
Addr expected_output = value_interleaving_bits_removed - start;
EXPECT_EQ(expected_output, r.getOffset(value));
}
TEST(AddrRangeTest, InterleavingLessThanStartEquals)
{
Addr start1 = 0x0000FFFF;
Addr end1 = 0xFFFF0000;
std::vector<Addr> masks1;
masks1.push_back((1 << 4) | (1 << 2));
uint8_t intlv_match1 = 0;
AddrRange r1(start1, end1, masks1, intlv_match1);
Addr start2 = 0x0000FFFF;
Addr end2 = 0x000F0000;
std::vector<Addr> masks2;
masks2.push_back((1 << 4) | (1 << 2));
masks2.push_back((1 << 10));
uint8_t intlv_match2 = 2;
AddrRange r2(start2, end2, masks2, intlv_match2);
/*
* When The start addresses are equal, the intlv_match values are
* compared.
*/
EXPECT_TRUE(r1 < r2);
EXPECT_FALSE(r2 < r1);
}
TEST(AddrRangeTest, InterleavingLessThanStartNotEquals)
{
Addr start1 = 0x0000FFFF;
Addr end1 = 0xFFFF0000;
std::vector<Addr> masks1;
masks1.push_back((1 << 4) | (1 << 2));
uint8_t intlv_match1 = 0;
AddrRange r1(start1, end1, masks1, intlv_match1);
Addr start2 = 0x0000FFFE;
Addr end2 = 0x000F0000;
std::vector<Addr> masks2;
masks2.push_back((1 << 4) | (1 << 2));
masks2.push_back((1 << 10));
uint8_t intlv_match2 = 2;
AddrRange r2(start2, end2, masks2, intlv_match2);
EXPECT_TRUE(r2 < r1);
EXPECT_FALSE(r1 < r2);
}
TEST(AddrRangeTest, InterleavingEqualTo)
{
Addr start1 = 0x0000FFFF;
Addr end1 = 0xFFFF0000;
std::vector<Addr> masks1;
masks1.push_back((1 << 4) | (1 << 2));
uint8_t intlv_match1 = 0;
AddrRange r1(start1, end1, masks1, intlv_match1);
Addr start2 = 0x0000FFFF;
Addr end2 = 0xFFFF0000;
std::vector<Addr> masks2;
masks2.push_back((1 << 4) | (1 << 2));
uint8_t intlv_match2 = 0;
AddrRange r2(start2, end2, masks2, intlv_match2);
EXPECT_TRUE(r1 == r2);
}
TEST(AddrRangeTest, InterleavingNotEqualTo)
{
Addr start1 = 0x0000FFFF;
Addr end1 = 0xFFFF0000;
std::vector<Addr> masks1;
masks1.push_back((1 << 4) | (1 << 2));
uint8_t intlv_match1 = 0;
AddrRange r1(start1, end1, masks1, intlv_match1);
Addr start2 = 0x0000FFFF;
Addr end2 = 0xFFFF0000;
std::vector<Addr> masks2;
masks2.push_back((1 << 4) | (1 << 2));
masks2.push_back((1 << 10));
uint8_t intlv_match2 = 2;
AddrRange r2(start2, end2, masks2, intlv_match2);
/*
* These ranges are not equal due to having different masks.
*/
EXPECT_FALSE(r1 == r2);
}
/*
* The AddrRange(AddrRangeList) constructor "merges" the interleaving
* address ranges. It should be noted that this constructor simply checks that
* these interleaving addresses can be merged then creates a new address from
* the start and end addresses of the first address range in the list.
*/
TEST(AddrRangeTest, MergingInterleavingAddressRanges)
{
Addr start1 = 0x0000;
Addr end1 = 0xFFFF;
std::vector<Addr> masks1;
masks1.push_back((1 << 4) | (1 << 2));
uint8_t intlv_match1 = 0;
AddrRange r1(start1, end1, masks1, intlv_match1);
Addr start2 = 0x0000;
Addr end2 = 0xFFFF;
std::vector<Addr> masks2;
masks2.push_back((1 << 4) | (1 << 2));
uint8_t intlv_match2 = 1;
AddrRange r2(start2, end2, masks2, intlv_match2);
AddrRangeList to_merge;
to_merge.push_back(r1);
to_merge.push_back(r2);
AddrRange output(to_merge);
EXPECT_EQ(0x0000, output.start());
EXPECT_EQ(0xFFFF, output.end());
EXPECT_FALSE(output.interleaved());
}
TEST(AddrRangeTest, MergingInterleavingAddressRangesOneRange)
{
/*
* In the case where there is just one range in the list, the merged
* address range is equal to that range.
*/
Addr start = 0x0000;
Addr end = 0xFFFF;
std::vector<Addr> masks;
masks.push_back((1 << 4) | (1 << 2));
uint8_t intlv_match = 0;
AddrRange r(start, end, masks, intlv_match);
AddrRangeList to_merge;
to_merge.push_back(r);
AddrRange output(to_merge);
EXPECT_EQ(r, output);
}
/*
* The following tests verify the soundness of the "legacy constructor",
* AddrRange(Addr, Addr, uint8_t, uint8_t, uint8_t, uint8_t).
*
* The address is assumed to contain two ranges; the interleaving bits, and
* the xor bits. The first two arguments of this constructor specify the
* start and end addresses. The third argument specifies the MSB of the
* interleaving bits. The fourth argument specifies the MSB of the xor bits.
* The firth argument specifies the size (in bits) of the xor and interleaving
* bits. These cannot overlap. The sixth argument specifies the value the
* XORing of the xor and interleaving bits should equal to be considered in
* range.
*
* This constructor does a lot of complex translation to migrate this
* constructor to the masks/intlv_match format.
*/
TEST(AddrRangeTest, LegacyConstructorNoInterleaving)
{
/*
* This constructor should create a range with no interleaving.
*/
AddrRange range(0x0000, 0xFFFF, 0, 0, 0 ,0);
AddrRange expected(0x0000, 0xFFFF);
EXPECT_EQ(expected, range);
}
TEST(AddrRangeTest, LegacyConstructorOneBitMask)
{
/*
* In this test, the LSB of the address determines whether an address is
* in range. If even, it's in range, if not, it's out of range. the XOR
* bit range is not used.
*/
AddrRange range(0x00000000, 0xFFFFFFFF, 0, 0, 1, 0);
std::vector<Addr> masks;
masks.push_back(1);
AddrRange expected(0x00000000, 0xFFFFFFFF, masks, 0);
EXPECT_TRUE(expected == range);
}
TEST(AddrRangeTest, LegacyConstructorTwoBitMask)
{
/*
* In this test, the two LSBs of the address determines whether an address
* is in range. If the two are set, the address is in range. The XOR bit
* range is not used.
*/
AddrRange range(0x00000000, 0xFFFFFFFF, 1, 0, 2, 3);
std::vector<Addr> masks;
masks.push_back(1);
masks.push_back((1 << 1));
AddrRange expected(0x00000000, 0xFFFFFFFF, masks, 3);
EXPECT_TRUE(expected == range);
}
TEST(AddrRangeTest, LegacyConstructorTwoBitMaskWithXOR)
{
/*
* In this test, the two LSBs of the address determine wether an address
* is in range. They are XORed to the 10th and 11th bits in the address.
* If XORed value is equal to 3, then the address is in range.
*/
AddrRange range(0x00000000, 0xFFFFFFFF, 1, 11, 2, 3);
/*
* The easiest way to ensure this range is correct is to iterate throguh
* the address range and ensure the correct set of addresses are contained
* within the range.
*
* We start with the xor_mask: a mask to select the 10th and 11th bits.
*/
Addr xor_mask = (1 << 11) | (1 << 10);
for (Addr i = 0; i < 0x0000FFFF; i++) {
// Get xor bits.
Addr xor_value = (xor_mask & i) >> 10;
/* If the XOR of xor_bits and the intlv bits (the 0th and 1st bits) is
* equal to intlv_match (3, i.e., the 0th and 1st bit is set),then the
* address is within range.
*/
if (((xor_value ^ i) & 3) == 3) {
EXPECT_TRUE(range.contains(i));
} else {
EXPECT_FALSE(range.contains(i));
}
}
}
/*
* addr_range.hh contains some convenience constructors. The following tests
* verify they construct AddrRange correctly.
*/
TEST(AddrRangeTest, RangeExConstruction)
{
AddrRange r = RangeEx(0x6, 0xE);
EXPECT_EQ(0x6, r.start());
EXPECT_EQ(0xE, r.end());
}
TEST(AddrRangeTest, RangeInConstruction)
{
AddrRange r = RangeIn(0x6, 0xE);
EXPECT_EQ(0x6, r.start());
EXPECT_EQ(0xF, r.end());
}
TEST(AddrRangeTest, RangeSizeConstruction){
AddrRange r = RangeSize(0x5, 5);
EXPECT_EQ(0x5, r.start());
EXPECT_EQ(0xA, r.end());
}
/*
* The exclude list is excluding the entire range: return an empty
* list of ranges
*
* |---------------------|
* | range |
* |---------------------|
*
* |------------------------------|
* | exclude_range |
* |------------------------------|
*/
TEST(AddrRangeTest, ExcludeAll)
{
const AddrRangeList exclude_ranges{
AddrRange(0x0, 0x200)
};
AddrRange r(0x00, 0x100);
auto ranges = r.exclude(exclude_ranges);
EXPECT_TRUE(ranges.empty());
}
/*
* The exclude list is excluding the entire range: return an empty
* list of ranges. The exclude_range = range
*
* |---------------------|
* | range |
* |---------------------|
*
* |---------------------|
* | exclude_range |
* |---------------------|
*/
TEST(AddrRangeTest, ExcludeAllEqual)
{
const AddrRangeList exclude_ranges{
AddrRange(0x0, 0x100)
};
AddrRange r(0x00, 0x100);
auto ranges = r.exclude(exclude_ranges);
EXPECT_TRUE(ranges.empty());
}
/*
* The exclude list is made of multiple adjacent ranges covering the entire
* interval: return an empty list of ranges.
*
* |---------------------------------------------------------------|
* | range |
* |---------------------------------------------------------------|
*
* |--------------------------|---------------|--------------------------|
* | exclude_range | exclude_range | exclude_range |
* |--------------------------|---------------|--------------------------|
*/
TEST(AddrRangeTest, ExcludeAllMultiple)
{
const AddrRangeList exclude_ranges{
AddrRange(0x0, 0x30),
AddrRange(0x30, 0x40),
AddrRange(0x40, 0x120)
};
AddrRange r(0x00, 0x100);
auto ranges = r.exclude(exclude_ranges);
EXPECT_TRUE(ranges.empty());
}
/*
* ExcludeAllOverlapping:
* The exclude list is made of multiple overlapping ranges covering the entire
* interval: return an empty list of ranges.
*
* |-----------------------------------|
* | range |
* |-----------------------------------|
*
* |-----------------------------|
* | exclude_range |
* |-----------------------------|
* |-----------------------------|
* | exclude_range |
* |-----------------------------|
*/
TEST(AddrRangeTest, ExcludeAllOverlapping)
{
const AddrRangeList exclude_ranges{
AddrRange(0x0, 0x150),
AddrRange(0x140, 0x220)
};
AddrRange r(0x100, 0x200);
auto ranges = r.exclude(exclude_ranges);
EXPECT_TRUE(ranges.empty());
}
/*
* The exclude list is empty:
* the return list contains the unmodified range
*
* |---------------------|
* | range |
* |---------------------|
*
*/
TEST(AddrRangeTest, ExcludeEmpty)
{
const AddrRangeList exclude_ranges;
AddrRange r(0x00, 0x100);
auto ranges = r.exclude(exclude_ranges);
EXPECT_EQ(ranges.size(), 1);
EXPECT_EQ(ranges.front(), r);
}
/*
* Ranges do not overlap:
* the return list contains the unmodified range
*
* |---------------------|
* | range |
* |---------------------|
*
* |------------------------------|
* | exclude_range |
* |------------------------------|
*/
TEST(AddrRangeTest, NoExclusion)
{
const AddrRangeList exclude_ranges{
AddrRange(0x100, 0x200)
};
AddrRange r(0x00, 0x100);
auto ranges = r.exclude(exclude_ranges);
EXPECT_EQ(ranges.size(), 1);
EXPECT_EQ(ranges.front(), r);
}
/*
* DoubleExclusion:
* The exclusion should return two ranges:
* AddrRange(0x130, 0x140)
* AddrRange(0x170, 0x200)
*
* |-----------------------------------|
* | range |
* |-----------------------------------|
*
* |-----------------| |-----------------|
* | exclude_range | | exclude_range |
* |-----------------| |-----------------|
*/
TEST(AddrRangeTest, DoubleExclusion)
{
const AddrRangeList exclude_ranges{
AddrRange(0x000, 0x130),
AddrRange(0x140, 0x170),
};
const AddrRange expected_range1(0x130, 0x140);
const AddrRange expected_range2(0x170, 0x200);
AddrRange r(0x100, 0x200);
auto ranges = r.exclude(exclude_ranges);
EXPECT_EQ(ranges.size(), 2);
EXPECT_THAT(ranges, ElementsAre(expected_range1, expected_range2));
}
/*
* MultipleExclusion:
* The exclusion should return two ranges:
* AddrRange(0x130, 0x140)
* AddrRange(0x170, 0x180)
*
* |-----------------------------------|
* | range |
* |-----------------------------------|
*
* |-----------------| |-----------------| |-----------------|
* | exclude_range | | exclude_range | | exclude_range |
* |-----------------| |-----------------| |-----------------|
*/
TEST(AddrRangeTest, MultipleExclusion)
{
const AddrRangeList exclude_ranges{
AddrRange(0x000, 0x130),
AddrRange(0x140, 0x170),
AddrRange(0x180, 0x210)
};
const AddrRange expected_range1(0x130, 0x140);
const AddrRange expected_range2(0x170, 0x180);
AddrRange r(0x100, 0x200);
auto ranges = r.exclude(exclude_ranges);
EXPECT_EQ(ranges.size(), 2);
EXPECT_THAT(ranges, ElementsAre(expected_range1, expected_range2));
}
/*
* MultipleExclusionOverlapping:
* The exclusion should return one range:
* AddrRange(0x130, 0x140)
*
* |-----------------------------------|
* | range |
* |-----------------------------------|
*
* |-----------------| |-----------------|
* | exclude_range | | exclude_range |
* |-----------------| |-----------------|
* |-----------------|
* | exclude_range |
* |-----------------|
*/
TEST(AddrRangeTest, MultipleExclusionOverlapping)
{
const AddrRangeList exclude_ranges{
AddrRange(0x000, 0x130),
AddrRange(0x140, 0x170),
AddrRange(0x150, 0x210)
};
const AddrRange expected_range1(0x130, 0x140);
AddrRange r(0x100, 0x200);
auto ranges = r.exclude(exclude_ranges);
EXPECT_EQ(ranges.size(), 1);
EXPECT_THAT(ranges, ElementsAre(expected_range1));
}
/*
* ExclusionOverlapping:
* The exclusion should return two range:
* AddrRange(0x100, 0x120)
* AddrRange(0x180, 0x200)
*
* |-----------------------------------|
* | range |
* |-----------------------------------|
*
* |--------------------|
* | exclude_range |
* |--------------------|
*
* |---------------|
* | exclude_range |
* |---------------|
*/
TEST(AddrRangeTest, ExclusionOverlapping)
{
const AddrRangeList exclude_ranges{
AddrRange(0x120, 0x180),
AddrRange(0x130, 0x170)
};
const AddrRange expected_range1(0x100, 0x120);
const AddrRange expected_range2(0x180, 0x200);
AddrRange r(0x100, 0x200);
auto ranges = r.exclude(exclude_ranges);
EXPECT_EQ(ranges.size(), 2);
EXPECT_THAT(ranges, ElementsAre(expected_range1, expected_range2));
}
/*
* MultipleExclusionUnsorted:
* The exclusion should return two ranges:
* AddrRange(0x130, 0x140)
* AddrRange(0x170, 0x180)
* Same as MultipleExclusion, but the exclude list is provided
* in unsorted order
*
* |-----------------------------------|
* | range |
* |-----------------------------------|
*
* |-----------------| |-----------------| |-----------------|
* | exclude_range | | exclude_range | | exclude_range |
* |-----------------| |-----------------| |-----------------|
*/
TEST(AddrRangeTest, MultipleExclusionUnsorted)
{
const AddrRangeList exclude_ranges{
AddrRange(0x180, 0x210),
AddrRange(0x000, 0x130),
AddrRange(0x140, 0x170)
};
const AddrRange expected_range1(0x130, 0x140);
const AddrRange expected_range2(0x170, 0x180);
AddrRange r(0x100, 0x200);
auto ranges = r.exclude(exclude_ranges);
EXPECT_EQ(ranges.size(), 2);
EXPECT_THAT(ranges, ElementsAre(expected_range1, expected_range2));
}
TEST(AddrRangeTest, ExclusionOfSingleRange)
{
const AddrRange expected_range1(0x100, 0x140);
const AddrRange expected_range2(0x1c0, 0x200);
AddrRange r(0x100, 0x200);
auto ranges = r.exclude(AddrRange(0x140, 0x1c0));
EXPECT_EQ(ranges.size(), 2);
EXPECT_THAT(ranges, ElementsAre(expected_range1, expected_range2));
}
TEST(AddrRangeTest, ExclusionOfRangeFromRangeList)
{
AddrRangeList base({AddrRange(0x100, 0x200), AddrRange(0x300, 0x400)});
const AddrRange expected_range1(0x100, 0x180);
const AddrRange expected_range2(0x380, 0x400);
auto ranges = exclude(base, AddrRange(0x180, 0x380));
EXPECT_EQ(ranges.size(), 2);
EXPECT_THAT(ranges, ElementsAre(expected_range1, expected_range2));
}
TEST(AddrRangeTest, ExclusionOfRangeListFromRangeList)
{
AddrRangeList base({AddrRange(0x100, 0x200), AddrRange(0x300, 0x400)});
const AddrRange expected_range1(0x100, 0x140);
const AddrRange expected_range2(0x180, 0x200);
const AddrRange expected_range3(0x300, 0x340);
const AddrRange expected_range4(0x380, 0x400);
const AddrRangeList to_exclude({
AddrRange(0x140, 0x180), AddrRange(0x340, 0x380)});
auto ranges = exclude(base, to_exclude);
EXPECT_EQ(ranges.size(), 4);
EXPECT_THAT(ranges, ElementsAre(
expected_range1, expected_range2,
expected_range3, expected_range4));
}
TEST(AddrRangeTest, SubtractionOperatorRange)
{
const AddrRange expected_range1(0x100, 0x140);
const AddrRange expected_range2(0x1c0, 0x200);
AddrRange r(0x100, 0x200);
auto ranges = r - AddrRange(0x140, 0x1c0);
EXPECT_EQ(ranges.size(), 2);
EXPECT_THAT(ranges, ElementsAre(expected_range1, expected_range2));
}
TEST(AddrRangeTest, SubtractionOperatorRangeList)
{
const AddrRange expected_range1(0x100, 0x140);
const AddrRange expected_range2(0x160, 0x180);
const AddrRange expected_range3(0x1a0, 0x200);
AddrRange r(0x100, 0x200);
auto ranges = r - AddrRangeList(
{AddrRange(0x140, 0x160), AddrRange(0x180, 0x1a0)});
EXPECT_EQ(ranges.size(), 3);
EXPECT_THAT(ranges, ElementsAre(
expected_range1, expected_range2, expected_range3));
}
TEST(AddrRangeTest, SubtractionOfRangeFromRangeList)
{
AddrRangeList base({AddrRange(0x100, 0x200), AddrRange(0x300, 0x400)});
const AddrRange expected_range1(0x100, 0x180);
const AddrRange expected_range2(0x380, 0x400);
auto ranges = base - AddrRange(0x180, 0x380);
EXPECT_EQ(ranges.size(), 2);
EXPECT_THAT(ranges, ElementsAre(expected_range1, expected_range2));
}
TEST(AddrRangeTest, SubtractionOfRangeListFromRangeList)
{
AddrRangeList base({AddrRange(0x100, 0x200), AddrRange(0x300, 0x400)});
const AddrRange expected_range1(0x100, 0x140);
const AddrRange expected_range2(0x180, 0x200);
const AddrRange expected_range3(0x300, 0x340);
const AddrRange expected_range4(0x380, 0x400);
const AddrRangeList to_exclude({
AddrRange(0x140, 0x180), AddrRange(0x340, 0x380)});
auto ranges = base - to_exclude;
EXPECT_EQ(ranges.size(), 4);
EXPECT_THAT(ranges, ElementsAre(
expected_range1, expected_range2,
expected_range3, expected_range4));
}
TEST(AddrRangeTest, SubtractionAssignmentOfRangeFromRangeList)
{
AddrRangeList base({AddrRange(0x100, 0x200), AddrRange(0x300, 0x400)});
const AddrRange expected_range1(0x100, 0x180);
const AddrRange expected_range2(0x380, 0x400);
base -= AddrRange(0x180, 0x380);
EXPECT_EQ(base.size(), 2);
EXPECT_THAT(base, ElementsAre(expected_range1, expected_range2));
}
TEST(AddrRangeTest, SubtractionAssignmentOfRangeListFromRangeList)
{
AddrRangeList base({AddrRange(0x100, 0x200), AddrRange(0x300, 0x400)});
const AddrRange expected_range1(0x100, 0x140);
const AddrRange expected_range2(0x180, 0x200);
const AddrRange expected_range3(0x300, 0x340);
const AddrRange expected_range4(0x380, 0x400);
const AddrRangeList to_exclude({
AddrRange(0x140, 0x180), AddrRange(0x340, 0x380)});
base -= to_exclude;
EXPECT_EQ(base.size(), 4);
EXPECT_THAT(base, ElementsAre(
expected_range1, expected_range2,
expected_range3, expected_range4));
}
/*
* InterleavingRanges:
* The exclude method does not support interleaving ranges
*/
TEST(AddrRangeDeathTest, ExcludeInterleavingRanges)
{
/* An `assert(!interleaved());` exists at the top of the `exclude(...)`
* method. This means EXPECT_DEATH will only function when DEBUG is enabled
* (as when compiled to `.opt`). When disabled (as when compiled to `.fast`),
* `r.exclude` fails more catastrophically via a `panic` which GTest cannot
* handle correctly. We therefore include a `#ifdef NDEBUG` guard so this
* test is skipped when DEBUG is disabled.
*/
#ifdef NDEBUG
GTEST_SKIP() << "Skipping as assetions are stripped from fast builds.";
#endif
const AddrRangeList exclude_ranges{
AddrRange(0x180, 0x210),
};
AddrRange r(0x100, 0x200, {1}, 0);
EXPECT_TRUE(r.interleaved());
EXPECT_DEATH(r.exclude(exclude_ranges), "");
}