blob: 890fb4f3a8b2ea42fcd99faa5ec3b1156a53296d [file] [log] [blame]
/*
* Copyright (c) 2019 The Regents of the University of California
* Copyright (c) 2018-2019 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.
*
* Authors: Nikos Nikoleris
* Bobby R. Bruce
*/
#include <gtest/gtest.h>
#include <cmath>
#include "base/addr_range.hh"
#include "base/bitfield.hh"
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 ULL(1).
*/
EXPECT_EQ(ULL(1), 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(ULL(1), 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(ULL(1), 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(ULL(2), 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(ULL(4), 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((ULL(1) << 63) | (ULL(1) << 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(ULL(4), 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 << 16);
masks.push_back(1 << 30);
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 << 16) | (1 << 30),
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(std::vector<AddrRange>) 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 vector.
*/
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);
std::vector<AddrRange> 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 vector, 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);
std::vector<AddrRange> 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());
}