1 /* Copyright  (C) 2010-2020 The RetroArch team
2  *
3  * ---------------------------------------------------------------------------------------
4  * The following license statement only applies to this file (retro_endianness.h).
5  * ---------------------------------------------------------------------------------------
6  *
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:
12  *
13  * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
14  *
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.
21  */
22 
23 #ifndef __LIBRETRO_SDK_ENDIANNESS_H
24 #define __LIBRETRO_SDK_ENDIANNESS_H
25 
26 #include <retro_inline.h>
27 #include <stdint.h>
28 #include <stdlib.h>
29 
30 #if defined(_MSC_VER) && _MSC_VER > 1200
31 #define SWAP16 _byteswap_ushort
32 #define SWAP32 _byteswap_ulong
33 #else
SWAP16(uint16_t x)34 static INLINE uint16_t SWAP16(uint16_t x)
35 {
36   return ((x & 0x00ff) << 8) |
37          ((x & 0xff00) >> 8);
38 }
39 
SWAP32(uint32_t x)40 static INLINE uint32_t SWAP32(uint32_t x)
41 {
42   return ((x & 0x000000ff) << 24) |
43          ((x & 0x0000ff00) <<  8) |
44          ((x & 0x00ff0000) >>  8) |
45          ((x & 0xff000000) >> 24);
46 }
47 
48 #endif
49 
50 #if defined(_MSC_VER) && _MSC_VER <= 1200
SWAP64(uint64_t val)51 static INLINE uint64_t SWAP64(uint64_t val)
52 {
53   return
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);
62 }
63 #else
SWAP64(uint64_t val)64 static INLINE uint64_t SWAP64(uint64_t val)
65 {
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);
74 }
75 #endif
76 
77 
78 #if defined (LSB_FIRST) || defined (MSB_FIRST)
79 #  warning Defining MSB_FIRST and LSB_FIRST in compile options is deprecated
80 #  undef LSB_FIRST
81 #  undef MSB_FIRST
82 #endif
83 
84 #if defined(_MSC_VER) && !defined(_XBOX)
85 #include <winsock2.h>
86 #endif
87 
88 #ifdef _MSC_VER
89 #if _M_IX86 || _M_AMD64 || _M_ARM || _M_ARM64
90 #define LSB_FIRST 1
91 #elif _M_PPC
92 #define MSB_FIRST 1
93 #else
94 /* 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 */
95 #error "unknown platform, can't determine endianness"
96 #endif
97 #else
98 #if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
99 #define MSB_FIRST 1
100 #elif __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
101 #define LSB_FIRST 1
102 #else
103 #error "Invalid endianness macros"
104 #endif
105 #endif
106 
107 #if defined(MSB_FIRST) && defined(LSB_FIRST)
108 #  error "Bug in LSB_FIRST/MSB_FIRST definition"
109 #endif
110 
111 #if !defined(MSB_FIRST) && !defined(LSB_FIRST)
112 #  error "Bug in LSB_FIRST/MSB_FIRST definition"
113 #endif
114 
115 #ifdef MSB_FIRST
116 #  define RETRO_IS_BIG_ENDIAN 1
117 #  define RETRO_IS_LITTLE_ENDIAN 0
118 /* For compatibility */
119 #  define WORDS_BIGENDIAN 1
120 #else
121 #  define RETRO_IS_BIG_ENDIAN 0
122 #  define RETRO_IS_LITTLE_ENDIAN 1
123 /* For compatibility */
124 #  undef WORDS_BIGENDIAN
125 #endif
126 
127 
128 /**
129  * is_little_endian:
130  *
131  * Checks if the system is little endian or big-endian.
132  *
133  * Returns: greater than 0 if little-endian,
134  * otherwise big-endian.
135  **/
136 #define is_little_endian() RETRO_IS_LITTLE_ENDIAN
137 
138 /**
139  * swap_if_big64:
140  * @val        : unsigned 64-bit value
141  *
142  * Byteswap unsigned 64-bit value if system is big-endian.
143  *
144  * Returns: Byteswapped value in case system is big-endian,
145  * otherwise returns same value.
146  **/
147 
148 #if RETRO_IS_BIG_ENDIAN
149 #define swap_if_big64(val) (SWAP64(val))
150 #elif RETRO_IS_LITTLE_ENDIAN
151 #define swap_if_big64(val) (val)
152 #endif
153 
154 /**
155  * swap_if_big32:
156  * @val        : unsigned 32-bit value
157  *
158  * Byteswap unsigned 32-bit value if system is big-endian.
159  *
160  * Returns: Byteswapped value in case system is big-endian,
161  * otherwise returns same value.
162  **/
163 
164 #if RETRO_IS_BIG_ENDIAN
165 #define swap_if_big32(val) (SWAP32(val))
166 #elif RETRO_IS_LITTLE_ENDIAN
167 #define swap_if_big32(val) (val)
168 #endif
169 
170 /**
171  * swap_if_little64:
172  * @val        : unsigned 64-bit value
173  *
174  * Byteswap unsigned 64-bit value if system is little-endian.
175  *
176  * Returns: Byteswapped value in case system is little-endian,
177  * otherwise returns same value.
178  **/
179 
180 #if RETRO_IS_BIG_ENDIAN
181 #define swap_if_little64(val) (val)
182 #elif RETRO_IS_LITTLE_ENDIAN
183 #define swap_if_little64(val) (SWAP64(val))
184 #endif
185 
186 /**
187  * swap_if_little32:
188  * @val        : unsigned 32-bit value
189  *
190  * Byteswap unsigned 32-bit value if system is little-endian.
191  *
192  * Returns: Byteswapped value in case system is little-endian,
193  * otherwise returns same value.
194  **/
195 
196 #if RETRO_IS_BIG_ENDIAN
197 #define swap_if_little32(val) (val)
198 #elif RETRO_IS_LITTLE_ENDIAN
199 #define swap_if_little32(val) (SWAP32(val))
200 #endif
201 
202 /**
203  * swap_if_big16:
204  * @val        : unsigned 16-bit value
205  *
206  * Byteswap unsigned 16-bit value if system is big-endian.
207  *
208  * Returns: Byteswapped value in case system is big-endian,
209  * otherwise returns same value.
210  **/
211 
212 #if RETRO_IS_BIG_ENDIAN
213 #define swap_if_big16(val) (SWAP16(val))
214 #elif RETRO_IS_LITTLE_ENDIAN
215 #define swap_if_big16(val) (val)
216 #endif
217 
218 /**
219  * swap_if_little16:
220  * @val        : unsigned 16-bit value
221  *
222  * Byteswap unsigned 16-bit value if system is little-endian.
223  *
224  * Returns: Byteswapped value in case system is little-endian,
225  * otherwise returns same value.
226  **/
227 
228 #if RETRO_IS_BIG_ENDIAN
229 #define swap_if_little16(val) (val)
230 #elif RETRO_IS_LITTLE_ENDIAN
231 #define swap_if_little16(val) (SWAP16(val))
232 #endif
233 
234 /**
235  * store32be:
236  * @addr        : pointer to unsigned 32-bit buffer
237  * @data        : unsigned 32-bit value to write
238  *
239  * Write data to address. Endian-safe. Byteswaps the data
240  * first if necessary before storing it.
241  **/
store32be(uint32_t * addr,uint32_t data)242 static INLINE void store32be(uint32_t *addr, uint32_t data)
243 {
244    *addr = swap_if_little32(data);
245 }
246 
247 /**
248  * load32be:
249  * @addr        : pointer to unsigned 32-bit buffer
250  *
251  * Load value from address. Endian-safe.
252  *
253  * Returns: value from address, byte-swapped if necessary.
254  **/
load32be(const uint32_t * addr)255 static INLINE uint32_t load32be(const uint32_t *addr)
256 {
257    return swap_if_little32(*addr);
258 }
259 
260 /**
261  * retro_cpu_to_le16:
262  * @val        : unsigned 16-bit value
263  *
264  * Convert unsigned 16-bit value from system to little-endian.
265  *
266  * Returns: Little-endian representation of val.
267  **/
268 
269 #define retro_cpu_to_le16(val) swap_if_big16(val)
270 
271 /**
272  * retro_cpu_to_le32:
273  * @val        : unsigned 32-bit value
274  *
275  * Convert unsigned 32-bit value from system to little-endian.
276  *
277  * Returns: Little-endian representation of val.
278  **/
279 
280 #define retro_cpu_to_le32(val) swap_if_big32(val)
281 
282 /**
283  * retro_cpu_to_le64:
284  * @val        : unsigned 64-bit value
285  *
286  * Convert unsigned 64-bit value from system to little-endian.
287  *
288  * Returns: Little-endian representation of val.
289  **/
290 
291 #define retro_cpu_to_le64(val) swap_if_big64(val)
292 
293 /**
294  * retro_le_to_cpu16:
295  * @val        : unsigned 16-bit value
296  *
297  * Convert unsigned 16-bit value from little-endian to native.
298  *
299  * Returns: Native representation of little-endian val.
300  **/
301 
302 #define retro_le_to_cpu16(val) swap_if_big16(val)
303 
304 /**
305  * retro_le_to_cpu32:
306  * @val        : unsigned 32-bit value
307  *
308  * Convert unsigned 32-bit value from little-endian to native.
309  *
310  * Returns: Native representation of little-endian val.
311  **/
312 
313 #define retro_le_to_cpu32(val) swap_if_big32(val)
314 
315 /**
316  * retro_le_to_cpu16:
317  * @val        : unsigned 64-bit value
318  *
319  * Convert unsigned 64-bit value from little-endian to native.
320  *
321  * Returns: Native representation of little-endian val.
322  **/
323 
324 #define retro_le_to_cpu64(val) swap_if_big64(val)
325 
326 /**
327  * retro_cpu_to_be16:
328  * @val        : unsigned 16-bit value
329  *
330  * Convert unsigned 16-bit value from system to big-endian.
331  *
332  * Returns: Big-endian representation of val.
333  **/
334 
335 #define retro_cpu_to_be16(val) swap_if_little16(val)
336 
337 /**
338  * retro_cpu_to_be32:
339  * @val        : unsigned 32-bit value
340  *
341  * Convert unsigned 32-bit value from system to big-endian.
342  *
343  * Returns: Big-endian representation of val.
344  **/
345 
346 #define retro_cpu_to_be32(val) swap_if_little32(val)
347 
348 /**
349  * retro_cpu_to_be64:
350  * @val        : unsigned 64-bit value
351  *
352  * Convert unsigned 64-bit value from system to big-endian.
353  *
354  * Returns: Big-endian representation of val.
355  **/
356 
357 #define retro_cpu_to_be64(val) swap_if_little64(val)
358 
359 /**
360  * retro_be_to_cpu16:
361  * @val        : unsigned 16-bit value
362  *
363  * Convert unsigned 16-bit value from big-endian to native.
364  *
365  * Returns: Native representation of big-endian val.
366  **/
367 
368 #define retro_be_to_cpu16(val) swap_if_little16(val)
369 
370 /**
371  * retro_be_to_cpu32:
372  * @val        : unsigned 32-bit value
373  *
374  * Convert unsigned 32-bit value from big-endian to native.
375  *
376  * Returns: Native representation of big-endian val.
377  **/
378 
379 #define retro_be_to_cpu32(val) swap_if_little32(val)
380 
381 /**
382  * retro_be_to_cpu64:
383  * @val        : unsigned 64-bit value
384  *
385  * Convert unsigned 64-bit value from big-endian to native.
386  *
387  * Returns: Native representation of big-endian val.
388  **/
389 
390 #define retro_be_to_cpu64(val) swap_if_little64(val)
391 
392 #ifdef  __GNUC__
393 /* This attribute means that the same memory may be referred through
394    pointers to different size of the object (aliasing). E.g. that u8 *
395    and u32 * may actually be pointing to the same object.  */
396 #define MAY_ALIAS  __attribute__((__may_alias__))
397 #else
398 #define MAY_ALIAS
399 #endif
400 
401 #pragma pack(push, 1)
402 struct retro_unaligned_uint16_s
403 {
404   uint16_t val;
405 } MAY_ALIAS;
406 struct retro_unaligned_uint32_s
407 {
408   uint32_t val;
409 } MAY_ALIAS;
410 struct retro_unaligned_uint64_s
411 {
412   uint64_t val;
413 } MAY_ALIAS;
414 #pragma pack(pop)
415 
416 typedef struct retro_unaligned_uint16_s retro_unaligned_uint16_t;
417 typedef struct retro_unaligned_uint32_s retro_unaligned_uint32_t;
418 typedef struct retro_unaligned_uint64_s retro_unaligned_uint64_t;
419 
420 /* L-value references to unaligned pointers.  */
421 #define retro_unaligned16(p) (((retro_unaligned_uint16_t *)p)->val)
422 #define retro_unaligned32(p) (((retro_unaligned_uint32_t *)p)->val)
423 #define retro_unaligned64(p) (((retro_unaligned_uint64_t *)p)->val)
424 
425 /**
426  * retro_get_unaligned_16be:
427  * @addr        : pointer to unsigned 16-bit value
428  *
429  * Convert unsigned unaligned 16-bit value from big-endian to native.
430  *
431  * Returns: Native representation of big-endian val.
432  **/
433 
retro_get_unaligned_16be(void * addr)434 static INLINE uint16_t retro_get_unaligned_16be(void *addr) {
435   return retro_be_to_cpu16(retro_unaligned16(addr));
436 }
437 
438 /**
439  * retro_get_unaligned_32be:
440  * @addr        : pointer to unsigned 32-bit value
441  *
442  * Convert unsigned unaligned 32-bit value from big-endian to native.
443  *
444  * Returns: Native representation of big-endian val.
445  **/
446 
retro_get_unaligned_32be(void * addr)447 static INLINE uint32_t retro_get_unaligned_32be(void *addr) {
448   return retro_be_to_cpu32(retro_unaligned32(addr));
449 }
450 
451 /**
452  * retro_get_unaligned_64be:
453  * @addr        : pointer to unsigned 64-bit value
454  *
455  * Convert unsigned unaligned 64-bit value from big-endian to native.
456  *
457  * Returns: Native representation of big-endian val.
458  **/
459 
retro_get_unaligned_64be(void * addr)460 static INLINE uint64_t retro_get_unaligned_64be(void *addr) {
461   return retro_be_to_cpu64(retro_unaligned64(addr));
462 }
463 
464 /**
465  * retro_get_unaligned_16le:
466  * @addr        : pointer to unsigned 16-bit value
467  *
468  * Convert unsigned unaligned 16-bit value from little-endian to native.
469  *
470  * Returns: Native representation of little-endian val.
471  **/
472 
retro_get_unaligned_16le(void * addr)473 static INLINE uint16_t retro_get_unaligned_16le(void *addr) {
474   return retro_le_to_cpu16(retro_unaligned16(addr));
475 }
476 
477 /**
478  * retro_get_unaligned_32le:
479  * @addr        : pointer to unsigned 32-bit value
480  *
481  * Convert unsigned unaligned 32-bit value from little-endian to native.
482  *
483  * Returns: Native representation of little-endian val.
484  **/
485 
retro_get_unaligned_32le(void * addr)486 static INLINE uint32_t retro_get_unaligned_32le(void *addr) {
487   return retro_le_to_cpu32(retro_unaligned32(addr));
488 }
489 
490 /**
491  * retro_get_unaligned_64le:
492  * @addr        : pointer to unsigned 64-bit value
493  *
494  * Convert unsigned unaligned 64-bit value from little-endian to native.
495  *
496  * Returns: Native representation of little-endian val.
497  **/
498 
retro_get_unaligned_64le(void * addr)499 static INLINE uint64_t retro_get_unaligned_64le(void *addr) {
500   return retro_le_to_cpu64(retro_unaligned64(addr));
501 }
502 
503 /**
504  * retro_set_unaligned_16le:
505  * @addr        : pointer to unsigned 16-bit value
506  * @val         : value to store
507  *
508  * Convert native value to unsigned unaligned 16-bit little-endian value
509  *
510  **/
511 
retro_set_unaligned_16le(void * addr,uint16_t v)512 static INLINE void retro_set_unaligned_16le(void *addr, uint16_t v) {
513   retro_unaligned16(addr) = retro_cpu_to_le16(v);
514 }
515 
516 /**
517  * retro_set_unaligned_32le:
518  * @addr        : pointer to unsigned 32-bit value
519  * @val         : value to store
520  *
521  * Convert native value to unsigned unaligned 32-bit little-endian value
522  *
523  **/
524 
retro_set_unaligned_32le(void * addr,uint32_t v)525 static INLINE void retro_set_unaligned_32le(void *addr, uint32_t v) {
526   retro_unaligned32(addr) = retro_cpu_to_le32(v);
527 }
528 
529 /**
530  * retro_set_unaligned_32le:
531  * @addr        : pointer to unsigned 32-bit value
532  * @val         : value to store
533  *
534  * Convert native value to unsigned unaligned 32-bit little-endian value
535  *
536  **/
537 
retro_set_unaligned_64le(void * addr,uint64_t v)538 static INLINE void retro_set_unaligned_64le(void *addr, uint64_t v) {
539   retro_unaligned64(addr) = retro_cpu_to_le64(v);
540 }
541 
542 /**
543  * retro_set_unaligned_16be:
544  * @addr        : pointer to unsigned 16-bit value
545  * @val         : value to store
546  *
547  * Convert native value to unsigned unaligned 16-bit big-endian value
548  *
549  **/
550 
retro_set_unaligned_16be(void * addr,uint16_t v)551 static INLINE void retro_set_unaligned_16be(void *addr, uint16_t v) {
552   retro_unaligned16(addr) = retro_cpu_to_be16(v);
553 }
554 
555 /**
556  * retro_set_unaligned_32be:
557  * @addr        : pointer to unsigned 32-bit value
558  * @val         : value to store
559  *
560  * Convert native value to unsigned unaligned 32-bit big-endian value
561  *
562  **/
563 
retro_set_unaligned_32be(void * addr,uint32_t v)564 static INLINE void retro_set_unaligned_32be(void *addr, uint32_t v) {
565   retro_unaligned32(addr) = retro_cpu_to_be32(v);
566 }
567 
568 /**
569  * retro_set_unaligned_32be:
570  * @addr        : pointer to unsigned 32-bit value
571  * @val         : value to store
572  *
573  * Convert native value to unsigned unaligned 32-bit big-endian value
574  *
575  **/
576 
retro_set_unaligned_64be(void * addr,uint64_t v)577 static INLINE void retro_set_unaligned_64be(void *addr, uint64_t v) {
578   retro_unaligned64(addr) = retro_cpu_to_be64(v);
579 }
580 
581 
582 #endif
583