Statistics
| Branch: | Revision:

root / include / qemu / bswap.h @ a5c82852

History | View | Annotate | Download (8.1 kB)

1
#ifndef BSWAP_H
2
#define BSWAP_H
3

    
4
#include "config-host.h"
5
#include <inttypes.h>
6
#include <limits.h>
7
#include <string.h>
8
#include "fpu/softfloat.h"
9

    
10
#ifdef CONFIG_MACHINE_BSWAP_H
11
# include <sys/endian.h>
12
# include <sys/types.h>
13
# include <machine/bswap.h>
14
#elif defined(CONFIG_BYTESWAP_H)
15
# include <byteswap.h>
16

    
17
static inline uint16_t bswap16(uint16_t x)
18
{
19
    return bswap_16(x);
20
}
21

    
22
static inline uint32_t bswap32(uint32_t x)
23
{
24
    return bswap_32(x);
25
}
26

    
27
static inline uint64_t bswap64(uint64_t x)
28
{
29
    return bswap_64(x);
30
}
31
# else
32
static inline uint16_t bswap16(uint16_t x)
33
{
34
    return (((x & 0x00ff) << 8) |
35
            ((x & 0xff00) >> 8));
36
}
37

    
38
static inline uint32_t bswap32(uint32_t x)
39
{
40
    return (((x & 0x000000ffU) << 24) |
41
            ((x & 0x0000ff00U) <<  8) |
42
            ((x & 0x00ff0000U) >>  8) |
43
            ((x & 0xff000000U) >> 24));
44
}
45

    
46
static inline uint64_t bswap64(uint64_t x)
47
{
48
    return (((x & 0x00000000000000ffULL) << 56) |
49
            ((x & 0x000000000000ff00ULL) << 40) |
50
            ((x & 0x0000000000ff0000ULL) << 24) |
51
            ((x & 0x00000000ff000000ULL) <<  8) |
52
            ((x & 0x000000ff00000000ULL) >>  8) |
53
            ((x & 0x0000ff0000000000ULL) >> 24) |
54
            ((x & 0x00ff000000000000ULL) >> 40) |
55
            ((x & 0xff00000000000000ULL) >> 56));
56
}
57
#endif /* ! CONFIG_MACHINE_BSWAP_H */
58

    
59
static inline void bswap16s(uint16_t *s)
60
{
61
    *s = bswap16(*s);
62
}
63

    
64
static inline void bswap32s(uint32_t *s)
65
{
66
    *s = bswap32(*s);
67
}
68

    
69
static inline void bswap64s(uint64_t *s)
70
{
71
    *s = bswap64(*s);
72
}
73

    
74
#if defined(HOST_WORDS_BIGENDIAN)
75
#define be_bswap(v, size) (v)
76
#define le_bswap(v, size) glue(bswap, size)(v)
77
#define be_bswaps(v, size)
78
#define le_bswaps(p, size) do { *p = glue(bswap, size)(*p); } while(0)
79
#else
80
#define le_bswap(v, size) (v)
81
#define be_bswap(v, size) glue(bswap, size)(v)
82
#define le_bswaps(v, size)
83
#define be_bswaps(p, size) do { *p = glue(bswap, size)(*p); } while(0)
84
#endif
85

    
86
#define CPU_CONVERT(endian, size, type)\
87
static inline type endian ## size ## _to_cpu(type v)\
88
{\
89
    return glue(endian, _bswap)(v, size);\
90
}\
91
\
92
static inline type cpu_to_ ## endian ## size(type v)\
93
{\
94
    return glue(endian, _bswap)(v, size);\
95
}\
96
\
97
static inline void endian ## size ## _to_cpus(type *p)\
98
{\
99
    glue(endian, _bswaps)(p, size);\
100
}\
101
\
102
static inline void cpu_to_ ## endian ## size ## s(type *p)\
103
{\
104
    glue(endian, _bswaps)(p, size);\
105
}\
106
\
107
static inline type endian ## size ## _to_cpup(const type *p)\
108
{\
109
    return glue(glue(endian, size), _to_cpu)(*p);\
110
}\
111
\
112
static inline void cpu_to_ ## endian ## size ## w(type *p, type v)\
113
{\
114
    *p = glue(glue(cpu_to_, endian), size)(v);\
115
}
116

    
117
CPU_CONVERT(be, 16, uint16_t)
118
CPU_CONVERT(be, 32, uint32_t)
119
CPU_CONVERT(be, 64, uint64_t)
120

    
121
CPU_CONVERT(le, 16, uint16_t)
122
CPU_CONVERT(le, 32, uint32_t)
123
CPU_CONVERT(le, 64, uint64_t)
124

    
125
/* len must be one of 1, 2, 4 */
126
static inline uint32_t qemu_bswap_len(uint32_t value, int len)
127
{
128
    return bswap32(value) >> (32 - 8 * len);
129
}
130

    
131
/* Unions for reinterpreting between floats and integers.  */
132

    
133
typedef union {
134
    float32 f;
135
    uint32_t l;
136
} CPU_FloatU;
137

    
138
typedef union {
139
    float64 d;
140
#if defined(HOST_WORDS_BIGENDIAN)
141
    struct {
142
        uint32_t upper;
143
        uint32_t lower;
144
    } l;
145
#else
146
    struct {
147
        uint32_t lower;
148
        uint32_t upper;
149
    } l;
150
#endif
151
    uint64_t ll;
152
} CPU_DoubleU;
153

    
154
typedef union {
155
     floatx80 d;
156
     struct {
157
         uint64_t lower;
158
         uint16_t upper;
159
     } l;
160
} CPU_LDoubleU;
161

    
162
typedef union {
163
    float128 q;
164
#if defined(HOST_WORDS_BIGENDIAN)
165
    struct {
166
        uint32_t upmost;
167
        uint32_t upper;
168
        uint32_t lower;
169
        uint32_t lowest;
170
    } l;
171
    struct {
172
        uint64_t upper;
173
        uint64_t lower;
174
    } ll;
175
#else
176
    struct {
177
        uint32_t lowest;
178
        uint32_t lower;
179
        uint32_t upper;
180
        uint32_t upmost;
181
    } l;
182
    struct {
183
        uint64_t lower;
184
        uint64_t upper;
185
    } ll;
186
#endif
187
} CPU_QuadU;
188

    
189
/* unaligned/endian-independent pointer access */
190

    
191
/*
192
 * the generic syntax is:
193
 *
194
 * load: ld{type}{sign}{size}{endian}_p(ptr)
195
 *
196
 * store: st{type}{size}{endian}_p(ptr, val)
197
 *
198
 * Note there are small differences with the softmmu access API!
199
 *
200
 * type is:
201
 * (empty): integer access
202
 *   f    : float access
203
 *
204
 * sign is:
205
 * (empty): for floats or 32 bit size
206
 *   u    : unsigned
207
 *   s    : signed
208
 *
209
 * size is:
210
 *   b: 8 bits
211
 *   w: 16 bits
212
 *   l: 32 bits
213
 *   q: 64 bits
214
 *
215
 * endian is:
216
 * (empty): host endian
217
 *   be   : big endian
218
 *   le   : little endian
219
 */
