1 /* Copyright (C) 2010-2020 The RetroArch team
3 * ---------------------------------------------------------------------------------------
4 * The following license statement only applies to this file (retro_endianness.h).
5 * ---------------------------------------------------------------------------------------
7 * Permission is hereby granted, free of charge,
8 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
9 * to deal in the Software without restriction, including without limitation the rights to
10 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
11 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
13 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
16 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
18 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
19 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23 #ifndef __LIBRETRO_SDK_ENDIANNESS_H
24 #define __LIBRETRO_SDK_ENDIANNESS_H
26 #include <retro_inline.h>
30 #if defined(_MSC_VER) && _MSC_VER > 1200
31 #define SWAP16 _byteswap_ushort
32 #define SWAP32 _byteswap_ulong
34 static INLINE uint16_t SWAP16(uint16_t x)
36 return ((x & 0x00ff) << 8) |
40 static INLINE uint32_t SWAP32(uint32_t x)
42 return ((x & 0x000000ff) << 24) |
43 ((x & 0x0000ff00) << 8) |
44 ((x & 0x00ff0000) >> 8) |
45 ((x & 0xff000000) >> 24);
50 #if defined(_MSC_VER) && _MSC_VER <= 1200
51 static INLINE uint64_t SWAP64(uint64_t val)
54 ((val & 0x00000000000000ff) << 56)
55 | ((val & 0x000000000000ff00) << 40)
56 | ((val & 0x0000000000ff0000) << 24)
57 | ((val & 0x00000000ff000000) << 8)
58 | ((val & 0x000000ff00000000) >> 8)
59 | ((val & 0x0000ff0000000000) >> 24)
60 | ((val & 0x00ff000000000000) >> 40)
61 | ((val & 0xff00000000000000) >> 56);
64 static INLINE uint64_t SWAP64(uint64_t val)
66 return ((val & 0x00000000000000ffULL) << 56)
67 | ((val & 0x000000000000ff00ULL) << 40)
68 | ((val & 0x0000000000ff0000ULL) << 24)
69 | ((val & 0x00000000ff000000ULL) << 8)
70 | ((val & 0x000000ff00000000ULL) >> 8)
71 | ((val & 0x0000ff0000000000ULL) >> 24)
72 | ((val & 0x00ff000000000000ULL) >> 40)
73 | ((val & 0xff00000000000000ULL) >> 56);
78 /* MSVC pre-defines macros depending on target arch */
79 #if defined (_M_IX86) || defined (_M_AMD64) || defined (_M_ARM) || defined (_M_ARM64)
88 /* MSVC can run on _M_ALPHA and _M_IA64 too, but they're both bi-endian; need to find what mode MSVC runs them at */
89 #error "unknown platform, can't determine endianness"
92 #if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
96 #elif __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
101 #error "Invalid endianness macros"
105 #if defined(MSB_FIRST) && defined(LSB_FIRST)
106 # error "Bug in LSB_FIRST/MSB_FIRST definition"
109 #if !defined(MSB_FIRST) && !defined(LSB_FIRST)
110 # error "Bug in LSB_FIRST/MSB_FIRST definition"
114 # define RETRO_IS_BIG_ENDIAN 1
115 # define RETRO_IS_LITTLE_ENDIAN 0
116 /* For compatibility */
117 # define WORDS_BIGENDIAN 1
119 # define RETRO_IS_BIG_ENDIAN 0
120 # define RETRO_IS_LITTLE_ENDIAN 1
121 /* For compatibility */
122 # undef WORDS_BIGENDIAN
129 * Checks if the system is little endian or big-endian.
131 * Returns: greater than 0 if little-endian,
132 * otherwise big-endian.
134 #define is_little_endian() RETRO_IS_LITTLE_ENDIAN
138 * @val : unsigned 64-bit value
140 * Byteswap unsigned 64-bit value if system is big-endian.
142 * Returns: Byteswapped value in case system is big-endian,
143 * otherwise returns same value.
146 #if RETRO_IS_BIG_ENDIAN
147 #define swap_if_big64(val) (SWAP64(val))
148 #elif RETRO_IS_LITTLE_ENDIAN
149 #define swap_if_big64(val) (val)
154 * @val : unsigned 32-bit value
156 * Byteswap unsigned 32-bit value if system is big-endian.
158 * Returns: Byteswapped value in case system is big-endian,
159 * otherwise returns same value.
162 #if RETRO_IS_BIG_ENDIAN
163 #define swap_if_big32(val) (SWAP32(val))
164 #elif RETRO_IS_LITTLE_ENDIAN
165 #define swap_if_big32(val) (val)
170 * @val : unsigned 64-bit value
172 * Byteswap unsigned 64-bit value if system is little-endian.
174 * Returns: Byteswapped value in case system is little-endian,
175 * otherwise returns same value.
178 #if RETRO_IS_BIG_ENDIAN
179 #define swap_if_little64(val) (val)
180 #elif RETRO_IS_LITTLE_ENDIAN
181 #define swap_if_little64(val) (SWAP64(val))
186 * @val : unsigned 32-bit value
188 * Byteswap unsigned 32-bit value if system is little-endian.
190 * Returns: Byteswapped value in case system is little-endian,
191 * otherwise returns same value.
194 #if RETRO_IS_BIG_ENDIAN
195 #define swap_if_little32(val) (val)
196 #elif RETRO_IS_LITTLE_ENDIAN
197 #define swap_if_little32(val) (SWAP32(val))
202 * @val : unsigned 16-bit value
204 * Byteswap unsigned 16-bit value if system is big-endian.
206 * Returns: Byteswapped value in case system is big-endian,
207 * otherwise returns same value.
210 #if RETRO_IS_BIG_ENDIAN
211 #define swap_if_big16(val) (SWAP16(val))
212 #elif RETRO_IS_LITTLE_ENDIAN
213 #define swap_if_big16(val) (val)
218 * @val : unsigned 16-bit value
220 * Byteswap unsigned 16-bit value if system is little-endian.
222 * Returns: Byteswapped value in case system is little-endian,
223 * otherwise returns same value.
226 #if RETRO_IS_BIG_ENDIAN
227 #define swap_if_little16(val) (val)
228 #elif RETRO_IS_LITTLE_ENDIAN
229 #define swap_if_little16(val) (SWAP16(val))
234 * @addr : pointer to unsigned 32-bit buffer
235 * @data : unsigned 32-bit value to write
237 * Write data to address. Endian-safe. Byteswaps the data
238 * first if necessary before storing it.
240 static INLINE void store32be(uint32_t *addr, uint32_t data)
242 *addr = swap_if_little32(data);
247 * @addr : pointer to unsigned 32-bit buffer
249 * Load value from address. Endian-safe.
251 * Returns: value from address, byte-swapped if necessary.
253 static INLINE uint32_t load32be(const uint32_t *addr)
255 return swap_if_little32(*addr);
260 * @val : unsigned 16-bit value
262 * Convert unsigned 16-bit value from system to little-endian.
264 * Returns: Little-endian representation of val.
267 #define retro_cpu_to_le16(val) swap_if_big16(val)
271 * @val : unsigned 32-bit value
273 * Convert unsigned 32-bit value from system to little-endian.
275 * Returns: Little-endian representation of val.
278 #define retro_cpu_to_le32(val) swap_if_big32(val)
282 * @val : unsigned 64-bit value
284 * Convert unsigned 64-bit value from system to little-endian.
286 * Returns: Little-endian representation of val.
289 #define retro_cpu_to_le64(val) swap_if_big64(val)
293 * @val : unsigned 16-bit value
295 * Convert unsigned 16-bit value from little-endian to native.
297 * Returns: Native representation of little-endian val.
300 #define retro_le_to_cpu16(val) swap_if_big16(val)
304 * @val : unsigned 32-bit value
306 * Convert unsigned 32-bit value from little-endian to native.
308 * Returns: Native representation of little-endian val.
311 #define retro_le_to_cpu32(val) swap_if_big32(val)
315 * @val : unsigned 64-bit value
317 * Convert unsigned 64-bit value from little-endian to native.
319 * Returns: Native representation of little-endian val.
322 #define retro_le_to_cpu64(val) swap_if_big64(val)
326 * @val : unsigned 16-bit value
328 * Convert unsigned 16-bit value from system to big-endian.
330 * Returns: Big-endian representation of val.
333 #define retro_cpu_to_be16(val) swap_if_little16(val)
337 * @val : unsigned 32-bit value
339 * Convert unsigned 32-bit value from system to big-endian.
341 * Returns: Big-endian representation of val.
344 #define retro_cpu_to_be32(val) swap_if_little32(val)
348 * @val : unsigned 64-bit value
350 * Convert unsigned 64-bit value from system to big-endian.
352 * Returns: Big-endian representation of val.
355 #define retro_cpu_to_be64(val) swap_if_little64(val)
359 * @val : unsigned 16-bit value
361 * Convert unsigned 16-bit value from big-endian to native.
363 * Returns: Native representation of big-endian val.
366 #define retro_be_to_cpu16(val) swap_if_little16(val)
370 * @val : unsigned 32-bit value
372 * Convert unsigned 32-bit value from big-endian to native.
374 * Returns: Native representation of big-endian val.
377 #define retro_be_to_cpu32(val) swap_if_little32(val)
381 * @val : unsigned 64-bit value
383 * Convert unsigned 64-bit value from big-endian to native.
385 * Returns: Native representation of big-endian val.
388 #define retro_be_to_cpu64(val) swap_if_little64(val)
391 /* This attribute means that the same memory may be referred through
392 pointers to different size of the object (aliasing). E.g. that u8 *
393 and u32 * may actually be pointing to the same object. */
394 #define MAY_ALIAS __attribute__((__may_alias__))
399 #pragma pack(push, 1)
400 struct retro_unaligned_uint16_s
404 struct retro_unaligned_uint32_s
408 struct retro_unaligned_uint64_s
414 typedef struct retro_unaligned_uint16_s retro_unaligned_uint16_t;
415 typedef struct retro_unaligned_uint32_s retro_unaligned_uint32_t;
416 typedef struct retro_unaligned_uint64_s retro_unaligned_uint64_t;
418 /* L-value references to unaligned pointers. */
419 #define retro_unaligned16(p) (((retro_unaligned_uint16_t *)p)->val)
420 #define retro_unaligned32(p) (((retro_unaligned_uint32_t *)p)->val)
421 #define retro_unaligned64(p) (((retro_unaligned_uint64_t *)p)->val)
424 * retro_get_unaligned_16be:
425 * @addr : pointer to unsigned 16-bit value
427 * Convert unsigned unaligned 16-bit value from big-endian to native.
429 * Returns: Native representation of big-endian val.
432 static INLINE uint16_t retro_get_unaligned_16be(void *addr) {
433 return retro_be_to_cpu16(retro_unaligned16(addr));
437 * retro_get_unaligned_32be:
438 * @addr : pointer to unsigned 32-bit value
440 * Convert unsigned unaligned 32-bit value from big-endian to native.
442 * Returns: Native representation of big-endian val.
445 static INLINE uint32_t retro_get_unaligned_32be(void *addr) {
446 return retro_be_to_cpu32(retro_unaligned32(addr));
450 * retro_get_unaligned_64be:
451 * @addr : pointer to unsigned 64-bit value
453 * Convert unsigned unaligned 64-bit value from big-endian to native.
455 * Returns: Native representation of big-endian val.
458 static INLINE uint64_t retro_get_unaligned_64be(void *addr) {
459 return retro_be_to_cpu64(retro_unaligned64(addr));
463 * retro_get_unaligned_16le:
464 * @addr : pointer to unsigned 16-bit value
466 * Convert unsigned unaligned 16-bit value from little-endian to native.
468 * Returns: Native representation of little-endian val.
471 static INLINE uint16_t retro_get_unaligned_16le(void *addr) {
472 return retro_le_to_cpu16(retro_unaligned16(addr));
476 * retro_get_unaligned_32le:
477 * @addr : pointer to unsigned 32-bit value
479 * Convert unsigned unaligned 32-bit value from little-endian to native.
481 * Returns: Native representation of little-endian val.
484 static INLINE uint32_t retro_get_unaligned_32le(void *addr) {
485 return retro_le_to_cpu32(retro_unaligned32(addr));
489 * retro_get_unaligned_64le:
490 * @addr : pointer to unsigned 64-bit value
492 * Convert unsigned unaligned 64-bit value from little-endian to native.
494 * Returns: Native representation of little-endian val.
497 static INLINE uint64_t retro_get_unaligned_64le(void *addr) {
498 return retro_le_to_cpu64(retro_unaligned64(addr));
502 * retro_set_unaligned_16le:
503 * @addr : pointer to unsigned 16-bit value
504 * @val : value to store
506 * Convert native value to unsigned unaligned 16-bit little-endian value
510 static INLINE void retro_set_unaligned_16le(void *addr, uint16_t v) {
511 retro_unaligned16(addr) = retro_cpu_to_le16(v);
515 * retro_set_unaligned_32le:
516 * @addr : pointer to unsigned 32-bit value
517 * @val : value to store
519 * Convert native value to unsigned unaligned 32-bit little-endian value
523 static INLINE void retro_set_unaligned_32le(void *addr, uint32_t v) {
524 retro_unaligned32(addr) = retro_cpu_to_le32(v);
528 * retro_set_unaligned_32le:
529 * @addr : pointer to unsigned 32-bit value
530 * @val : value to store
532 * Convert native value to unsigned unaligned 32-bit little-endian value
536 static INLINE void retro_set_unaligned_64le(void *addr, uint64_t v) {
537 retro_unaligned64(addr) = retro_cpu_to_le64(v);
541 * retro_set_unaligned_16be:
542 * @addr : pointer to unsigned 16-bit value
543 * @val : value to store
545 * Convert native value to unsigned unaligned 16-bit big-endian value
549 static INLINE void retro_set_unaligned_16be(void *addr, uint16_t v) {
550 retro_unaligned16(addr) = retro_cpu_to_be16(v);
554 * retro_set_unaligned_32be:
555 * @addr : pointer to unsigned 32-bit value
556 * @val : value to store
558 * Convert native value to unsigned unaligned 32-bit big-endian value
562 static INLINE void retro_set_unaligned_32be(void *addr, uint32_t v) {
563 retro_unaligned32(addr) = retro_cpu_to_be32(v);
567 * retro_set_unaligned_32be:
568 * @addr : pointer to unsigned 32-bit value
569 * @val : value to store
571 * Convert native value to unsigned unaligned 32-bit big-endian value
575 static INLINE void retro_set_unaligned_64be(void *addr, uint64_t v) {
576 retro_unaligned64(addr) = retro_cpu_to_be64(v);