]> git.buserror.net Git - polintos/scott/priv.git/blob - include/c/lowlevel/arch-ppc/io.h
Initial checkin from Perforce.
[polintos/scott/priv.git] / include / c / lowlevel / arch-ppc / io.h
1 // Byte-swapping, unaligned memory, and I/O port access functions. These
2 // functions are all unprivileged, except the ll_in_* and ll_out_*
3 // functions, whose privilege is architecture-dependent (on PPC and most
4 // other non-x86 architectures, they require the address specified to be
5 // mapped appropriately).
6
7 #ifndef _LL_ARCH_IO_H
8 #define _LL_ARCH_IO_H
9
10 #include <lowlevel/types.h>
11
12 // Unconditional byte-swap
13
14 static inline uint16_t ll_swap16(uint16_t val)
15 {
16         return (uint16_t)val | ((uint16_t)val >> 8) << 8);
17 }
18
19 static inline uint32_t ll_swap32(uint32_t val)
20 {
21         return ((val & 0x000000ff) << 24) |
22                ((val & 0x0000ff00) <<  8) |
23             ((val & 0x00ff0000) >>  8) |
24          ((val & 0xff000000) >> 24);
25 }
26
27 static inline uint64_t ll_swap64(uint64_t val)
28 {
29         return (uint64_t)ll_swap32(val) | ((uint64_t)ll_swap32(val >> 32) << 32);
30 }
31
32 // Conditional byte-swap to/from a specific endianness
33
34 static inline uint64_t ll_swap_be64(uint64_t val)
35 {
36         return val;
37 }
38
39 static inline uint32_t ll_swap_be32(uint32_t val)
40 {
41         return val;
42 }
43
44 static inline uint16_t ll_swap_be16(uint16_t val)
45 {
46         return val;
47 }
48
49 static inline uint64_t ll_swap_le64(uint64_t val)
50 {
51         return ll_swap64(val);
52 }
53
54 static inline uint32_t ll_swap_le32(uint32_t val)
55 {
56         return ll_swap32(val);
57 }
58
59 static inline uint16_t ll_swap_le16(uint16_t val)
60 {
61         return ll_swap16(val);
62 }
63
64 // Unaligned, host-endian
65
66 static inline uint16_t ll_load_unaligned_16(void *addr)
67 {
68         return *(uint16_t *)addr;
69 }
70
71 static inline uint64_t ll_load_unaligned_64(void *addr)
72 {
73         // FIXME: atomic using FP?
74         return *(uint64_t *)addr;
75 }
76
77 static inline uint32_t ll_load_unaligned_32(void *addr)
78 {
79         return *(uint32_t *)addr;
80 }
81
82 static inline void ll_store_unaligned_16(void *addr, uint16_t val)
83 {
84         *(uint16_t *)addr = val;
85 }
86
87 static inline void ll_store_unaligned_64(void *addr, uint64_t val)
88 {
89         // FIXME: atomic using FP?
90         *(uint64_t *)addr = val;
91 }
92
93 static inline void ll_store_unaligned_32(void *addr, uint32_t val)
94 {
95         *(uint32_t *)addr = val;
96 }
97
98 // Unaligned, little-endian
99
100 static inline uint16_t ll_load_unaligned_le16(void *addr)
101 {
102         uint16_t val;
103         asm("lhbrx %0, 0, %1" : "=r" (val) : "r" (addr), "m" (*(uint16_t *)addr));
104         return val;
105 }
106
107 static inline uint32_t ll_load_unaligned_le32(void *addr)
108 {
109         uint32_t val;
110         asm("lwbrx %0, 0, %1" : "=r" (val) : "r" (addr), "m" (*(uint32_t *)addr));
111         return val;
112 }
113
114 static inline uint64_t ll_load_unaligned_le64(void *addr)
115 {
116         // FIXME: atomic using FP?
117         return (uint64_t)ll_load_unaligned_le32(addr) |
118                ((uint64_t)ll_load_unaligned_le32((void *)((char *)addr + 4)) << 32);
119 }
120
121 static inline void ll_store_unaligned_le16(void *addr, uint16_t val)
122 {
123         asm("sthbrx %1, 0, %2" : "=m" (*(uint16_t *)addr) : "r" (val), "r" (addr));
124 }
125
126 static inline void ll_store_unaligned_le32(void *addr, uint32_t val)
127 {
128         asm("stwbrx %1, 0, %2" : "=m" (*(uint32_t *)addr) : "r" (val), "r" (addr));
129 }
130
131 static inline void ll_store_unaligned_le64(void *addr, uint64_t val)
132 {
133         // FIXME: atomic using FP?
134         ll_store_unaligned_le32(addr, (uint32_t)val);
135         ll_store_unaligned_le32((void *)((char *)addr + 4), (uint32_t)(val >> 32));
136 }
137
138 // Aligned, little-endian
139
140 static inline uint64_t ll_load_le64(uint64_t *addr)
141 {
142         return ll_load_unaligned_le64(addr);
143 }
144
145 static inline uint32_t ll_load_le32(uint32_t *addr)
146 {
147         return ll_load_unaligned_le32(addr);
148 }
149
150 static inline uint16_t ll_load_le16(uint16_t *addr)
151 {
152         return ll_load_unaligned_le16(addr);
153 }
154
155 static inline void ll_store_le64(uint64_t *addr, uint64_t val)
156 {
157         ll_store_unaligned_le64(addr, val);
158 }
159
160 static inline void ll_store_le32(uint32_t *addr, uint32_t val)
161 {
162         ll_store_unaligned_le32(addr, val);
163 }
164
165 static inline void ll_store_le16(uint16_t *addr, uint16_t val)
166 {
167         ll_store_unaligned_le16(addr, val);
168 }
169
170 // Unaligned, big-endian
171
172 static inline uint64_t ll_load_unaligned_be64(void *addr)
173 {
174         return ll_load_unaligned_64(addr);
175 }
176
177 static inline uint32_t ll_load_unaligned_be32(void *addr)
178 {
179         return ll_load_unaligned_32(addr);
180 }
181
182 static inline uint16_t ll_load_unaligned_be16(void *addr)
183 {
184         return ll_load_unaligned_16(addr);
185 }
186
187 static inline void ll_store_unaligned_be32(void *addr, uint32_t val)
188 {
189         ll_store_unaligned_32(addr, val);
190 }
191
192 static inline void ll_store_unaligned_be16(void *addr, uint16_t val)
193 {
194         ll_store_unaligned_16(addr, val);
195 }
196
197 // Aligned, big-endian
198
199 static inline uint32_t ll_load_be32(uint32_t *addr)
200 {
201         return ll_load_unaligned_be32(addr);
202 }
203
204 static inline uint16_t ll_load_be16(uint16_t *addr)
205 {
206         return ll_load_unaligned_be16(addr);
207 }
208
209 static inline void ll_store_be32(uint32_t *addr, uint32_t val)
210 {
211         ll_store_unaligned_be32(addr, val);
212 }
213
214 static inline void ll_store_be16(uint16_t *addr, uint16_t val)
215 {
216         ll_store_unaligned_be16(addr, val);
217 }
218
219 // PCI/ISA/similar I/O-space; if memory-mapped, addr must include
220 // the base of the I/O window.
221
222 static inline uint8_t ll_in_8(ulong addr)
223 {
224         return *(uint8_t *)addr;
225 }
226
227 static inline uint16_t ll_in_be16(ulong addr)
228 {
229         return ll_load_be16(addr);
230 }
231
232 static inline uint32_t ll_in_be32(ulong addr)
233 {
234         return ll_load_be32(addr);
235 }
236
237 static inline uint16_t ll_in_le16(ulong addr)
238 {
239         return ll_load_le16(addr);
240 }
241
242 static inline uint32_t ll_in_le32(ulong addr)
243 {
244         return ll_load_le32(addr);
245 }
246
247 static inline void ll_out_8(ulong addr, uint8_t val)
248 {
249         *(uint8_t *)addr = val;
250 }
251
252 static inline void ll_out_be16(ulong addr, uint16_t val)
253 {
254         ll_store_be16(addr, val);
255 }
256
257 static inline void ll_out_be32(ulong addr, uint32_t val)
258 {
259         ll_store_be32(addr, val);
260 }
261
262 static inline void ll_out_le16(ulong addr, uint16_t val)
263 {
264         ll_store_le16(addr, val);
265 }
266
267 static inline void ll_out_le32(ulong addr, uint32_t val)
268 {
269         ll_store_le32(addr, val);
270 }
271         
272 #endif