Update preset.
[bertos.git] / bertos / cpu / byteorder.h
1 /**
2  * \file
3  * <!--
4  * This file is part of BeRTOS.
5  *
6  * Bertos is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
19  *
20  * As a special exception, you may use this file as part of a free software
21  * library without restriction.  Specifically, if other files instantiate
22  * templates or use macros or inline functions from this file, or you compile
23  * this file and link it with other files to produce an executable, this
24  * file does not by itself cause the resulting executable to be covered by
25  * the GNU General Public License.  This exception does not however
26  * invalidate any other reasons why the executable file might be covered by
27  * the GNU General Public License.
28  *
29  * Copyright 2004 Develer S.r.l. (http://www.develer.com/)
30  * -->
31  *
32  * \brief Functions to convert integers to/from host byte-order.
33  *
34  * \author Bernie Innocenti <bernie@codewiz.org>
35  * \author Stefano Fedrigo <aleph@develer.com>
36  */
37
38 #ifndef MWARE_BYTEORDER_H
39 #define MWARE_BYTEORDER_H
40
41 #include <cfg/compiler.h>
42 #include <cpu/attr.h>
43 #include <cpu/detect.h>
44 #include <cpu/types.h>
45 #include <cfg/macros.h>
46
47 /**
48  * Swap upper and lower bytes in a 16-bit value.
49  */
50 #define SWAB16(x) ((uint16_t)(ROTR((x), 8) + \
51                 STATIC_ASSERT_EXPR(sizeof(x) == sizeof(uint16_t))))
52
53 /*
54  * On Cortex-M3, GCC 4.4 builtin implementation is slower than our own
55  * rot-based implementation.
56  */
57 #if GNUC_PREREQ(4, 3) && !CPU_CM3
58 #define SWAB32(x) ((uint32_t)(__builtin_bswap32((x) + \
59                 STATIC_ASSERT_EXPR(sizeof(x) == sizeof(uint32_t)))))
60 #else
61 /**
62  * Reverse bytes in a 32-bit value (e.g.: 0x12345678 -> 0x78563412).
63  */
64 #define SWAB32(x) ((uint32_t)(( \
65         (ROTR(x, 8) & 0xFF00FF00) | \
66         (ROTL(x, 8) & 0x00FF00FF))) + \
67                 STATIC_ASSERT_EXPR(sizeof(x) == sizeof(uint32_t)))
68 #endif
69
70 #if GNUC_PREREQ(4, 3)
71 #define SWAB64(x) ((uint64_t)(__builtin_bswap64((x) + \
72                 STATIC_ASSERT_EXPR(sizeof(x) == sizeof(uint64_t)))))
73 #else
74 /**
75  * Reverse bytes in a 64-bit value.
76  */
77 #define SWAB64(x) ((uint64_t)(                                          \
78         (((uint64_t)(x) & (uint64_t)0x00000000000000ffULL) << 56) |     \
79         (((uint64_t)(x) & (uint64_t)0x000000000000ff00ULL) << 40) |     \
80         (((uint64_t)(x) & (uint64_t)0x0000000000ff0000ULL) << 24) |     \
81         (((uint64_t)(x) & (uint64_t)0x00000000ff000000ULL) <<  8) |     \
82         (((uint64_t)(x) & (uint64_t)0x000000ff00000000ULL) >>  8) |     \
83         (((uint64_t)(x) & (uint64_t)0x0000ff0000000000ULL) >> 24) |     \
84         (((uint64_t)(x) & (uint64_t)0x00ff000000000000ULL) >> 40) |     \
85         (((uint64_t)(x) & (uint64_t)0xff00000000000000ULL) >> 56) +     \
86                 STATIC_ASSERT_EXPR(sizeof(x) == sizeof(uint64_t))))
87 #endif
88
89 #if CPU_BYTE_ORDER == CPU_LITTLE_ENDIAN
90 #define cpu_to_le16(x) ((uint16_t)(x + \
91                 STATIC_ASSERT_EXPR(sizeof(x) == sizeof(uint16_t))))
92 #define cpu_to_le32(x) ((uint32_t)(x + \
93                 STATIC_ASSERT_EXPR(sizeof(x) == sizeof(uint32_t))))
94 #define cpu_to_le64(x) ((uint64_t)(x + \
95                 STATIC_ASSERT_EXPR(sizeof(x) == sizeof(uint64_t))))
96 #define cpu_to_be16(x) SWAB16(x)
97 #define cpu_to_be32(x) SWAB32(x)
98 #define cpu_to_be64(x) SWAB64(x)
99 #elif CPU_BYTE_ORDER == CPU_BIG_ENDIAN
100 #define cpu_to_le16(x) SWAB16(x)
101 #define cpu_to_le32(x) SWAB32(x)
102 #define cpu_to_le64(x) SWAB64(x)
103 #define cpu_to_be16(x) ((uint16_t)(x + \
104                 STATIC_ASSERT_EXPR(sizeof(x) == sizeof(uint16_t))))
105 #define cpu_to_be32(x) ((uint32_t)(x + \
106                 STATIC_ASSERT_EXPR(sizeof(x) == sizeof(uint32_t))))
107 #define cpu_to_be64(x) ((uint64_t)(x + \
108                 STATIC_ASSERT_EXPR(sizeof(x) == sizeof(uint64_t))))
109 #else
110 #error "unrecognized CPU endianness"
111 #endif
112
113 #define be16_to_cpu(x)          cpu_to_be16(x)
114 #define le16_to_cpu(x)          cpu_to_le16(x)
115 #define be32_to_cpu(x)          cpu_to_be32(x)
116 #define le32_to_cpu(x)          cpu_to_le32(x)
117 #define be64_to_cpu(x)          cpu_to_be64(x)
118 #define le64_to_cpu(x)          cpu_to_le64(x)
119
120 #define host_to_net16(x)        cpu_to_be16(x)
121 #define net_to_host16(x)        be16_to_cpu(x)
122 #define host_to_net32(x)        cpu_to_be32(x)
123 #define net_to_host32(x)        be32_to_cpu(x)
124 #define host_to_net64(x)        cpu_to_be64(x)
125 #define net_to_host64(x)        be64_to_cpu(x)
126
127 /**
128  * Reverse bytes in a float value.
129  */
130 INLINE float swab_float(float x)
131 {
132         /* Avoid breaking strict aliasing rules.  */
133         char *cx = (char *)(&x);
134         STATIC_ASSERT(sizeof(float) == 4);
135         #define BYTEORDER_SWAP(a, b) do { (a) ^= (b); (b) ^= (a); (a) ^= (b); } while(0)
136         BYTEORDER_SWAP(cx[0], cx[3]);
137         BYTEORDER_SWAP(cx[1], cx[2]);
138         #undef BYTEORDER_SWAP
139         return x;
140 }
141
142 INLINE float cpu_to_be_float(float x)
143 {
144         return (CPU_BYTE_ORDER == CPU_LITTLE_ENDIAN) ? swab_float(x) : x;
145 }
146
147 INLINE float cpu_to_le_float(float x)
148 {
149         return (CPU_BYTE_ORDER == CPU_BIG_ENDIAN) ? swab_float(x) : x;
150 }
151
152 INLINE float be_float_to_cpu(float x)
153 {
154         return cpu_to_be_float(x);
155 }
156
157 INLINE float le_float_to_cpu(float x)
158 {
159         return cpu_to_le_float(x);
160 }
161
162 INLINE float host_to_net_float(float x)
163 {
164         return cpu_to_be_float(x);
165 }
166
167 INLINE float net_to_host_float(float x)
168 {
169         return be_float_to_cpu(x);
170 }
171
172 #if CPU_ARM
173 INLINE cpu_atomic_t
174 cpu_atomic_xchg(volatile cpu_atomic_t *ptr, cpu_atomic_t val)
175 {
176         cpu_atomic_t ret;
177
178         asm volatile(
179                 "swp     %0, %1, [%2]"
180
181                 : "=&r" (ret)
182                 : "r" (val), "r" (ptr)
183                 : "memory", "cc");
184
185         return ret;
186 }
187 #else /* CPU_ARM */
188 #include <cpu/irq.h>
189
190 INLINE cpu_atomic_t
191 cpu_atomic_xchg(volatile cpu_atomic_t *ptr, cpu_atomic_t val)
192 {
193         cpu_atomic_t ret;
194
195         ATOMIC(
196                 ret = *ptr;
197                 *ptr = val;
198         );
199         return ret;
200 }
201 #endif /* CPU_ARM */
202
203 #ifdef __cplusplus
204
205 /// Type generic byte swapping.
206 template<typename T>
207 INLINE T swab(T x);
208
209 template<> INLINE uint16_t swab(uint16_t x) { return SWAB16(x); }
210 template<> INLINE uint32_t swab(uint32_t x) { return SWAB32(x); }
211 template<> INLINE uint64_t swab(uint64_t x) { return SWAB64(x); }
212 template<> INLINE int16_t  swab(int16_t x)  { return static_cast<int16_t>(SWAB16(static_cast<uint16_t>(x))); }
213 template<> INLINE int32_t  swab(int32_t x)  { return static_cast<int32_t>(SWAB32(static_cast<uint32_t>(x))); }
214 template<> INLINE int64_t  swab(int64_t x)  { return static_cast<int64_t>(SWAB64(static_cast<uint64_t>(x))); }
215 template<> INLINE float    swab(float x)    { return swab_float(x); }
216
217 /// Type generic conversion from CPU byte order to big-endian byte order.
218 template<typename T>
219 INLINE T cpu_to_be(T x)
220 {
221         return (CPU_BYTE_ORDER == CPU_LITTLE_ENDIAN) ? swab(x) : x;
222 }
223
224 /// Type generic conversion from CPU byte-order to little-endian.
225 template<typename T>
226 INLINE T cpu_to_le(T x)
227 {
228         return (CPU_BYTE_ORDER == CPU_BIG_ENDIAN) ? swab(x) : x;
229 }
230
231 /// Type generic conversion from big endian byte-order to CPU byte order.
232 template<typename T>
233 INLINE T be_to_cpu(T x)
234 {
235         return cpu_to_be(x);
236 }
237
238 /// Type generic conversion from little-endian byte order to CPU byte order.
239 template<typename T>
240 INLINE T le_to_cpu(T x)
241 {
242         return cpu_to_le(x);
243 }
244
245 /// Type generic conversion from network byte order to host byte order.
246 template<typename T>
247 INLINE T net_to_host(T x)
248 {
249         return be_to_cpu(x);
250 }
251
252 /// Type generic conversion from host byte order to network byte order.
253 template<typename T>
254 INLINE T host_to_net(T x)
255 {
256         return net_to_host(x);
257 }
258
259 #endif /* __cplusplus */
260
261 #endif /* MWARE_BYTEORDER_H */