/* * Copyright © 2017 Advanced Micro Devices, Inc. * All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sub license, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NON-INFRINGEMENT. IN NO EVENT SHALL THE COPYRIGHT HOLDERS, AUTHORS * AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE * USE OR OTHER DEALINGS IN THE SOFTWARE. * * The above copyright notice and this permission notice (including the * next paragraph) shall be included in all copies or substantial portions * of the Software. */ // Coordinate class implementation #include "addrcommon.h" #include "coord.h" Coordinate::Coordinate() { dim = 'x'; ord = 0; } Coordinate::Coordinate(INT_8 c, INT_32 n) { set(c, n); } VOID Coordinate::set(INT_8 c, INT_32 n) { dim = c; ord = static_cast(n); } UINT_32 Coordinate::ison(UINT_32 x, UINT_32 y, UINT_32 z, UINT_32 s, UINT_32 m) const { UINT_32 bit = static_cast(1ull << static_cast(ord)); UINT_32 out = 0; switch (dim) { case 'm': out = m & bit; break; case 's': out = s & bit; break; case 'x': out = x & bit; break; case 'y': out = y & bit; break; case 'z': out = z & bit; break; } return (out != 0) ? 1 : 0; } INT_8 Coordinate::getdim() { return dim; } INT_8 Coordinate::getord() { return ord; } BOOL_32 Coordinate::operator==(const Coordinate& b) { return (dim == b.dim) && (ord == b.ord); } BOOL_32 Coordinate::operator<(const Coordinate& b) { BOOL_32 ret; if (dim == b.dim) { ret = ord < b.ord; } else { if (dim == 's' || b.dim == 'm') { ret = TRUE; } else if (b.dim == 's' || dim == 'm') { ret = FALSE; } else if (ord == b.ord) { ret = dim < b.dim; } else { ret = ord < b.ord; } } return ret; } BOOL_32 Coordinate::operator>(const Coordinate& b) { BOOL_32 lt = *this < b; BOOL_32 eq = *this == b; return !lt && !eq; } BOOL_32 Coordinate::operator<=(const Coordinate& b) { return (*this < b) || (*this == b); } BOOL_32 Coordinate::operator>=(const Coordinate& b) { return !(*this < b); } BOOL_32 Coordinate::operator!=(const Coordinate& b) { return !(*this == b); } Coordinate& Coordinate::operator++(INT_32) { ord++; return *this; } // CoordTerm CoordTerm::CoordTerm() { num_coords = 0; } VOID CoordTerm::Clear() { num_coords = 0; } VOID CoordTerm::add(Coordinate& co) { // This function adds a coordinate INT_32o the list // It will prevent the same coordinate from appearing, // and will keep the list ordered from smallest to largest UINT_32 i; for (i = 0; i < num_coords; i++) { if (m_coord[i] == co) { break; } if (m_coord[i] > co) { for (UINT_32 j = num_coords; j > i; j--) { m_coord[j] = m_coord[j - 1]; } m_coord[i] = co; num_coords++; break; } } if (i == num_coords) { m_coord[num_coords] = co; num_coords++; } } VOID CoordTerm::add(CoordTerm& cl) { for (UINT_32 i = 0; i < cl.num_coords; i++) { add(cl.m_coord[i]); } } BOOL_32 CoordTerm::remove(Coordinate& co) { BOOL_32 remove = FALSE; for (UINT_32 i = 0; i < num_coords; i++) { if (m_coord[i] == co) { remove = TRUE; num_coords--; } if (remove) { m_coord[i] = m_coord[i + 1]; } } return remove; } BOOL_32 CoordTerm::Exists(Coordinate& co) { BOOL_32 exists = FALSE; for (UINT_32 i = 0; i < num_coords; i++) { if (m_coord[i] == co) { exists = TRUE; break; } } return exists; } VOID CoordTerm::copyto(CoordTerm& cl) { cl.num_coords = num_coords; for (UINT_32 i = 0; i < num_coords; i++) { cl.m_coord[i] = m_coord[i]; } } UINT_32 CoordTerm::getsize() { return num_coords; } UINT_32 CoordTerm::getxor(UINT_32 x, UINT_32 y, UINT_32 z, UINT_32 s, UINT_32 m) const { UINT_32 out = 0; for (UINT_32 i = 0; i < num_coords; i++) { out = out ^ m_coord[i].ison(x, y, z, s, m); } return out; } VOID CoordTerm::getsmallest(Coordinate& co) { co = m_coord[0]; } UINT_32 CoordTerm::Filter(INT_8 f, Coordinate& co, UINT_32 start, INT_8 axis) { for (UINT_32 i = start; i < num_coords;) { if (((f == '<' && m_coord[i] < co) || (f == '>' && m_coord[i] > co) || (f == '=' && m_coord[i] == co)) && (axis == '\0' || axis == m_coord[i].getdim())) { for (UINT_32 j = i; j < num_coords - 1; j++) { m_coord[j] = m_coord[j + 1]; } num_coords--; } else { i++; } } return num_coords; } Coordinate& CoordTerm::operator[](UINT_32 i) { return m_coord[i]; } BOOL_32 CoordTerm::operator==(const CoordTerm& b) { BOOL_32 ret = TRUE; if (num_coords != b.num_coords) { ret = FALSE; } else { for (UINT_32 i = 0; i < num_coords; i++) { // Note: the lists will always be in order, so we can compare the two lists at time if (m_coord[i] != b.m_coord[i]) { ret = FALSE; break; } } } return ret; } BOOL_32 CoordTerm::operator!=(const CoordTerm& b) { return !(*this == b); } BOOL_32 CoordTerm::exceedRange(UINT_32 xRange, UINT_32 yRange, UINT_32 zRange, UINT_32 sRange) { BOOL_32 exceed = FALSE; for (UINT_32 i = 0; (i < num_coords) && (exceed == FALSE); i++) { UINT_32 subject; switch (m_coord[i].getdim()) { case 'x': subject = xRange; break; case 'y': subject = yRange; break; case 'z': subject = zRange; break; case 's': subject = sRange; break; case 'm': subject = 0; break; default: // Invalid input! ADDR_ASSERT_ALWAYS(); subject = 0; break; } exceed = ((1u << m_coord[i].getord()) <= subject); } return exceed; } // coordeq CoordEq::CoordEq() { m_numBits = 0; } VOID CoordEq::remove(Coordinate& co) { for (UINT_32 i = 0; i < m_numBits; i++) { m_eq[i].remove(co); } } BOOL_32 CoordEq::Exists(Coordinate& co) { BOOL_32 exists = FALSE; for (UINT_32 i = 0; i < m_numBits; i++) { if (m_eq[i].Exists(co)) { exists = TRUE; } } return exists; } VOID CoordEq::resize(UINT_32 n) { if (n > m_numBits) { for (UINT_32 i = m_numBits; i < n; i++) { m_eq[i].Clear(); } } m_numBits = n; } UINT_32 CoordEq::getsize() { return m_numBits; } UINT_64 CoordEq::solve(UINT_32 x, UINT_32 y, UINT_32 z, UINT_32 s, UINT_32 m) const { UINT_64 out = 0; for (UINT_32 i = 0; i < m_numBits; i++) { if (m_eq[i].getxor(x, y, z, s, m) != 0) { out |= (1ULL << i); } } return out; } VOID CoordEq::solveAddr( UINT_64 addr, UINT_32 sliceInM, UINT_32& x, UINT_32& y, UINT_32& z, UINT_32& s, UINT_32& m) const { UINT_32 xBitsValid = 0; UINT_32 yBitsValid = 0; UINT_32 zBitsValid = 0; UINT_32 sBitsValid = 0; UINT_32 mBitsValid = 0; CoordEq temp = *this; x = y = z = s = m = 0; UINT_32 bitsLeft = 0; for (UINT_32 i = 0; i < temp.m_numBits; i++) { UINT_32 termSize = temp.m_eq[i].getsize(); if (termSize == 1) { INT_8 bit = (addr >> i) & 1; INT_8 dim = temp.m_eq[i][0].getdim(); INT_8 ord = temp.m_eq[i][0].getord(); ADDR_ASSERT((ord < 32) || (bit == 0)); switch (dim) { case 'x': xBitsValid |= (1 << ord); x |= (bit << ord); break; case 'y': yBitsValid |= (1 << ord); y |= (bit << ord); break; case 'z': zBitsValid |= (1 << ord); z |= (bit << ord); break; case 's': sBitsValid |= (1 << ord); s |= (bit << ord); break; case 'm': mBitsValid |= (1 << ord); m |= (bit << ord); break; default: break; } temp.m_eq[i].Clear(); } else if (termSize > 1) { bitsLeft++; } } if (bitsLeft > 0) { if (sliceInM != 0) { z = m / sliceInM; zBitsValid = 0xffffffff; } do { bitsLeft = 0; for (UINT_32 i = 0; i < temp.m_numBits; i++) { UINT_32 termSize = temp.m_eq[i].getsize(); if (termSize == 1) { INT_8 bit = (addr >> i) & 1; INT_8 dim = temp.m_eq[i][0].getdim(); INT_8 ord = temp.m_eq[i][0].getord(); ADDR_ASSERT((ord < 32) || (bit == 0)); switch (dim) { case 'x': xBitsValid |= (1 << ord); x |= (bit << ord); break; case 'y': yBitsValid |= (1 << ord); y |= (bit << ord); break; case 'z': zBitsValid |= (1 << ord); z |= (bit << ord); break; case 's': ADDR_ASSERT_ALWAYS(); break; case 'm': ADDR_ASSERT_ALWAYS(); break; default: break; } temp.m_eq[i].Clear(); } else if (termSize > 1) { CoordTerm tmpTerm = temp.m_eq[i]; for (UINT_32 j = 0; j < termSize; j++) { INT_8 dim = temp.m_eq[i][j].getdim(); INT_8 ord = temp.m_eq[i][j].getord(); switch (dim) { case 'x': if (xBitsValid & (1 << ord)) { UINT_32 v = (((x >> ord) & 1) << i); addr ^= static_cast(v); tmpTerm.remove(temp.m_eq[i][j]); } break; case 'y': if (yBitsValid & (1 << ord)) { UINT_32 v = (((y >> ord) & 1) << i); addr ^= static_cast(v); tmpTerm.remove(temp.m_eq[i][j]); } break; case 'z': if (zBitsValid & (1 << ord)) { UINT_32 v = (((z >> ord) & 1) << i); addr ^= static_cast(v); tmpTerm.remove(temp.m_eq[i][j]); } break; case 's': ADDR_ASSERT_ALWAYS(); break; case 'm': ADDR_ASSERT_ALWAYS(); break; default: break; } } temp.m_eq[i] = tmpTerm; bitsLeft++; } } } while (bitsLeft > 0); } } VOID CoordEq::copy(CoordEq& o, UINT_32 start, UINT_32 num) { o.m_numBits = (num == 0xFFFFFFFF) ? m_numBits : num; for (UINT_32 i = 0; i < o.m_numBits; i++) { m_eq[start + i].copyto(o.m_eq[i]); } } VOID CoordEq::reverse(UINT_32 start, UINT_32 num) { UINT_32 n = (num == 0xFFFFFFFF) ? m_numBits : num; for (UINT_32 i = 0; i < n / 2; i++) { CoordTerm temp; m_eq[start + i].copyto(temp); m_eq[start + n - 1 - i].copyto(m_eq[start + i]); temp.copyto(m_eq[start + n - 1 - i]); } } VOID CoordEq::xorin(CoordEq& x, UINT_32 start) { UINT_32 n = ((m_numBits - start) < x.m_numBits) ? (m_numBits - start) : x.m_numBits; for (UINT_32 i = 0; i < n; i++) { m_eq[start + i].add(x.m_eq[i]); } } UINT_32 CoordEq::Filter(INT_8 f, Coordinate& co, UINT_32 start, INT_8 axis) { for (UINT_32 i = start; i < m_numBits;) { UINT_32 m = m_eq[i].Filter(f, co, 0, axis); if (m == 0) { for (UINT_32 j = i; j < m_numBits - 1; j++) { m_eq[j] = m_eq[j + 1]; } m_numBits--; } else { i++; } } return m_numBits; } VOID CoordEq::shift(INT_32 amount, INT_32 start) { if (amount != 0) { INT_32 numBits = static_cast(m_numBits); amount = -amount; INT_32 inc = (amount < 0) ? -1 : 1; INT_32 i = (amount < 0) ? numBits - 1 : start; INT_32 end = (amount < 0) ? start - 1 : numBits; for (; (inc > 0) ? i < end : i > end; i += inc) { if ((i + amount < start) || (i + amount >= numBits)) { m_eq[i].Clear(); } else { m_eq[i + amount].copyto(m_eq[i]); } } } } CoordTerm& CoordEq::operator[](UINT_32 i) { return m_eq[i]; } VOID CoordEq::mort2d(Coordinate& c0, Coordinate& c1, UINT_32 start, UINT_32 end) { if (end == 0) { ADDR_ASSERT(m_numBits > 0); end = m_numBits - 1; } for (UINT_32 i = start; i <= end; i++) { UINT_32 select = (i - start) % 2; Coordinate& c = (select == 0) ? c0 : c1; m_eq[i].add(c); c++; } } VOID CoordEq::mort3d(Coordinate& c0, Coordinate& c1, Coordinate& c2, UINT_32 start, UINT_32 end) { if (end == 0) { ADDR_ASSERT(m_numBits > 0); end = m_numBits - 1; } for (UINT_32 i = start; i <= end; i++) { UINT_32 select = (i - start) % 3; Coordinate& c = (select == 0) ? c0 : ((select == 1) ? c1 : c2); m_eq[i].add(c); c++; } } BOOL_32 CoordEq::operator==(const CoordEq& b) { BOOL_32 ret = TRUE; if (m_numBits != b.m_numBits) { ret = FALSE; } else { for (UINT_32 i = 0; i < m_numBits; i++) { if (m_eq[i] != b.m_eq[i]) { ret = FALSE; break; } } } return ret; } BOOL_32 CoordEq::operator!=(const CoordEq& b) { return !(*this == b); }