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