xref: /aosp_15_r20/external/mesa3d/src/amd/addrlib/src/core/addrcommon.h (revision 6104692788411f58d303aa86923a9ff6ecaded22)
1 /*
2 ************************************************************************************************************************
3 *
4 *  Copyright (C) 2007-2022 Advanced Micro Devices, Inc.  All rights reserved.
5 *  SPDX-License-Identifier: MIT
6 *
7 ***********************************************************************************************************************/
8 
9 /**
10 ****************************************************************************************************
11 * @file  addrcommon.h
12 * @brief Contains the helper function and constants.
13 ****************************************************************************************************
14 */
15 
16 #ifndef __ADDR_COMMON_H__
17 #define __ADDR_COMMON_H__
18 
19 #include "addrinterface.h"
20 
21 
22 #if !defined(__APPLE__) || defined(HAVE_TSERVER)
23     #include <stdlib.h>
24     #include <string.h>
25 #endif
26 
27 #if defined(__GNUC__)
28     #include <signal.h>
29     #include <assert.h>
30 #endif
31 
32 #if defined(_WIN32)
33 #include <intrin.h>
34 #endif
35 
36 ////////////////////////////////////////////////////////////////////////////////////////////////////
37 // Platform specific debug break defines
38 ////////////////////////////////////////////////////////////////////////////////////////////////////
39 #if !defined(DEBUG)
40     #ifdef NDEBUG
41         #define DEBUG 0
42     #else
43         #define DEBUG 1
44     #endif
45 #endif
46 
47 #if DEBUG
48     #if defined(__GNUC__)
49         #define ADDR_DBG_BREAK()    { assert(false); }
50     #elif defined(__APPLE__)
51         #define ADDR_DBG_BREAK()    { IOPanic("");}
52     #else
53         #define ADDR_DBG_BREAK()    { __debugbreak(); }
54     #endif
55 #else
56     #define ADDR_DBG_BREAK()
57 #endif
58 ////////////////////////////////////////////////////////////////////////////////////////////////////
59 
60 ////////////////////////////////////////////////////////////////////////////////////////////////////
61 // Debug print macro
62 ////////////////////////////////////////////////////////////////////////////////////////////////////
63 #if DEBUG
64 
65 // Forward decl.
66 namespace Addr {
67 
68 /// @brief Debug print helper
69 /// This function sends messages to thread-local callbacks for printing. If no callback is present
70 /// it is sent to stderr.
71 ///
72 VOID DebugPrint( const CHAR* pDebugString, ...);
73 
74 /// This function sets thread-local callbacks (or NULL) for printing. It should be called when
75 /// entering addrlib and is implicitly called by GetLib().
76 VOID ApplyDebugPrinters(ADDR_DEBUGPRINT pfnDebugPrint, ADDR_CLIENT_HANDLE pClientHandle);
77 }
78 
79 /// @brief Printf-like macro for printing messages
80 #define ADDR_PRNT(msg, ...) Addr::DebugPrint(msg, ##__VA_ARGS__)
81 
82 /// @brief Resets thread-local debug state
83 /// @ingroup util
84 ///
85 /// This macro resets any thread-local state on where to print a message.
86 /// It should be called before returning from addrlib.
87 #define ADDR_RESET_DEBUG_PRINTERS() Addr::ApplyDebugPrinters(NULL, NULL)
88 
89 /// @brief Macro for reporting informational messages
90 /// @ingroup util
91 ///
92 /// This macro optionally prints an informational message to stdout.
93 /// The first parameter is a condition -- if it is true, nothing is done.
94 /// The second parameter is a message that may have printf-like args.
95 /// Any remaining parameters are used to format the message.
96 ///
97 #define ADDR_INFO(cond, msg, ...)         \
98 do { if (!(cond)) { Addr::DebugPrint(msg, ##__VA_ARGS__); } } while (0)
99 
100 
101 /// @brief Macro for reporting error warning messages
102 /// @ingroup util
103 ///
104 /// This macro optionally prints an error warning message to stdout,
105 /// followed by the file name and line number where the macro was called.
106 /// The first parameter is a condition -- if it is true, nothing is done.
107 /// The second parameter is a message that may have printf-like args.
108 /// Any remaining parameters are used to format the message.
109 ///
110 #define ADDR_WARN(cond, msg, ...)         \
111 do { if (!(cond))                         \
112   { Addr::DebugPrint(msg, ##__VA_ARGS__); \
113     Addr::DebugPrint("  WARNING in file %s, line %d\n", __FILE__, __LINE__); \
114 } } while (0)
115 
116 
117 /// @brief Macro for reporting fatal error conditions
118 /// @ingroup util
119 ///
120 /// This macro optionally stops execution of the current routine
121 /// after printing an error warning message to stdout,
122 /// followed by the file name and line number where the macro was called.
123 /// The first parameter is a condition -- if it is true, nothing is done.
124 /// The second parameter is a message that may have printf-like args.
125 /// Any remaining parameters are used to format the message.
126 ///
127 #define ADDR_EXIT(cond, msg, ...)                           \
128 do { if (!(cond))                                           \
129   { Addr::DebugPrint(msg, ##__VA_ARGS__); ADDR_DBG_BREAK(); \
130 } } while (0)
131 
132 #else // DEBUG
133 
134 #define ADDR_RESET_DEBUG_PRINTERS()
135 
136 #define ADDR_PRNT(msg, ...)
137 
138 #define ADDR_DBG_BREAK()
139 
140 #define ADDR_INFO(cond, msg, ...)
141 
142 #define ADDR_WARN(cond, msg, ...)
143 
144 #define ADDR_EXIT(cond, msg, ...)
145 
146 #endif // DEBUG
147 ////////////////////////////////////////////////////////////////////////////////////////////////////
148 
149 ////////////////////////////////////////////////////////////////////////////////////////////////////
150 // Debug assertions used in AddrLib
151 ////////////////////////////////////////////////////////////////////////////////////////////////////
152 #if defined(_WIN32) && (_MSC_VER >= 1400)
153     #define ADDR_ANALYSIS_ASSUME(expr) __analysis_assume(expr)
154 #else
155     #define ADDR_ANALYSIS_ASSUME(expr) do { (void)(expr); } while (0)
156 #endif
157 
158 #if DEBUG
159     #define ADDR_BREAK_WITH_MSG(msg)                                      \
160         do {                                                              \
161             Addr::DebugPrint(msg " in file %s:%d\n", __FILE__, __LINE__); \
162             ADDR_DBG_BREAK();                                             \
163         } while (0)
164 
165     #define ADDR_ASSERT(__e)                                    \
166     do {                                                        \
167         ADDR_ANALYSIS_ASSUME(__e);                              \
168         if ( !((__e) ? TRUE : FALSE)) {                         \
169             ADDR_BREAK_WITH_MSG("Assertion '" #__e "' failed"); \
170         }                                                       \
171     } while (0)
172 
173     #if ADDR_SILENCE_ASSERT_ALWAYS
174         #define ADDR_ASSERT_ALWAYS()
175     #else
176         #define ADDR_ASSERT_ALWAYS() ADDR_BREAK_WITH_MSG("Unconditional assert failed")
177     #endif
178 
179     #define ADDR_UNHANDLED_CASE() ADDR_BREAK_WITH_MSG("Unhandled case")
180     #define ADDR_NOT_IMPLEMENTED() ADDR_BREAK_WITH_MSG("Not implemented");
181 #else //DEBUG
182     #if defined( _WIN32 )
183         #define ADDR_ASSERT(__e) ADDR_ANALYSIS_ASSUME(__e)
184     #else
185         #define ADDR_ASSERT(__e)
186     #endif
187     #define ADDR_ASSERT_ALWAYS()
188     #define ADDR_UNHANDLED_CASE()
189     #define ADDR_NOT_IMPLEMENTED()
190 #endif //DEBUG
191 ////////////////////////////////////////////////////////////////////////////////////////////////////
192 
193 
194 #if defined(static_assert)
195 #define ADDR_C_ASSERT(__e) static_assert(__e, "")
196 #else
197    /* This version of STATIC_ASSERT() relies on VLAs.  If COND is
198     * false/zero, the array size will be -1 and we'll get a compile
199     * error
200     */
201 #  define ADDR_C_ASSERT(__e) do {         \
202       (void) sizeof(char [1 - 2*!(__e)]); \
203    } while (0)
204 #endif
205 
206 namespace Addr
207 {
208 
209 namespace V1
210 {
211 ////////////////////////////////////////////////////////////////////////////////////////////////////
212 // Common constants
213 ////////////////////////////////////////////////////////////////////////////////////////////////////
214 static const UINT_32 MicroTileWidth      = 8;       ///< Micro tile width, for 1D and 2D tiling
215 static const UINT_32 MicroTileHeight     = 8;       ///< Micro tile height, for 1D and 2D tiling
216 static const UINT_32 ThickTileThickness  = 4;       ///< Micro tile thickness, for THICK modes
217 static const UINT_32 XThickTileThickness = 8;       ///< Extra thick tiling thickness
218 static const UINT_32 PowerSaveTileBytes  = 64;      ///< Nuber of bytes per tile for power save 64
219 static const UINT_32 CmaskCacheBits      = 1024;    ///< Number of bits for CMASK cache
220 static const UINT_32 CmaskElemBits       = 4;       ///< Number of bits for CMASK element
221 static const UINT_32 HtileCacheBits      = 16384;   ///< Number of bits for HTILE cache 512*32
222 
223 static const UINT_32 MicroTilePixels     = MicroTileWidth * MicroTileHeight;
224 
225 static const INT_32 TileIndexInvalid        = TILEINDEX_INVALID;
226 static const INT_32 TileIndexLinearGeneral  = TILEINDEX_LINEAR_GENERAL;
227 static const INT_32 TileIndexNoMacroIndex   = -3;
228 
229 } // V1
230 
231 namespace V2
232 {
233 ////////////////////////////////////////////////////////////////////////////////////////////////////
234 // Common constants
235 ////////////////////////////////////////////////////////////////////////////////////////////////////
236 static const UINT_32 MaxSurfaceHeight = 16384;
237 } // V2
238 
239 namespace V3
240 {
241 ////////////////////////////////////////////////////////////////////////////////////////////////////
242 // Common constants
243 ////////////////////////////////////////////////////////////////////////////////////////////////////
244 static const UINT_32 MaxSurfaceHeight = 65536;
245 } // V3
246 
247 ////////////////////////////////////////////////////////////////////////////////////////////////////
248 // Common macros
249 ////////////////////////////////////////////////////////////////////////////////////////////////////
250 #define BITS_PER_BYTE 8
251 #define BITS_TO_BYTES(x) ( ((x) + (BITS_PER_BYTE-1)) / BITS_PER_BYTE )
252 #define BYTES_TO_BITS(x) ( (x) * BITS_PER_BYTE )
253 
254 /// Helper macros to select a single bit from an int (undefined later in section)
255 #define _BIT(v,b)      (((v) >> (b) ) & 1)
256 
257 /**
258 ****************************************************************************************************
259 * ChipFamily
260 *
261 *   @brief
262 *       Neutral enums that specifies chip family.
263 *
264 ****************************************************************************************************
265 */
266 enum ChipFamily
267 {
268     ADDR_CHIP_FAMILY_IVLD,    ///< Invalid family
269     ADDR_CHIP_FAMILY_R6XX,
270     ADDR_CHIP_FAMILY_R7XX,
271     ADDR_CHIP_FAMILY_R8XX,
272     ADDR_CHIP_FAMILY_NI,
273     ADDR_CHIP_FAMILY_SI,
274     ADDR_CHIP_FAMILY_CI,
275     ADDR_CHIP_FAMILY_VI,
276     ADDR_CHIP_FAMILY_AI,
277     ADDR_CHIP_FAMILY_NAVI,
278     ADDR_CHIP_FAMILY_UNKNOWN,
279 };
280 
281 /**
282 ****************************************************************************************************
283 * ConfigFlags
284 *
285 *   @brief
286 *       This structure is used to set configuration flags.
287 ****************************************************************************************************
288 */
289 union ConfigFlags
290 {
291     struct
292     {
293         /// These flags are set up internally thru AddrLib::Create() based on ADDR_CREATE_FLAGS
294         UINT_32 optimalBankSwap        : 1;    ///< New bank tiling for RV770 only
295         UINT_32 noCubeMipSlicesPad     : 1;    ///< Disables faces padding for cubemap mipmaps
296         UINT_32 fillSizeFields         : 1;    ///< If clients fill size fields in all input and
297                                                ///  output structure
298         UINT_32 ignoreTileInfo         : 1;    ///< Don't use tile info structure
299         UINT_32 useTileIndex           : 1;    ///< Make tileIndex field in input valid
300         UINT_32 useCombinedSwizzle     : 1;    ///< Use combined swizzle
301         UINT_32 checkLast2DLevel       : 1;    ///< Check the last 2D mip sub level
302         UINT_32 useHtileSliceAlign     : 1;    ///< Do htile single slice alignment
303         UINT_32 allowLargeThickTile    : 1;    ///< Allow 64*thickness*bytesPerPixel > rowSize
304         UINT_32 disableLinearOpt       : 1;    ///< Disallow tile modes to be optimized to linear
305         UINT_32 use32bppFor422Fmt      : 1;    ///< View 422 formats as 32 bits per pixel element
306         UINT_32 forceDccAndTcCompat    : 1;    ///< Force enable DCC and TC compatibility
307         UINT_32 nonPower2MemConfig     : 1;    ///< Video memory bit width is not power of 2
308         UINT_32 enableAltTiling        : 1;    ///< Enable alt tile mode
309         UINT_32 reserved               : 18;   ///< Reserved bits for future use
310     };
311 
312     UINT_32 value;
313 };
314 
315 ////////////////////////////////////////////////////////////////////////////////////////////////////
316 // Misc helper functions
317 ////////////////////////////////////////////////////////////////////////////////////////////////////
318 
319 /**
320 ****************************************************************************************************
321 *   AddrXorReduce
322 *
323 *   @brief
324 *       Xor the right-side numberOfBits bits of x.
325 ****************************************************************************************************
326 */
XorReduce(UINT_32 x,UINT_32 numberOfBits)327 static inline UINT_32 XorReduce(
328     UINT_32 x,
329     UINT_32 numberOfBits)
330 {
331     UINT_32 i;
332     UINT_32 result = x & 1;
333 
334     for (i=1; i<numberOfBits; i++)
335     {
336         result ^= ((x>>i) & 1);
337     }
338 
339     return result;
340 }
341 
342 /**
343 ****************************************************************************************************
344 *   Unset least bit
345 *
346 *   @brief
347 *       Returns a copy of the value with the least-significant '1' bit unset
348 ****************************************************************************************************
349 */
UnsetLeastBit(UINT_32 val)350 static inline UINT_32 UnsetLeastBit(
351     UINT_32 val)
352 {
353     return val & (val - 1);
354 }
355 
356 /**
357 ****************************************************************************************************
358 *   BitScanForward
359 *
360 *   @brief
361 *       Returns the index-position of the least-significant '1' bit. Must not be 0.
362 ****************************************************************************************************
363 */
BitScanForward(UINT_32 mask)364 static inline UINT_32 BitScanForward(
365     UINT_32 mask) ///< [in] Bitmask to scan
366 {
367     ADDR_ASSERT(mask > 0);
368     unsigned long out = 0;
369 #if (defined(_WIN64) && defined(_M_X64)) || (defined(_WIN32) && defined(_M_IX64))
370     out = ::_tzcnt_u32(mask);
371 #elif (defined(_WIN32) || defined(_WIN64))
372     ::_BitScanForward(&out, mask);
373 #elif defined(__GNUC__)
374     out = __builtin_ctz(mask);
375 #else
376     while ((mask & 1) == 0)
377     {
378         mask >>= 1;
379         out++;
380     }
381 #endif
382     return out;
383 }
384 
385 /**
386 ****************************************************************************************************
387 *   IsPow2
388 *
389 *   @brief
390 *       Check if the size (UINT_32) is pow 2
391 ****************************************************************************************************
392 */
IsPow2(UINT_32 dim)393 static inline UINT_32 IsPow2(
394     UINT_32 dim)        ///< [in] dimension of miplevel
395 {
396     ADDR_ASSERT(dim > 0);
397     return !(dim & (dim - 1));
398 }
399 
400 /**
401 ****************************************************************************************************
402 *   IsPow2
403 *
404 *   @brief
405 *       Check if the size (UINT_64) is pow 2
406 ****************************************************************************************************
407 */
IsPow2(UINT_64 dim)408 static inline UINT_64 IsPow2(
409     UINT_64 dim)        ///< [in] dimension of miplevel
410 {
411     ADDR_ASSERT(dim > 0);
412     return !(dim & (dim - 1));
413 }
414 
415 /**
416 ****************************************************************************************************
417 *   ByteAlign
418 *
419 *   @brief
420 *       Align UINT_32 "x" to "align" alignment, "align" should be power of 2
421 ****************************************************************************************************
422 */
PowTwoAlign(UINT_32 x,UINT_32 align)423 static inline UINT_32 PowTwoAlign(
424     UINT_32 x,
425     UINT_32 align)
426 {
427     //
428     // Assert that x is a power of two.
429     //
430     ADDR_ASSERT(IsPow2(align));
431     return (x + (align - 1)) & (~(align - 1));
432 }
433 
434 /**
435 ****************************************************************************************************
436 *   ByteAlign
437 *
438 *   @brief
439 *       Align UINT_64 "x" to "align" alignment, "align" should be power of 2
440 ****************************************************************************************************
441 */
PowTwoAlign(UINT_64 x,UINT_64 align)442 static inline UINT_64 PowTwoAlign(
443     UINT_64 x,
444     UINT_64 align)
445 {
446     //
447     // Assert that x is a power of two.
448     //
449     ADDR_ASSERT(IsPow2(align));
450     return (x + (align - 1)) & (~(align - 1));
451 }
452 
453 /**
454 ****************************************************************************************************
455 *   Min
456 *
457 *   @brief
458 *       Get the min value between two unsigned values
459 ****************************************************************************************************
460 */
Min(UINT_32 value1,UINT_32 value2)461 static inline UINT_32 Min(
462     UINT_32 value1,
463     UINT_32 value2)
464 {
465     return ((value1 < (value2)) ? (value1) : value2);
466 }
467 
468 /**
469 ****************************************************************************************************
470 *   Min
471 *
472 *   @brief
473 *       Get the min value between two signed values
474 ****************************************************************************************************
475 */
Min(INT_32 value1,INT_32 value2)476 static inline INT_32 Min(
477     INT_32 value1,
478     INT_32 value2)
479 {
480     return ((value1 < (value2)) ? (value1) : value2);
481 }
482 
483 /**
484 ****************************************************************************************************
485 *   Max
486 *
487 *   @brief
488 *       Get the max value between two unsigned values
489 ****************************************************************************************************
490 */
Max(UINT_32 value1,UINT_32 value2)491 static inline UINT_32 Max(
492     UINT_32 value1,
493     UINT_32 value2)
494 {
495     return ((value1 > (value2)) ? (value1) : value2);
496 }
497 
498 /**
499 ****************************************************************************************************
500 *   Max
501 *
502 *   @brief
503 *       Get the max value between two signed values
504 ****************************************************************************************************
505 */
Max(INT_32 value1,INT_32 value2)506 static inline INT_32 Max(
507     INT_32 value1,
508     INT_32 value2)
509 {
510     return ((value1 > (value2)) ? (value1) : value2);
511 }
512 
513 /**
514 ****************************************************************************************************
515 *   RoundUpQuotient
516 *
517 *   @brief
518 *       Divides two numbers, rounding up any remainder.
519 ****************************************************************************************************
520 */
RoundUpQuotient(UINT_32 numerator,UINT_32 denominator)521 static inline UINT_32 RoundUpQuotient(
522     UINT_32 numerator,
523     UINT_32 denominator)
524 {
525     ADDR_ASSERT(denominator > 0);
526     return ((numerator + (denominator - 1)) / denominator);
527 }
528 
529 /**
530 ****************************************************************************************************
531 *   RoundUpQuotient
532 *
533 *   @brief
534 *       Divides two numbers, rounding up any remainder.
535 ****************************************************************************************************
536 */
RoundUpQuotient(UINT_64 numerator,UINT_64 denominator)537 static inline UINT_64 RoundUpQuotient(
538     UINT_64 numerator,
539     UINT_64 denominator)
540 {
541     ADDR_ASSERT(denominator > 0);
542     return ((numerator + (denominator - 1)) / denominator);
543 }
544 
545 /**
546 ****************************************************************************************************
547 *   NextPow2
548 *
549 *   @brief
550 *       Compute the mipmap's next level dim size
551 ****************************************************************************************************
552 */
NextPow2(UINT_32 dim)553 static inline UINT_32 NextPow2(
554     UINT_32 dim)        ///< [in] dimension of miplevel
555 {
556     UINT_32 newDim = 1;
557 
558     if (dim > 0x7fffffff)
559     {
560         ADDR_ASSERT_ALWAYS();
561         newDim = 0x80000000;
562     }
563     else
564     {
565         while (newDim < dim)
566         {
567             newDim <<= 1;
568         }
569     }
570 
571     return newDim;
572 }
573 
574 /**
575 ****************************************************************************************************
576 *   Log2NonPow2
577 *
578 *   @brief
579 *       Compute log of base 2 no matter the target is power of 2 or not
580 ****************************************************************************************************
581 */
Log2NonPow2(UINT_32 x)582 static inline UINT_32 Log2NonPow2(
583     UINT_32 x)      ///< [in] the value should calculate log based 2
584 {
585     UINT_32 y;
586 
587     y = 0;
588     while (x > 1)
589     {
590         x >>= 1;
591         y++;
592     }
593 
594     return y;
595 }
596 
597 /**
598 ****************************************************************************************************
599 *   Log2
600 *
601 *   @brief
602 *       Compute log of base 2
603 ****************************************************************************************************
604 */
Log2(UINT_32 x)605 static inline UINT_32 Log2(
606     UINT_32 x)      ///< [in] the value should calculate log based 2
607 {
608     // Assert that x is a power of two.
609     ADDR_ASSERT(IsPow2(x));
610 
611     return Log2NonPow2(x);
612 }
613 
614 /**
615 ****************************************************************************************************
616 *   QLog2
617 *
618 *   @brief
619 *       Compute log of base 2 quickly (<= 16)
620 ****************************************************************************************************
621 */
QLog2(UINT_32 x)622 static inline UINT_32 QLog2(
623     UINT_32 x)      ///< [in] the value should calculate log based 2
624 {
625     ADDR_ASSERT(x <= 16);
626 
627     UINT_32 y = 0;
628 
629     switch (x)
630     {
631         case 1:
632             y = 0;
633             break;
634         case 2:
635             y = 1;
636             break;
637         case 4:
638             y = 2;
639             break;
640         case 8:
641             y = 3;
642             break;
643         case 16:
644             y = 4;
645             break;
646         default:
647             ADDR_ASSERT_ALWAYS();
648     }
649 
650     return y;
651 }
652 
653 /**
654 ****************************************************************************************************
655 *   SafeAssign
656 *
657 *   @brief
658 *       NULL pointer safe assignment
659 ****************************************************************************************************
660 */
SafeAssign(UINT_32 * pLVal,UINT_32 rVal)661 static inline VOID SafeAssign(
662     UINT_32*    pLVal,  ///< [in] Pointer to left val
663     UINT_32     rVal)   ///< [in] Right value
664 {
665     if (pLVal)
666     {
667         *pLVal = rVal;
668     }
669 }
670 
671 /**
672 ****************************************************************************************************
673 *   SafeAssign
674 *
675 *   @brief
676 *       NULL pointer safe assignment for 64bit values
677 ****************************************************************************************************
678 */
SafeAssign(UINT_64 * pLVal,UINT_64 rVal)679 static inline VOID SafeAssign(
680     UINT_64*    pLVal,  ///< [in] Pointer to left val
681     UINT_64     rVal)   ///< [in] Right value
682 {
683     if (pLVal)
684     {
685         *pLVal = rVal;
686     }
687 }
688 
689 /**
690 ****************************************************************************************************
691 *   RoundHalf
692 *
693 *   @brief
694 *       return (x + 1) / 2
695 ****************************************************************************************************
696 */
RoundHalf(UINT_32 x)697 static inline UINT_32 RoundHalf(
698     UINT_32     x)     ///< [in] input value
699 {
700     ADDR_ASSERT(x != 0);
701 
702 #if 1
703     return (x >> 1) + (x & 1);
704 #else
705     return (x + 1) >> 1;
706 #endif
707 }
708 
709 /**
710 ****************************************************************************************************
711 *   SumGeo
712 *
713 *   @brief
714 *       Calculate sum of a geometric progression whose ratio is 1/2
715 ****************************************************************************************************
716 */
SumGeo(UINT_32 base,UINT_32 num)717 static inline UINT_32 SumGeo(
718     UINT_32     base,   ///< [in] First term in the geometric progression
719     UINT_32     num)    ///< [in] Number of terms to be added into sum
720 {
721     ADDR_ASSERT(base > 0);
722 
723     UINT_32 sum = 0;
724     UINT_32 i = 0;
725     for (; (i < num) && (base > 1); i++)
726     {
727         sum += base;
728         base = RoundHalf(base);
729     }
730     sum += num - i;
731 
732     return sum;
733 }
734 
735 /**
736 ****************************************************************************************************
737 *   GetBit
738 *
739 *   @brief
740 *       Extract bit N value (0 or 1) of a UINT32 value.
741 ****************************************************************************************************
742 */
GetBit(UINT_32 u32,UINT_32 pos)743 static inline UINT_32 GetBit(
744     UINT_32     u32,   ///< [in] UINT32 value
745     UINT_32     pos)   ///< [in] bit position from LSB, valid range is [0..31]
746 {
747     ADDR_ASSERT(pos <= 31);
748 
749     return (u32 >> pos) & 0x1;
750 }
751 
752 /**
753 ****************************************************************************************************
754 *   GetBits
755 *
756 *   @brief
757 *       Copy 'bitsNum' bits from src start from srcStartPos into destination from dstStartPos
758 *       srcStartPos: 0~31 for UINT_32
759 *       bitsNum    : 1~32 for UINT_32
760 *       srcStartPos: 0~31 for UINT_32
761 *                                                                 src start position
762 *                                                                          |
763 *       src : b[31] b[30] b[29] ... ... ... ... ... ... ... ... b[end]..b[beg] ... b[1] b[0]
764 *                                   || Bits num || copy length  || Bits num ||
765 *       dst : b[31] b[30] b[29] ... b[end]..b[beg] ... ... ... ... ... ... ... ... b[1] b[0]
766 *                                              |
767 *                                     dst start position
768 ****************************************************************************************************
769 */
GetBits(UINT_32 src,UINT_32 srcStartPos,UINT_32 bitsNum,UINT_32 dstStartPos)770 static inline UINT_32 GetBits(
771     UINT_32 src,
772     UINT_32 srcStartPos,
773     UINT_32 bitsNum,
774     UINT_32 dstStartPos)
775 {
776     ADDR_ASSERT((srcStartPos < 32) && (dstStartPos < 32) && (bitsNum > 0));
777     ADDR_ASSERT((bitsNum + dstStartPos <= 32) && (bitsNum + srcStartPos <= 32));
778 
779     return ((src >> srcStartPos) << (32 - bitsNum)) >> (32 - bitsNum - dstStartPos);
780 }
781 
782 /**
783 ****************************************************************************************************
784 *   MortonGen2d
785 *
786 *   @brief
787 *       Generate 2D Morton interleave code with num lowest bits in each channel
788 ****************************************************************************************************
789 */
MortonGen2d(UINT_32 x,UINT_32 y,UINT_32 num)790 static inline UINT_32 MortonGen2d(
791     UINT_32     x,     ///< [in] First channel
792     UINT_32     y,     ///< [in] Second channel
793     UINT_32     num)   ///< [in] Number of bits extracted from each channel
794 {
795     UINT_32 mort = 0;
796 
797     for (UINT_32 i = 0; i < num; i++)
798     {
799         mort |= (GetBit(y, i) << (2 * i));
800         mort |= (GetBit(x, i) << (2 * i + 1));
801     }
802 
803     return mort;
804 }
805 
806 /**
807 ****************************************************************************************************
808 *   MortonGen3d
809 *
810 *   @brief
811 *       Generate 3D Morton interleave code with num lowest bits in each channel
812 ****************************************************************************************************
813 */
MortonGen3d(UINT_32 x,UINT_32 y,UINT_32 z,UINT_32 num)814 static inline UINT_32 MortonGen3d(
815     UINT_32     x,     ///< [in] First channel
816     UINT_32     y,     ///< [in] Second channel
817     UINT_32     z,     ///< [in] Third channel
818     UINT_32     num)   ///< [in] Number of bits extracted from each channel
819 {
820     UINT_32 mort = 0;
821 
822     for (UINT_32 i = 0; i < num; i++)
823     {
824         mort |= (GetBit(z, i) << (3 * i));
825         mort |= (GetBit(y, i) << (3 * i + 1));
826         mort |= (GetBit(x, i) << (3 * i + 2));
827     }
828 
829     return mort;
830 }
831 
832 /**
833 ****************************************************************************************************
834 *   ReverseBitVector
835 *
836 *   @brief
837 *       Return reversed lowest num bits of v: v[0]v[1]...v[num-2]v[num-1]
838 ****************************************************************************************************
839 */
ReverseBitVector(UINT_32 v,UINT_32 num)840 static inline UINT_32 ReverseBitVector(
841     UINT_32     v,     ///< [in] Reverse operation base value
842     UINT_32     num)   ///< [in] Number of bits used in reverse operation
843 {
844     UINT_32 reverse = 0;
845 
846     for (UINT_32 i = 0; i < num; i++)
847     {
848         reverse |= (GetBit(v, num - 1 - i) << i);
849     }
850 
851     return reverse;
852 }
853 
854 /**
855 ****************************************************************************************************
856 *   FoldXor2d
857 *
858 *   @brief
859 *       Xor bit vector v[num-1]v[num-2]...v[1]v[0] with v[num]v[num+1]...v[2*num-2]v[2*num-1]
860 ****************************************************************************************************
861 */
FoldXor2d(UINT_32 v,UINT_32 num)862 static inline UINT_32 FoldXor2d(
863     UINT_32     v,     ///< [in] Xor operation base value
864     UINT_32     num)   ///< [in] Number of bits used in fold xor operation
865 {
866     return (v & ((1 << num) - 1)) ^ ReverseBitVector(v >> num, num);
867 }
868 
869 /**
870 ****************************************************************************************************
871 *   DeMort
872 *
873 *   @brief
874 *       Return v[0] | v[2] | v[4] | v[6]... | v[2*num - 2]
875 ****************************************************************************************************
876 */
DeMort(UINT_32 v,UINT_32 num)877 static inline UINT_32 DeMort(
878     UINT_32     v,     ///< [in] DeMort operation base value
879     UINT_32     num)   ///< [in] Number of bits used in fold DeMort operation
880 {
881     UINT_32 d = 0;
882 
883     for (UINT_32 i = 0; i < num; i++)
884     {
885         d |= ((v & (1 << (i << 1))) >> i);
886     }
887 
888     return d;
889 }
890 
891 /**
892 ****************************************************************************************************
893 *   FoldXor3d
894 *
895 *   @brief
896 *       v[0]...v[num-1] ^ v[3*num-1]v[3*num-3]...v[num+2]v[num] ^ v[3*num-2]...v[num+1]v[num-1]
897 ****************************************************************************************************
898 */
FoldXor3d(UINT_32 v,UINT_32 num)899 static inline UINT_32 FoldXor3d(
900     UINT_32     v,     ///< [in] Xor operation base value
901     UINT_32     num)   ///< [in] Number of bits used in fold xor operation
902 {
903     UINT_32 t = v & ((1 << num) - 1);
904     t ^= ReverseBitVector(DeMort(v >> num, num), num);
905     t ^= ReverseBitVector(DeMort(v >> (num + 1), num), num);
906 
907     return t;
908 }
909 
910 /**
911 ****************************************************************************************************
912 *   InitChannel
913 *
914 *   @brief
915 *       Set channel initialization value via a return value
916 ****************************************************************************************************
917 */
InitChannel(UINT_32 valid,UINT_32 channel,UINT_32 index)918 static inline ADDR_CHANNEL_SETTING InitChannel(
919     UINT_32     valid,     ///< [in] valid setting
920     UINT_32     channel,   ///< [in] channel setting
921     UINT_32     index)     ///< [in] index setting
922 {
923     ADDR_CHANNEL_SETTING t;
924     t.valid = valid;
925     t.channel = channel;
926     t.index = index;
927 
928     return t;
929 }
930 
931 /**
932 ****************************************************************************************************
933 *   InitChannel
934 *
935 *   @brief
936 *       Set channel initialization value via channel pointer
937 ****************************************************************************************************
938 */
InitChannel(UINT_32 valid,UINT_32 channel,UINT_32 index,ADDR_CHANNEL_SETTING * pChanSet)939 static inline VOID InitChannel(
940     UINT_32     valid,              ///< [in] valid setting
941     UINT_32     channel,            ///< [in] channel setting
942     UINT_32     index,              ///< [in] index setting
943     ADDR_CHANNEL_SETTING *pChanSet) ///< [out] channel setting to be initialized
944 {
945     pChanSet->valid = valid;
946     pChanSet->channel = channel;
947     pChanSet->index = index;
948 }
949 
950 
951 /**
952 ****************************************************************************************************
953 *   InitChannel
954 *
955 *   @brief
956 *       Set channel initialization value via another channel
957 ****************************************************************************************************
958 */
InitChannel(ADDR_CHANNEL_SETTING * pChanDst,ADDR_CHANNEL_SETTING * pChanSrc)959 static inline VOID InitChannel(
960     ADDR_CHANNEL_SETTING *pChanDst, ///< [in] channel setting to be copied from
961     ADDR_CHANNEL_SETTING *pChanSrc) ///< [out] channel setting to be initialized
962 {
963     pChanDst->valid = pChanSrc->valid;
964     pChanDst->channel = pChanSrc->channel;
965     pChanDst->index = pChanSrc->index;
966 }
967 
968 /**
969 ****************************************************************************************************
970 *   GetMaxValidChannelIndex
971 *
972 *   @brief
973 *       Get max valid index for a specific channel
974 ****************************************************************************************************
975 */
GetMaxValidChannelIndex(const ADDR_CHANNEL_SETTING * pChanSet,UINT_32 searchCount,UINT_32 channel)976 static inline UINT_32 GetMaxValidChannelIndex(
977     const ADDR_CHANNEL_SETTING *pChanSet,   ///< [in] channel setting to be initialized
978     UINT_32                     searchCount,///< [in] number of channel setting to be searched
979     UINT_32                     channel)    ///< [in] channel to be searched
980 {
981     UINT_32 index = 0;
982 
983     for (UINT_32 i = 0; i < searchCount; i++)
984     {
985         if (pChanSet[i].valid && (pChanSet[i].channel == channel))
986         {
987             index = Max(index, static_cast<UINT_32>(pChanSet[i].index));
988         }
989     }
990 
991     return index;
992 }
993 
994 /**
995 ****************************************************************************************************
996 *   GetCoordActiveMask
997 *
998 *   @brief
999 *       Get bit mask which indicates which positions in the equation match the target coord
1000 ****************************************************************************************************
1001 */
GetCoordActiveMask(const ADDR_CHANNEL_SETTING * pChanSet,UINT_32 searchCount,UINT_32 channel,UINT_32 index)1002 static inline UINT_32 GetCoordActiveMask(
1003     const ADDR_CHANNEL_SETTING *pChanSet,   ///< [in] channel setting to be initialized
1004     UINT_32                     searchCount,///< [in] number of channel setting to be searched
1005     UINT_32                     channel,    ///< [in] channel to be searched
1006     UINT_32                     index)      ///< [in] index to be searched
1007 {
1008     UINT_32 mask = 0;
1009 
1010     for (UINT_32 i = 0; i < searchCount; i++)
1011     {
1012         if ((pChanSet[i].valid   == TRUE)    &&
1013             (pChanSet[i].channel == channel) &&
1014             (pChanSet[i].index   == index))
1015         {
1016             mask |= (1 << i);
1017         }
1018     }
1019 
1020     return mask;
1021 }
1022 
1023 /**
1024 ****************************************************************************************************
1025 *   FillEqBitComponents
1026 *
1027 *   @brief
1028 *       Fill the 'numBitComponents' field based on the equation.
1029 ****************************************************************************************************
1030 */
FillEqBitComponents(ADDR_EQUATION * pEquation)1031 static inline void FillEqBitComponents(
1032     ADDR_EQUATION *pEquation) // [in/out] Equation to calculate bit components for
1033 {
1034     pEquation->numBitComponents = 1; // We always have at least the address
1035     for (UINT_32 xorN = 1; xorN < ADDR_MAX_EQUATION_COMP; xorN++)
1036     {
1037         for (UINT_32 bit = 0; bit < ADDR_MAX_EQUATION_BIT; bit++)
1038         {
1039             if (pEquation->comps[xorN][bit].valid)
1040             {
1041                 pEquation->numBitComponents = xorN + 1;
1042                 break;
1043             }
1044         }
1045 
1046         if (pEquation->numBitComponents != (xorN + 1))
1047         {
1048             // Skip following components if this one wasn't valid
1049             break;
1050         }
1051     }
1052 }
1053 
1054 /**
1055 ****************************************************************************************************
1056 *   ShiftCeil
1057 *
1058 *   @brief
1059 *       Apply right-shift with ceiling
1060 ****************************************************************************************************
1061 */
ShiftCeil(UINT_32 a,UINT_32 b)1062 static inline UINT_32 ShiftCeil(
1063     UINT_32 a,  ///< [in] value to be right-shifted
1064     UINT_32 b)  ///< [in] number of bits to shift
1065 {
1066     return (a >> b) + (((a & ((1 << b) - 1)) != 0) ? 1 : 0);
1067 }
1068 
1069 /**
1070 ****************************************************************************************************
1071 *   ShiftRight
1072 *
1073 *   @brief
1074 *       Return right-shift value and minimum is 1
1075 ****************************************************************************************************
1076 */
ShiftRight(UINT_32 a,UINT_32 b)1077 static inline UINT_32 ShiftRight(
1078     UINT_32 a,  ///< [in] value to be right-shifted
1079     UINT_32 b)  ///< [in] number of bits to shift
1080 {
1081     return Max(a >> b, 1u);
1082 }
1083 
1084 } // Addr
1085 
1086 #endif // __ADDR_COMMON_H__
1087 
1088