base: Add addIntlvBits to AddrRange
authorAndreas Sandberg <andreas.sandberg@arm.com>
Mon, 7 Oct 2019 15:11:48 +0000 (16:11 +0100)
committerAndreas Sandberg <andreas.sandberg@arm.com>
Wed, 16 Oct 2019 16:11:08 +0000 (16:11 +0000)
This method performs the opposite operation of removeIntlvBits and can
be used to transform a channel-local address to a global PA.

Change-Id: I2fab587d7c094597e52422305775ac7f31efba34
Signed-off-by: Andreas Sandberg <andreas.sandberg@arm.com>
Reviewed-on: https://gem5-review.googlesource.com/c/public/gem5/+/21599
Reviewed-by: Nikos Nikoleris <nikos.nikoleris@arm.com>
Reviewed-by: Daniel Carvalho <odanrc@yahoo.com.br>
Tested-by: kokoro <noreply+kokoro@google.com>
src/base/addr_range.hh
src/base/addr_range.test.cc

index cda6ccfb2011625da7312ee6b6b00aa40d9ed7e8..84a3d4de50fc55abfb871baa129b64794435c0e4 100644 (file)
@@ -470,6 +470,44 @@ class AddrRange
         return a;
     }
 
+    /**
+     * This method adds the interleaving bits removed by
+     * removeIntlvBits.
+     */
+    inline Addr addIntlvBits(Addr a) const
+    {
+        // Get the LSB set from each mask
+        int masks_lsb[masks.size()];
+        for (int i = 0; i < masks.size(); i++) {
+            masks_lsb[i] = ctz64(masks[i]);
+        }
+
+        // Add bits one-by-one from the LSB side.
+        std::sort(masks_lsb, masks_lsb + masks.size());
+        for (int i = 0; i < masks.size(); i++) {
+            const int intlv_bit = masks_lsb[i];
+            if (intlv_bit > 0) {
+                // on every iteration we add one bit from the input
+                // address, and therefore the lowest invtl_bit has
+                // also shifted to the left by i positions.
+                a = insertBits(a << 1, intlv_bit + i - 1, 0, a);
+            } else {
+                a <<= 1;
+            }
+        }
+
+        for (int i = 0; i < masks.size(); i++) {
+            const int lsb = ctz64(masks[i]);
+            const Addr intlv_bit = bits(intlvMatch, i);
+            // Calculate the mask ignoring the LSB
+            const Addr masked = a & masks[i] & ~(1 << lsb);
+            // Set the LSB of the mask to whatever satisfies the selector bit
+            a = insertBits(a, lsb, intlv_bit ^ popCount(masked));
+        }
+
+        return a;
+    }
+
     /**
      * Determine the offset of an address within the range.
      *
index 54eb1984c08b8b2aa8372818957dbb2f21729086..93afbb0e78d0617f7543e4b028d184cf75af1cf6 100644 (file)
@@ -121,6 +121,16 @@ class AddrRangeBase : public testing::Test {
         }
     }
 
+    void testAddRemoveIntlvBits()
+    {
+        for (Addr addr = start; addr <= end; addr++) {
+            AddrRange &r = range[getIndex(addr)];
+            Addr ch_addr = r.removeIntlvBits(addr);
+            Addr pa = r.addIntlvBits(ch_addr);
+            ASSERT_EQ(addr, pa);
+        }
+    }
+
     static const Addr end = 0x1ffff;
     static const Addr start = 0x0;
     static const int intlvSize = 4;
@@ -162,6 +172,11 @@ TEST_F(AddrRangeCont, AddrRangeGetOffset)
     testGetOffset();
 }
 
+TEST_F(AddrRangeCont, AddrRangeAddRemoveIntlvBits)
+{
+    testAddRemoveIntlvBits();
+}
+
 
 class AddrRangeContLegacy : public AddrRangeCont {
   protected:
@@ -185,6 +200,10 @@ TEST_F(AddrRangeContLegacy, AddrRangeGetOffset)
     testGetOffset();
 }
 
+TEST_F(AddrRangeContLegacy, AddrRangeAddRemoveIntlvBits)
+{
+    testAddRemoveIntlvBits();
+}
 
 class AddrRangeArb : public AddrRangeBase {
   protected:
@@ -218,3 +237,8 @@ TEST_F(AddrRangeArb, AddrRangeGetOffset)
 {
     testGetOffset();
 }
+
+TEST_F(AddrRangeArb, AddrRangeAddRemoveIntlvBits)
+{
+    testAddRemoveIntlvBits();
+}