sync with latest
[sdk/emulator/qemu.git] / bswap.h
1 #ifndef BSWAP_H
2 #define BSWAP_H
3
4 #include "config-host.h"
5
6 #include <inttypes.h>
7 #include "softfloat.h"
8
9 #ifdef CONFIG_MACHINE_BSWAP_H
10 #include <sys/endian.h>
11 #include <sys/types.h>
12 #include <machine/bswap.h>
13 #else
14
15 #ifdef CONFIG_BYTESWAP_H
16 #include <byteswap.h>
17 #else
18
19 #define bswap_16(x) \
20 ({ \
21         uint16_t __x = (x); \
22         ((uint16_t)( \
23                 (((uint16_t)(__x) & (uint16_t)0x00ffU) << 8) | \
24                 (((uint16_t)(__x) & (uint16_t)0xff00U) >> 8) )); \
25 })
26
27 #define bswap_32(x) \
28 ({ \
29         uint32_t __x = (x); \
30         ((uint32_t)( \
31                 (((uint32_t)(__x) & (uint32_t)0x000000ffUL) << 24) | \
32                 (((uint32_t)(__x) & (uint32_t)0x0000ff00UL) <<  8) | \
33                 (((uint32_t)(__x) & (uint32_t)0x00ff0000UL) >>  8) | \
34                 (((uint32_t)(__x) & (uint32_t)0xff000000UL) >> 24) )); \
35 })
36
37 #define bswap_64(x) \
38 ({ \
39         uint64_t __x = (x); \
40         ((uint64_t)( \
41                 (uint64_t)(((uint64_t)(__x) & (uint64_t)0x00000000000000ffULL) << 56) | \
42                 (uint64_t)(((uint64_t)(__x) & (uint64_t)0x000000000000ff00ULL) << 40) | \
43                 (uint64_t)(((uint64_t)(__x) & (uint64_t)0x0000000000ff0000ULL) << 24) | \
44                 (uint64_t)(((uint64_t)(__x) & (uint64_t)0x00000000ff000000ULL) <<  8) | \
45                 (uint64_t)(((uint64_t)(__x) & (uint64_t)0x000000ff00000000ULL) >>  8) | \
46                 (uint64_t)(((uint64_t)(__x) & (uint64_t)0x0000ff0000000000ULL) >> 24) | \
47                 (uint64_t)(((uint64_t)(__x) & (uint64_t)0x00ff000000000000ULL) >> 40) | \
48                 (uint64_t)(((uint64_t)(__x) & (uint64_t)0xff00000000000000ULL) >> 56) )); \
49 })
50
51 #endif /* !CONFIG_BYTESWAP_H */
52
53 static inline uint16_t bswap16(uint16_t x)
54 {
55     return bswap_16(x);
56 }
57
58 static inline uint32_t bswap32(uint32_t x)
59 {
60     return bswap_32(x);
61 }
62
63 static inline uint64_t bswap64(uint64_t x)
64 {
65     return bswap_64(x);
66 }
67
68 #endif /* ! CONFIG_MACHINE_BSWAP_H */
69
70 static inline void bswap16s(uint16_t *s)
71 {
72     *s = bswap16(*s);
73 }
74
75 static inline void bswap32s(uint32_t *s)
76 {
77     *s = bswap32(*s);
78 }
79
80 static inline void bswap64s(uint64_t *s)
81 {
82     *s = bswap64(*s);
83 }
84
85 #if defined(HOST_WORDS_BIGENDIAN)
86 #define be_bswap(v, size) (v)
87 #define le_bswap(v, size) bswap ## size(v)
88 #define be_bswaps(v, size)
89 #define le_bswaps(p, size) *p = bswap ## size(*p);
90 #else
91 #define le_bswap(v, size) (v)
92 #define be_bswap(v, size) bswap ## size(v)
93 #define le_bswaps(v, size)
94 #define be_bswaps(p, size) *p = bswap ## size(*p);
95 #endif
96
97 #define CPU_CONVERT(endian, size, type)\
98 static inline type endian ## size ## _to_cpu(type v)\
99 {\
100     return endian ## _bswap(v, size);\
101 }\
102 \
103 static inline type cpu_to_ ## endian ## size(type v)\
104 {\
105     return endian ## _bswap(v, size);\
106 }\
107 \
108 static inline void endian ## size ## _to_cpus(type *p)\
109 {\
110     endian ## _bswaps(p, size)\
111 }\
112 \
113 static inline void cpu_to_ ## endian ## size ## s(type *p)\
114 {\
115     endian ## _bswaps(p, size)\
116 }\
117 \
118 static inline type endian ## size ## _to_cpup(const type *p)\
119 {\
120     return endian ## size ## _to_cpu(*p);\
121 }\
122 \
123 static inline void cpu_to_ ## endian ## size ## w(type *p, type v)\
124 {\
125      *p = cpu_to_ ## endian ## size(v);\
126 }
127
128 CPU_CONVERT(be, 16, uint16_t)
129 CPU_CONVERT(be, 32, uint32_t)
130 CPU_CONVERT(be, 64, uint64_t)
131
132 CPU_CONVERT(le, 16, uint16_t)
133 CPU_CONVERT(le, 32, uint32_t)
134 CPU_CONVERT(le, 64, uint64_t)
135
136 /* unaligned versions (optimized for frequent unaligned accesses)*/
137
138 #if defined(__i386__) || defined(_ARCH_PPC)
139
140 #define cpu_to_le16wu(p, v) cpu_to_le16w(p, v)
141 #define cpu_to_le32wu(p, v) cpu_to_le32w(p, v)
142 #define le16_to_cpupu(p) le16_to_cpup(p)
143 #define le32_to_cpupu(p) le32_to_cpup(p)
144 #define be32_to_cpupu(p) be32_to_cpup(p)
145
146 #define cpu_to_be16wu(p, v) cpu_to_be16w(p, v)
147 #define cpu_to_be32wu(p, v) cpu_to_be32w(p, v)
148 #define cpu_to_be64wu(p, v) cpu_to_be64w(p, v)
149
150 #else
151
152 static inline void cpu_to_le16wu(uint16_t *p, uint16_t v)
153 {
154     uint8_t *p1 = (uint8_t *)p;
155
156     p1[0] = v & 0xff;
157     p1[1] = v >> 8;
158 }
159
160 static inline void cpu_to_le32wu(uint32_t *p, uint32_t v)
161 {
162     uint8_t *p1 = (uint8_t *)p;
163
164     p1[0] = v & 0xff;
165     p1[1] = v >> 8;
166     p1[2] = v >> 16;
167     p1[3] = v >> 24;
168 }
169
170 static inline uint16_t le16_to_cpupu(const uint16_t *p)
171 {
172     const uint8_t *p1 = (const uint8_t *)p;
173     return p1[0] | (p1[1] << 8);
174 }
175
176 static inline uint32_t le32_to_cpupu(const uint32_t *p)
177 {
178     const uint8_t *p1 = (const uint8_t *)p;
179     return p1[0] | (p1[1] << 8) | (p1[2] << 16) | (p1[3] << 24);
180 }
181
182 static inline uint32_t be32_to_cpupu(const uint32_t *p)
183 {
184     const uint8_t *p1 = (const uint8_t *)p;
185     return p1[3] | (p1[2] << 8) | (p1[1] << 16) | (p1[0] << 24);
186 }
187
188 static inline void cpu_to_be16wu(uint16_t *p, uint16_t v)
189 {
190     uint8_t *p1 = (uint8_t *)p;
191
192     p1[0] = v >> 8;
193     p1[1] = v & 0xff;
194 }
195
196 static inline void cpu_to_be32wu(uint32_t *p, uint32_t v)
197 {
198     uint8_t *p1 = (uint8_t *)p;
199
200     p1[0] = v >> 24;
201     p1[1] = v >> 16;
202     p1[2] = v >> 8;
203     p1[3] = v & 0xff;
204 }
205
206 static inline void cpu_to_be64wu(uint64_t *p, uint64_t v)
207 {
208     uint8_t *p1 = (uint8_t *)p;
209
210     p1[0] = v >> 56;
211     p1[1] = v >> 48;
212     p1[2] = v >> 40;
213     p1[3] = v >> 32;
214     p1[4] = v >> 24;
215     p1[5] = v >> 16;
216     p1[6] = v >> 8;
217     p1[7] = v & 0xff;
218 }
219
220 #endif
221
222 #ifdef HOST_WORDS_BIGENDIAN
223 #define cpu_to_32wu cpu_to_be32wu
224 #define leul_to_cpu(v) glue(glue(le,HOST_LONG_BITS),_to_cpu)(v)
225 #else
226 #define cpu_to_32wu cpu_to_le32wu
227 #define leul_to_cpu(v) (v)
228 #endif
229
230 #undef le_bswap
231 #undef be_bswap
232 #undef le_bswaps
233 #undef be_bswaps
234
235 /* len must be one of 1, 2, 4 */
236 static inline uint32_t qemu_bswap_len(uint32_t value, int len)
237 {
238     return bswap32(value) >> (32 - 8 * len);
239 }
240
241 typedef union {
242     float32 f;
243     uint32_t l;
244 } CPU_FloatU;
245
246 typedef union {
247     float64 d;
248 #if defined(HOST_WORDS_BIGENDIAN)
249     struct {
250         uint32_t upper;
251         uint32_t lower;
252     } l;
253 #else
254     struct {
255         uint32_t lower;
256         uint32_t upper;
257     } l;
258 #endif
259     uint64_t ll;
260 } CPU_DoubleU;
261
262 typedef union {
263      floatx80 d;
264      struct {
265          uint64_t lower;
266          uint16_t upper;
267      } l;
268 } CPU_LDoubleU;
269
270 typedef union {
271     float128 q;
272 #if defined(HOST_WORDS_BIGENDIAN)
273     struct {
274         uint32_t upmost;
275         uint32_t upper;
276         uint32_t lower;
277         uint32_t lowest;
278     } l;
279     struct {
280         uint64_t upper;
281         uint64_t lower;
282     } ll;
283 #else
284     struct {
285         uint32_t lowest;
286         uint32_t lower;
287         uint32_t upper;
288         uint32_t upmost;
289     } l;
290     struct {
291         uint64_t lower;
292         uint64_t upper;
293     } ll;
294 #endif
295 } CPU_QuadU;
296
297 /* unaligned/endian-independent pointer access */
298
299 /*
300  * the generic syntax is:
301  *
302  * load: ld{type}{sign}{size}{endian}_p(ptr)
303  *
304  * store: st{type}{size}{endian}_p(ptr, val)
305  *
306  * Note there are small differences with the softmmu access API!
307  *
308  * type is:
309  * (empty): integer access
310  *   f    : float access
311  *
312  * sign is:
313  * (empty): for floats or 32 bit size
314  *   u    : unsigned
315  *   s    : signed
316  *
317  * size is:
318  *   b: 8 bits
319  *   w: 16 bits
320  *   l: 32 bits
321  *   q: 64 bits
322  *
323  * endian is:
324  * (empty): 8 bit access
325  *   be   : big endian
326  *   le   : little endian
327  */
328 static inline int ldub_p(const void *ptr)
329 {
330     return *(uint8_t *)ptr;
331 }
332
333 static inline int ldsb_p(const void *ptr)
334 {
335     return *(int8_t *)ptr;
336 }
337
338 static inline void stb_p(void *ptr, int v)
339 {
340     *(uint8_t *)ptr = v;
341 }
342
343 /* NOTE: on arm, putting 2 in /proc/sys/debug/alignment so that the
344    kernel handles unaligned load/stores may give better results, but
345    it is a system wide setting : bad */
346 #if defined(HOST_WORDS_BIGENDIAN) || defined(WORDS_ALIGNED)
347
348 /* conservative code for little endian unaligned accesses */
349 static inline int lduw_le_p(const void *ptr)
350 {
351 #ifdef _ARCH_PPC
352     int val;
353     __asm__ __volatile__ ("lhbrx %0,0,%1" : "=r" (val) : "r" (ptr));
354     return val;
355 #else
356     const uint8_t *p = ptr;
357     return p[0] | (p[1] << 8);
358 #endif
359 }
360
361 static inline int ldsw_le_p(const void *ptr)
362 {
363 #ifdef _ARCH_PPC
364     int val;
365     __asm__ __volatile__ ("lhbrx %0,0,%1" : "=r" (val) : "r" (ptr));
366     return (int16_t)val;
367 #else
368     const uint8_t *p = ptr;
369     return (int16_t)(p[0] | (p[1] << 8));
370 #endif
371 }
372
373 static inline int ldl_le_p(const void *ptr)
374 {
375 #ifdef _ARCH_PPC
376     int val;
377     __asm__ __volatile__ ("lwbrx %0,0,%1" : "=r" (val) : "r" (ptr));
378     return val;
379 #else
380     const uint8_t *p = ptr;
381     return p[0] | (p[1] << 8) | (p[2] << 16) | (p[3] << 24);
382 #endif
383 }
384
385 static inline uint64_t ldq_le_p(const void *ptr)
386 {
387     const uint8_t *p = ptr;
388     uint32_t v1, v2;
389     v1 = ldl_le_p(p);
390     v2 = ldl_le_p(p + 4);
391     return v1 | ((uint64_t)v2 << 32);
392 }
393
394 static inline void stw_le_p(void *ptr, int v)
395 {
396 #ifdef _ARCH_PPC
397     __asm__ __volatile__ ("sthbrx %1,0,%2" : "=m" (*(uint16_t *)ptr) : "r" (v), "r" (ptr));
398 #else
399     uint8_t *p = ptr;
400     p[0] = v;
401     p[1] = v >> 8;
402 #endif
403 }
404
405 static inline void stl_le_p(void *ptr, int v)
406 {
407 #ifdef _ARCH_PPC
408     __asm__ __volatile__ ("stwbrx %1,0,%2" : "=m" (*(uint32_t *)ptr) : "r" (v), "r" (ptr));
409 #else
410     uint8_t *p = ptr;
411     p[0] = v;
412     p[1] = v >> 8;
413     p[2] = v >> 16;
414     p[3] = v >> 24;
415 #endif
416 }
417
418 static inline void stq_le_p(void *ptr, uint64_t v)
419 {
420     uint8_t *p = ptr;
421     stl_le_p(p, (uint32_t)v);
422     stl_le_p(p + 4, v >> 32);
423 }
424
425 /* float access */
426
427 static inline float32 ldfl_le_p(const void *ptr)
428 {
429     union {
430         float32 f;
431         uint32_t i;
432     } u;
433     u.i = ldl_le_p(ptr);
434     return u.f;
435 }
436
437 static inline void stfl_le_p(void *ptr, float32 v)
438 {
439     union {
440         float32 f;
441         uint32_t i;
442     } u;
443     u.f = v;
444     stl_le_p(ptr, u.i);
445 }
446
447 static inline float64 ldfq_le_p(const void *ptr)
448 {
449     CPU_DoubleU u;
450     u.l.lower = ldl_le_p(ptr);
451     u.l.upper = ldl_le_p(ptr + 4);
452     return u.d;
453 }
454
455 static inline void stfq_le_p(void *ptr, float64 v)
456 {
457     CPU_DoubleU u;
458     u.d = v;
459     stl_le_p(ptr, u.l.lower);
460     stl_le_p(ptr + 4, u.l.upper);
461 }
462
463 #else
464
465 static inline int lduw_le_p(const void *ptr)
466 {
467     return *(uint16_t *)ptr;
468 }
469
470 static inline int ldsw_le_p(const void *ptr)
471 {
472     return *(int16_t *)ptr;
473 }
474
475 static inline int ldl_le_p(const void *ptr)
476 {
477     return *(uint32_t *)ptr;
478 }
479
480 static inline uint64_t ldq_le_p(const void *ptr)
481 {
482     return *(uint64_t *)ptr;
483 }
484
485 static inline void stw_le_p(void *ptr, int v)
486 {
487     *(uint16_t *)ptr = v;
488 }
489
490 static inline void stl_le_p(void *ptr, int v)
491 {
492     *(uint32_t *)ptr = v;
493 }
494
495 static inline void stq_le_p(void *ptr, uint64_t v)
496 {
497     *(uint64_t *)ptr = v;
498 }
499
500 /* float access */
501
502 static inline float32 ldfl_le_p(const void *ptr)
503 {
504     return *(float32 *)ptr;
505 }
506
507 static inline float64 ldfq_le_p(const void *ptr)
508 {
509     return *(float64 *)ptr;
510 }
511
512 static inline void stfl_le_p(void *ptr, float32 v)
513 {
514     *(float32 *)ptr = v;
515 }
516
517 static inline void stfq_le_p(void *ptr, float64 v)
518 {
519     *(float64 *)ptr = v;
520 }
521 #endif
522
523 #if !defined(HOST_WORDS_BIGENDIAN) || defined(WORDS_ALIGNED)
524
525 static inline int lduw_be_p(const void *ptr)
526 {
527 #if defined(__i386__)
528     int val;
529     asm volatile ("movzwl %1, %0\n"
530                   "xchgb %b0, %h0\n"
531                   : "=q" (val)
532                   : "m" (*(uint16_t *)ptr));
533     return val;
534 #else
535     const uint8_t *b = ptr;
536     return ((b[0] << 8) | b[1]);
537 #endif
538 }
539
540 static inline int ldsw_be_p(const void *ptr)
541 {
542 #if defined(__i386__)
543     int val;
544     asm volatile ("movzwl %1, %0\n"
545                   "xchgb %b0, %h0\n"
546                   : "=q" (val)
547                   : "m" (*(uint16_t *)ptr));
548     return (int16_t)val;
549 #else
550     const uint8_t *b = ptr;
551     return (int16_t)((b[0] << 8) | b[1]);
552 #endif
553 }
554
555 static inline int ldl_be_p(const void *ptr)
556 {
557 #if defined(__i386__) || defined(__x86_64__)
558     int val;
559     asm volatile ("movl %1, %0\n"
560                   "bswap %0\n"
561                   : "=r" (val)
562                   : "m" (*(uint32_t *)ptr));
563     return val;
564 #else
565     const uint8_t *b = ptr;
566     return (b[0] << 24) | (b[1] << 16) | (b[2] << 8) | b[3];
567 #endif
568 }
569
570 static inline uint64_t ldq_be_p(const void *ptr)
571 {
572     uint32_t a,b;
573     a = ldl_be_p(ptr);
574     b = ldl_be_p((uint8_t *)ptr + 4);
575     return (((uint64_t)a<<32)|b);
576 }
577
578 static inline void stw_be_p(void *ptr, int v)
579 {
580 #if defined(__i386__)
581     asm volatile ("xchgb %b0, %h0\n"
582                   "movw %w0, %1\n"
583                   : "=q" (v)
584                   : "m" (*(uint16_t *)ptr), "0" (v));
585 #else
586     uint8_t *d = (uint8_t *) ptr;
587     d[0] = v >> 8;
588     d[1] = v;
589 #endif
590 }
591
592 static inline void stl_be_p(void *ptr, int v)
593 {
594 #if defined(__i386__) || defined(__x86_64__)
595     asm volatile ("bswap %0\n"
596                   "movl %0, %1\n"
597                   : "=r" (v)
598                   : "m" (*(uint32_t *)ptr), "0" (v));
599 #else
600     uint8_t *d = (uint8_t *) ptr;
601     d[0] = v >> 24;
602     d[1] = v >> 16;
603     d[2] = v >> 8;
604     d[3] = v;
605 #endif
606 }
607
608 static inline void stq_be_p(void *ptr, uint64_t v)
609 {
610     stl_be_p(ptr, v >> 32);
611     stl_be_p((uint8_t *)ptr + 4, v);
612 }
613
614 /* float access */
615
616 static inline float32 ldfl_be_p(const void *ptr)
617 {
618     union {
619         float32 f;
620         uint32_t i;
621     } u;
622     u.i = ldl_be_p(ptr);
623     return u.f;
624 }
625
626 static inline void stfl_be_p(void *ptr, float32 v)
627 {
628     union {
629         float32 f;
630         uint32_t i;
631     } u;
632     u.f = v;
633     stl_be_p(ptr, u.i);
634 }
635
636 static inline float64 ldfq_be_p(const void *ptr)
637 {
638     CPU_DoubleU u;
639     u.l.upper = ldl_be_p(ptr);
640     u.l.lower = ldl_be_p((uint8_t *)ptr + 4);
641     return u.d;
642 }
643
644 static inline void stfq_be_p(void *ptr, float64 v)
645 {
646     CPU_DoubleU u;
647     u.d = v;
648     stl_be_p(ptr, u.l.upper);
649     stl_be_p((uint8_t *)ptr + 4, u.l.lower);
650 }
651
652 #else
653
654 static inline int lduw_be_p(const void *ptr)
655 {
656     return *(uint16_t *)ptr;
657 }
658
659 static inline int ldsw_be_p(const void *ptr)
660 {
661     return *(int16_t *)ptr;
662 }
663
664 static inline int ldl_be_p(const void *ptr)
665 {
666     return *(uint32_t *)ptr;
667 }
668
669 static inline uint64_t ldq_be_p(const void *ptr)
670 {
671     return *(uint64_t *)ptr;
672 }
673
674 static inline void stw_be_p(void *ptr, int v)
675 {
676     *(uint16_t *)ptr = v;
677 }
678
679 static inline void stl_be_p(void *ptr, int v)
680 {
681     *(uint32_t *)ptr = v;
682 }
683
684 static inline void stq_be_p(void *ptr, uint64_t v)
685 {
686     *(uint64_t *)ptr = v;
687 }
688
689 /* float access */
690
691 static inline float32 ldfl_be_p(const void *ptr)
692 {
693     return *(float32 *)ptr;
694 }
695
696 static inline float64 ldfq_be_p(const void *ptr)
697 {
698     return *(float64 *)ptr;
699 }
700
701 static inline void stfl_be_p(void *ptr, float32 v)
702 {
703     *(float32 *)ptr = v;
704 }
705
706 static inline void stfq_be_p(void *ptr, float64 v)
707 {
708     *(float64 *)ptr = v;
709 }
710
711 #endif
712
713 #endif /* BSWAP_H */