git subrepo clone https://github.com/libretro/libretro-common.git deps/libretro-common
[pcsx_rearmed.git] / deps / libretro-common / include / retro_endianness.h
CommitLineData
3719602c
PC
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
34static INLINE uint16_t SWAP16(uint16_t x)
35{
36 return ((x & 0x00ff) << 8) |
37 ((x & 0xff00) >> 8);
38}
39
40static 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
51static 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
64static 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 **/
240static 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 **/
253static 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)
400struct retro_unaligned_uint16_s
401{
402 uint16_t val;
403} MAY_ALIAS;
404struct retro_unaligned_uint32_s
405{
406 uint32_t val;
407} MAY_ALIAS;
408struct retro_unaligned_uint64_s
409{
410 uint64_t val;
411} MAY_ALIAS;
412#pragma pack(pop)
413
414typedef struct retro_unaligned_uint16_s retro_unaligned_uint16_t;
415typedef struct retro_unaligned_uint32_s retro_unaligned_uint32_t;
416typedef 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
432static 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
445static 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
458static 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
471static 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
484static 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
497static 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
510static 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
523static 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
536static 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
549static 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
562static 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
575static 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