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