git subrepo clone https://github.com/libretro/libretro-common.git deps/libretro-common
[pcsx_rearmed.git] / deps / libretro-common / include / retro_endianness.h
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
34 static INLINE uint16_t SWAP16(uint16_t x)
35 {
36   return ((x & 0x00ff) << 8) |
37          ((x & 0xff00) >> 8);
38 }
39
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
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
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 #ifdef _MSC_VER
78 /* MSVC pre-defines macros depending on target arch */
79 #if defined (_M_IX86) || defined (_M_AMD64) || defined (_M_ARM) || defined (_M_ARM64)
80 #ifndef LSB_FIRST
81 #define LSB_FIRST 1
82 #endif
83 #elif _M_PPC
84 #ifndef MSB_FIRST
85 #define MSB_FIRST 1
86 #endif
87 #else
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"
90 #endif
91 #else
92 #if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
93 #ifndef MSB_FIRST
94 #define MSB_FIRST 1
95 #endif
96 #elif __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
97 #ifndef LSB_FIRST
98 #define LSB_FIRST 1
99 #endif
100 #else
101 #error "Invalid endianness macros"
102 #endif
103 #endif
104
105 #if defined(MSB_FIRST) && defined(LSB_FIRST)
106 #  error "Bug in LSB_FIRST/MSB_FIRST definition"
107 #endif
108
109 #if !defined(MSB_FIRST) && !defined(LSB_FIRST)
110 #  error "Bug in LSB_FIRST/MSB_FIRST definition"
111 #endif
112
113 #ifdef MSB_FIRST
114 #  define RETRO_IS_BIG_ENDIAN 1
115 #  define RETRO_IS_LITTLE_ENDIAN 0
116 /* For compatibility */
117 #  define WORDS_BIGENDIAN 1
118 #else
119 #  define RETRO_IS_BIG_ENDIAN 0
120 #  define RETRO_IS_LITTLE_ENDIAN 1
121 /* For compatibility */
122 #  undef WORDS_BIGENDIAN
123 #endif
124
125
126 /**
127  * is_little_endian:
128  *
129  * Checks if the system is little endian or big-endian.
130  *
131  * Returns: greater than 0 if little-endian,
132  * otherwise big-endian.
133  **/
134 #define is_little_endian() RETRO_IS_LITTLE_ENDIAN
135
136 /**
137  * swap_if_big64:
138  * @val        : unsigned 64-bit value
139  *
140  * Byteswap unsigned 64-bit value if system is big-endian.
141  *
142  * Returns: Byteswapped value in case system is big-endian,
143  * otherwise returns same value.
144  **/
145
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)
150 #endif
151
152 /**
153  * swap_if_big32:
154  * @val        : unsigned 32-bit value
155  *
156  * Byteswap unsigned 32-bit value if system is big-endian.
157  *
158  * Returns: Byteswapped value in case system is big-endian,
159  * otherwise returns same value.
160  **/
161
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)
166 #endif
167
168 /**
169  * swap_if_little64:
170  * @val        : unsigned 64-bit value
171  *
172  * Byteswap unsigned 64-bit value if system is little-endian.
173  *
174  * Returns: Byteswapped value in case system is little-endian,
175  * otherwise returns same value.
176  **/
177
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))
182 #endif
183
184 /**
185  * swap_if_little32:
186  * @val        : unsigned 32-bit value
187  *
188  * Byteswap unsigned 32-bit value if system is little-endian.
189  *
190  * Returns: Byteswapped value in case system is little-endian,
191  * otherwise returns same value.
192  **/
193
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))
198 #endif
199
200 /**
201  * swap_if_big16:
202  * @val        : unsigned 16-bit value
203  *
204  * Byteswap unsigned 16-bit value if system is big-endian.
205  *
206  * Returns: Byteswapped value in case system is big-endian,
207  * otherwise returns same value.
208  **/
209
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)
214 #endif
215
216 /**
217  * swap_if_little16:
218  * @val        : unsigned 16-bit value
219  *
220  * Byteswap unsigned 16-bit value if system is little-endian.
221  *
222  * Returns: Byteswapped value in case system is little-endian,
223  * otherwise returns same value.
224  **/
225
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))
230 #endif
231
232 /**
233  * store32be:
234  * @addr        : pointer to unsigned 32-bit buffer
235  * @data        : unsigned 32-bit value to write
236  *
237  * Write data to address. Endian-safe. Byteswaps the data
238  * first if necessary before storing it.
239  **/
240 static INLINE void store32be(uint32_t *addr, uint32_t data)
241 {
242    *addr = swap_if_little32(data);
243 }
244
245 /**
246  * load32be:
247  * @addr        : pointer to unsigned 32-bit buffer
248  *
249  * Load value from address. Endian-safe.
250  *
251  * Returns: value from address, byte-swapped if necessary.
252  **/
253 static INLINE uint32_t load32be(const uint32_t *addr)
254 {
255    return swap_if_little32(*addr);
256 }
257
258 /**
259  * retro_cpu_to_le16:
260  * @val        : unsigned 16-bit value
261  *
262  * Convert unsigned 16-bit value from system to little-endian.
263  *
264  * Returns: Little-endian representation of val.
265  **/
266
267 #define retro_cpu_to_le16(val) swap_if_big16(val)
268
269 /**
270  * retro_cpu_to_le32:
271  * @val        : unsigned 32-bit value
272  *
273  * Convert unsigned 32-bit value from system to little-endian.
274  *
275  * Returns: Little-endian representation of val.
276  **/
277
278 #define retro_cpu_to_le32(val) swap_if_big32(val)
279
280 /**
281  * retro_cpu_to_le64:
282  * @val        : unsigned 64-bit value
283  *
284  * Convert unsigned 64-bit value from system to little-endian.
285  *
286  * Returns: Little-endian representation of val.
287  **/
288
289 #define retro_cpu_to_le64(val) swap_if_big64(val)
290
291 /**
292  * retro_le_to_cpu16:
293  * @val        : unsigned 16-bit value
294  *
295  * Convert unsigned 16-bit value from little-endian to native.
296  *
297  * Returns: Native representation of little-endian val.
298  **/
299
300 #define retro_le_to_cpu16(val) swap_if_big16(val)
301
302 /**
303  * retro_le_to_cpu32:
304  * @val        : unsigned 32-bit value
305  *
306  * Convert unsigned 32-bit value from little-endian to native.
307  *
308  * Returns: Native representation of little-endian val.
309  **/
310
311 #define retro_le_to_cpu32(val) swap_if_big32(val)
312
313 /**
314  * retro_le_to_cpu16:
315  * @val        : unsigned 64-bit value
316  *
317  * Convert unsigned 64-bit value from little-endian to native.
318  *
319  * Returns: Native representation of little-endian val.
320  **/
321
322 #define retro_le_to_cpu64(val) swap_if_big64(val)
323
324 /**
325  * retro_cpu_to_be16:
326  * @val        : unsigned 16-bit value
327  *
328  * Convert unsigned 16-bit value from system to big-endian.
329  *
330  * Returns: Big-endian representation of val.
331  **/
332
333 #define retro_cpu_to_be16(val) swap_if_little16(val)
334
335 /**
336  * retro_cpu_to_be32:
337  * @val        : unsigned 32-bit value
338  *
339  * Convert unsigned 32-bit value from system to big-endian.
340  *
341  * Returns: Big-endian representation of val.
342  **/
343
344 #define retro_cpu_to_be32(val) swap_if_little32(val)
345
346 /**
347  * retro_cpu_to_be64:
348  * @val        : unsigned 64-bit value
349  *
350  * Convert unsigned 64-bit value from system to big-endian.
351  *
352  * Returns: Big-endian representation of val.
353  **/
354
355 #define retro_cpu_to_be64(val) swap_if_little64(val)
356
357 /**
358  * retro_be_to_cpu16:
359  * @val        : unsigned 16-bit value
360  *
361  * Convert unsigned 16-bit value from big-endian to native.
362  *
363  * Returns: Native representation of big-endian val.
364  **/
365
366 #define retro_be_to_cpu16(val) swap_if_little16(val)
367
368 /**
369  * retro_be_to_cpu32:
370  * @val        : unsigned 32-bit value
371  *
372  * Convert unsigned 32-bit value from big-endian to native.
373  *
374  * Returns: Native representation of big-endian val.
375  **/
376
377 #define retro_be_to_cpu32(val) swap_if_little32(val)
378
379 /**
380  * retro_be_to_cpu64:
381  * @val        : unsigned 64-bit value
382  *
383  * Convert unsigned 64-bit value from big-endian to native.
384  *
385  * Returns: Native representation of big-endian val.
386  **/
387
388 #define retro_be_to_cpu64(val) swap_if_little64(val)
389
390 #ifdef  __GNUC__
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__))
395 #else
396 #define MAY_ALIAS
397 #endif
398
399 #pragma pack(push, 1)
400 struct retro_unaligned_uint16_s
401 {
402   uint16_t val;
403 } MAY_ALIAS;
404 struct retro_unaligned_uint32_s
405 {
406   uint32_t val;
407 } MAY_ALIAS;
408 struct retro_unaligned_uint64_s
409 {
410   uint64_t val;
411 } MAY_ALIAS;
412 #pragma pack(pop)
413
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;
417
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)
422
423 /**
424  * retro_get_unaligned_16be:
425  * @addr        : pointer to unsigned 16-bit value
426  *
427  * Convert unsigned unaligned 16-bit value from big-endian to native.
428  *
429  * Returns: Native representation of big-endian val.
430  **/
431
432 static INLINE uint16_t retro_get_unaligned_16be(void *addr) {
433   return retro_be_to_cpu16(retro_unaligned16(addr));
434 }
435
436 /**
437  * retro_get_unaligned_32be:
438  * @addr        : pointer to unsigned 32-bit value
439  *
440  * Convert unsigned unaligned 32-bit value from big-endian to native.
441  *
442  * Returns: Native representation of big-endian val.
443  **/
444
445 static INLINE uint32_t retro_get_unaligned_32be(void *addr) {
446   return retro_be_to_cpu32(retro_unaligned32(addr));
447 }
448
449 /**
450  * retro_get_unaligned_64be:
451  * @addr        : pointer to unsigned 64-bit value
452  *
453  * Convert unsigned unaligned 64-bit value from big-endian to native.
454  *
455  * Returns: Native representation of big-endian val.
456  **/
457
458 static INLINE uint64_t retro_get_unaligned_64be(void *addr) {
459   return retro_be_to_cpu64(retro_unaligned64(addr));
460 }
461
462 /**
463  * retro_get_unaligned_16le:
464  * @addr        : pointer to unsigned 16-bit value
465  *
466  * Convert unsigned unaligned 16-bit value from little-endian to native.
467  *
468  * Returns: Native representation of little-endian val.
469  **/
470
471 static INLINE uint16_t retro_get_unaligned_16le(void *addr) {
472   return retro_le_to_cpu16(retro_unaligned16(addr));
473 }
474
475 /**
476  * retro_get_unaligned_32le:
477  * @addr        : pointer to unsigned 32-bit value
478  *
479  * Convert unsigned unaligned 32-bit value from little-endian to native.
480  *
481  * Returns: Native representation of little-endian val.
482  **/
483
484 static INLINE uint32_t retro_get_unaligned_32le(void *addr) {
485   return retro_le_to_cpu32(retro_unaligned32(addr));
486 }
487
488 /**
489  * retro_get_unaligned_64le:
490  * @addr        : pointer to unsigned 64-bit value
491  *
492  * Convert unsigned unaligned 64-bit value from little-endian to native.
493  *
494  * Returns: Native representation of little-endian val.
495  **/
496
497 static INLINE uint64_t retro_get_unaligned_64le(void *addr) {
498   return retro_le_to_cpu64(retro_unaligned64(addr));
499 }
500
501 /**
502  * retro_set_unaligned_16le:
503  * @addr        : pointer to unsigned 16-bit value
504  * @val         : value to store
505  *
506  * Convert native value to unsigned unaligned 16-bit little-endian value
507  *
508  **/
509
510 static INLINE void retro_set_unaligned_16le(void *addr, uint16_t v) {
511   retro_unaligned16(addr) = retro_cpu_to_le16(v);
512 }
513
514 /**
515  * retro_set_unaligned_32le:
516  * @addr        : pointer to unsigned 32-bit value
517  * @val         : value to store
518  *
519  * Convert native value to unsigned unaligned 32-bit little-endian value
520  *
521  **/
522
523 static INLINE void retro_set_unaligned_32le(void *addr, uint32_t v) {
524   retro_unaligned32(addr) = retro_cpu_to_le32(v);
525 }
526
527 /**
528  * retro_set_unaligned_32le:
529  * @addr        : pointer to unsigned 32-bit value
530  * @val         : value to store
531  *
532  * Convert native value to unsigned unaligned 32-bit little-endian value
533  *
534  **/
535
536 static INLINE void retro_set_unaligned_64le(void *addr, uint64_t v) {
537   retro_unaligned64(addr) = retro_cpu_to_le64(v);
538 }
539
540 /**
541  * retro_set_unaligned_16be:
542  * @addr        : pointer to unsigned 16-bit value
543  * @val         : value to store
544  *
545  * Convert native value to unsigned unaligned 16-bit big-endian value
546  *
547  **/
548
549 static INLINE void retro_set_unaligned_16be(void *addr, uint16_t v) {
550   retro_unaligned16(addr) = retro_cpu_to_be16(v);
551 }
552
553 /**
554  * retro_set_unaligned_32be:
555  * @addr        : pointer to unsigned 32-bit value
556  * @val         : value to store
557  *
558  * Convert native value to unsigned unaligned 32-bit big-endian value
559  *
560  **/
561
562 static INLINE void retro_set_unaligned_32be(void *addr, uint32_t v) {
563   retro_unaligned32(addr) = retro_cpu_to_be32(v);
564 }
565
566 /**
567  * retro_set_unaligned_32be:
568  * @addr        : pointer to unsigned 32-bit value
569  * @val         : value to store
570  *
571  * Convert native value to unsigned unaligned 32-bit big-endian value
572  *
573  **/
574
575 static INLINE void retro_set_unaligned_64be(void *addr, uint64_t v) {
576   retro_unaligned64(addr) = retro_cpu_to_be64(v);
577 }
578
579
580 #endif