The methods `AddrRange::removeIntlvBits(Addr)` and `AddrRange::addIntlvBits(Addr)` should be the inverse of one another, but the latter did not insert the blanks for filling the removed bits in the correct positions. Since the masks are ordered increasingly by the position of the least significant bit of each mask, the lowest bit that has to be inserted at each iteration is always `intlv_bit`, not needing to be shifted to the left or right. The bits that need to be copied from the input address are `intlv_bit-1..0` at each iteration. The test `AddrRangeTest.AddRemoveInterleavBitsAcrossRange` has been updated have masks below bit 12, making the old code not pass the test. A new `AddrRangeTest.AddRemoveInterleavBitsAcrossContiguousRange` test has been added to include a case in which the previous code fails. The corrected code passes both tests. This function is not used anywhere other than the tests and the class `ChannelAddr`. However, it is needed to efficiently implement interleaved caches in the classic mode. Change-Id: I7d626a1f6ecf09a230fc18810d2dad2104d1a865 Signed-off-by: Isaac Sánchez Barrera <isaac.sanchez@bsc.es> Reviewed-on: https://gem5-review.googlesource.com/c/public/gem5/+/37175 Tested-by: kokoro <noreply+kokoro@google.com> Reviewed-by: Nikos Nikoleris <nikos.nikoleris@arm.com> Reviewed-by: Bobby R. Bruce <bbruce@ucdavis.edu> Maintainer: Nikos Nikoleris <nikos.nikoleris@arm.com> Maintainer: Bobby R. Bruce <bbruce@ucdavis.edu>
1091 lines
30 KiB
C++
1091 lines
30 KiB
C++
/*
|
|
* 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.
|
|
*/
|
|
|
|
#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 << 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(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());
|
|
}
|