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