220

    
221
static inline int ldub_p(const void *ptr)
222
{
223
    return *(uint8_t *)ptr;
224
}
225

    
226
static inline int ldsb_p(const void *ptr)
227
{
228
    return *(int8_t *)ptr;
229
}
230

    
231
static inline void stb_p(void *ptr, int v)
232
{
233
    *(uint8_t *)ptr = v;
234
}
235

    
236
/* Any compiler worth its salt will turn these memcpy into native unaligned
237
   operations.  Thus we don't need to play games with packed attributes, or
238
   inline byte-by-byte stores.  */
239

    
240
static inline int lduw_p(const void *ptr)
241
{
242
    uint16_t r;
243
    memcpy(&r, ptr, sizeof(r));
244
    return r;
245
}
246

    
247
static inline int ldsw_p(const void *ptr)
248
{
249
    int16_t r;
250
    memcpy(&r, ptr, sizeof(r));
251
    return r;
252
}
253

    
254
static inline void stw_p(void *ptr, uint16_t v)
255
{
256
    memcpy(ptr, &v, sizeof(v));
257
}
258

    
259
static inline int ldl_p(const void *ptr)
260
{
261
    int32_t r;
262
    memcpy(&r, ptr, sizeof(r));
263
    return r;
264
}
265

    
266
static inline void stl_p(void *ptr, uint32_t v)
267
{
268
    memcpy(ptr, &v, sizeof(v));
269
}
270

    
271
static inline uint64_t ldq_p(const void *ptr)
272
{
273
    uint64_t r;
274
    memcpy(&r, ptr, sizeof(r));
275
    return r;
276
}
277

    
278
static inline void stq_p(void *ptr, uint64_t v)
279
{
280
    memcpy(ptr, &v, sizeof(v));
281
}
282

    
283
static inline int lduw_le_p(const void *ptr)
284
{
285
    return (uint16_t)le_bswap(lduw_p(ptr), 16);
286
}
287

    
288
static inline int ldsw_le_p(const void *ptr)
289
{
290
    return (int16_t)le_bswap(lduw_p(ptr), 16);
291
}
292

    
293
static inline int ldl_le_p(const void *ptr)
294
{
295
    return le_bswap(ldl_p(ptr), 32);
296
}
297

    
298
static inline uint64_t ldq_le_p(const void *ptr)
299
{
300
    return le_bswap(ldq_p(ptr), 64);
301
}
302

    
303
static inline void stw_le_p(void *ptr, int v)
304
{
305
    stw_p(ptr, le_bswap(v, 16));
306
}
307

    
308
static inline void stl_le_p(void *ptr, int v)
309
{
310
    stl_p(ptr, le_bswap(v, 32));
311
}
312

    
313
static inline void stq_le_p(void *ptr, uint64_t v)
314
{
315
    stq_p(ptr, le_bswap(v, 64));
316
}
317

    
318
/* float access */
319

    
320
static inline float32 ldfl_le_p(const void *ptr)
321
{
322
    CPU_FloatU u;
323
    u.l = ldl_le_p(ptr);
324
    return u.f;
325
}
326

    
327
static inline void stfl_le_p(void *ptr, float32 v)
328
{
329
    CPU_FloatU u;
330
    u.f = v;
331
    stl_le_p(ptr, u.l);
332
}
333

    
334
static inline float64 ldfq_le_p(const void *ptr)
335
{
336
    CPU_DoubleU u;
337
    u.ll = ldq_le_p(ptr);
338
    return u.d;
339
}
340

    
341
static inline void stfq_le_p(void *ptr, float64 v)
342
{
343
    CPU_DoubleU u;
344
    u.d = v;
345
    stq_le_p(ptr, u.ll);
346
}
347

    
348
static inline int lduw_be_p(const void *ptr)
349
{
350
    return (uint16_t)be_bswap(lduw_p(ptr), 16);
351
}
352

    
353
static inline int ldsw_be_p(const void *ptr)
354
{
355
    return (int16_t)be_bswap(lduw_p(ptr), 16);
356
}
357

    
358
static inline int ldl_be_p(const void *ptr)
359
{
360
    return be_bswap(ldl_p(ptr), 32);
361
}
362

    
363
static inline uint64_t ldq_be_p(const void *ptr)
364
{
365
    return be_bswap(ldq_p(ptr), 64);
366
}
367

    
368
static inline void stw_be_p(void *ptr, int v)
369
{
370
    stw_p(ptr, be_bswap(v, 16));
371
}
372

    
373
static inline void stl_be_p(void *ptr, int v)
374
{
375
    stl_p(ptr, be_bswap(v, 32));
376
}
377

    
378
static inline void stq_be_p(void *ptr, uint64_t v)
379
{
380
    stq_p(ptr, be_bswap(v, 64));
381
}
382

    
383
/* float access */
384

    
385
static inline float32 ldfl_be_p(const void *ptr)
386
{
387
    CPU_FloatU u;
388
    u.l = ldl_be_p(ptr);
389
    return u.f;
390
}
391

    
392
static inline void stfl_be_p(void *ptr, float32 v)
393
{
394
    CPU_FloatU u;
395
    u.f = v;
396
    stl_be_p(ptr, u.l);
397
}
398

    
399
static inline float64 ldfq_be_p(const void *ptr)
400
{
401
    CPU_DoubleU u;
402
    u.ll = ldq_be_p(ptr);
403
    return u.d;
404
}
405

    
406
static inline void stfq_be_p(void *ptr, float64 v)
407
{
408
    CPU_DoubleU u;
409
    u.d = v;
410
    stq_be_p(ptr, u.ll);
411
}
412

    
413
static inline unsigned long leul_to_cpu(unsigned long v)
414
{
415
    /* In order to break an include loop between here and
416
       qemu-common.h, don't rely on HOST_LONG_BITS.  */
417
#if ULONG_MAX == UINT32_MAX
418
    return le_bswap(v, 32);
419
#elif ULONG_MAX == UINT64_MAX
420
    return le_bswap(v, 64);
421
#else
422
# error Unknown sizeof long
423
#endif
424
}
425

    
426
#undef le_bswap
427
#undef be_bswap
428
#undef le_bswaps
429
#undef be_bswaps
430

    
431
#endif /* BSWAP_H */