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