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