1 /*---------------------------------------------------------------------------*
2   Project:     OS Library
3   File:        OSAtomic.h
4 
5   Copyright (C) 2010-2011 Nintendo.  All rights reserved.
6 
7   These coded instructions, statements, and computer programs contain
8   proprietary information of Nintendo of America Inc. and/or Nintendo
9   Company Ltd., and are protected by Federal copyright law.  They may
10   not be disclosed to third parties or copied or duplicated in any form,
11   in whole or in part, without the prior written consent of Nintendo.
12 
13  *---------------------------------------------------------------------------*/
14 
15 #ifndef __OSATOMIC_H__
16 #define __OSATOMIC_H__
17 
18 #ifdef __cplusplus
19 extern "C" {
20 #endif
21 
22 // 32-bit atomics
23 
24 typedef struct OSAtomicVar
25 {
26     union {
27         u32   u32;
28         s32   s32;
29         void* ptr32;
30     } u;
31 } OSAtomicVar;
32 
33 // 32-bit intrinsic atomics
34 
35 #ifndef __ghs__
36 #define OS_ATOMIC_DONT_INLINE
37 #endif
38 
39 #ifdef OS_ATOMIC_DONT_INLINE
40 s32     OSAddAtomic(volatile OSAtomicVar* ptr, s32 val);
41 u32     OSOrAtomic(volatile OSAtomicVar* ptr, u32 mask);
42 u32     OSAndAtomic(volatile OSAtomicVar* ptr, u32 mask);
43 u32     OSXorAtomic(volatile OSAtomicVar* ptr, u32 mask);
44 
45 u32     OSSwapAtomic(volatile OSAtomicVar* ptr, u32 val);
46 BOOL    OSCompareAndSwapAtomic(volatile OSAtomicVar* ptr, u32 cmp_val, u32 new_val);
47 BOOL    OSCompareAndSwapAtomicEx(volatile OSAtomicVar* ptr, u32 cmp_val, u32 new_val, u32 *orig_val);
48 
49 BOOL    OSTestAndSetAtomic(volatile OSAtomicVar* ptr, u32 bitnum);
50 BOOL    OSTestAndClearAtomic(volatile OSAtomicVar* ptr, u32 bitnum);
51 #else
52 
OSAddAtomic(volatile OSAtomicVar * ptr,s32 val)53 inline s32 OSAddAtomic(volatile OSAtomicVar* ptr, s32 val)
54 {
55   s32 orig_val;
56   s32 new_val;
57 
58   while(1) {
59     orig_val = (s32)__LWARX((u32*)&ptr->u.u32, 0);
60     new_val = orig_val + val;
61     __DCBST(0, (u32)ptr);
62     if(__STWCX((u32*)&ptr->u.u32, 0, new_val)) {
63       break;
64     }
65   }
66 
67   return orig_val;
68 }
69 
OSOrAtomic(volatile OSAtomicVar * ptr,u32 mask)70 inline u32 OSOrAtomic(volatile OSAtomicVar* ptr, u32 mask)
71 {
72   u32 orig_val;
73   u32 new_val;
74 
75   while(1) {
76     orig_val = (u32)__LWARX((u32*)&ptr->u.u32, 0);
77     new_val = orig_val | mask;
78     __DCBST(0, (u32)ptr);
79     if(__STWCX((u32*)&ptr->u.u32, 0, new_val)) {
80       break;
81     }
82   }
83 
84   return orig_val;
85 }
86 
OSAndAtomic(volatile OSAtomicVar * ptr,u32 mask)87 inline u32 OSAndAtomic(volatile OSAtomicVar* ptr, u32 mask)
88 {
89   u32 orig_val;
90   u32 new_val;
91 
92   while(1) {
93     orig_val = (u32)__LWARX((u32*)&ptr->u.u32, 0);
94     new_val = orig_val & mask;
95     __DCBST(0, (u32)ptr);
96     if(__STWCX((u32*)&ptr->u.u32, 0, new_val)) {
97       break;
98     }
99   }
100 
101   return orig_val;
102 }
103 
OSXorAtomic(volatile OSAtomicVar * ptr,u32 mask)104 inline u32 OSXorAtomic(volatile OSAtomicVar* ptr, u32 mask)
105 {
106   u32 orig_val;
107   u32 new_val;
108 
109   while(1) {
110     orig_val = (u32)__LWARX((u32*)&ptr->u.u32, 0);
111     new_val = orig_val ^ mask;
112     __DCBST(0, (u32)ptr);
113     if(__STWCX((u32*)&ptr->u.u32, 0, new_val)) {
114       break;
115     }
116   }
117 
118   return orig_val;
119 }
120 
OSSwapAtomic(volatile OSAtomicVar * ptr,u32 val)121 inline u32 OSSwapAtomic(volatile OSAtomicVar* ptr, u32 val)
122 {
123   u32 orig_val;
124 
125   while(1) {
126     orig_val = (u32)__LWARX((u32*)&ptr->u.u32, 0);
127     __DCBST(0, (u32)ptr);
128     if(__STWCX((u32*)&ptr->u.u32, 0, val)) {
129       break;
130     }
131   }
132 
133   return orig_val;
134 }
135 
OSCompareAndSwapAtomic(volatile OSAtomicVar * ptr,u32 cmp_val,u32 new_val)136 inline BOOL OSCompareAndSwapAtomic(volatile OSAtomicVar* ptr, u32 cmp_val, u32 new_val)
137 {
138   u32 orig_val;
139   BOOL ret_val;
140 
141   while(1) {
142     orig_val = (u32)__LWARX((u32*)&ptr->u.u32, 0);
143     if(orig_val == cmp_val) {
144       __DCBST(0, (u32)ptr);
145       if(__STWCX((u32*)&ptr->u.u32, 0, new_val)) {
146 	ret_val = TRUE;
147 	break;
148       }
149     } else {
150       ret_val = FALSE;
151       break;
152     }
153   }
154 
155   return ret_val;
156 }
157 
OSCompareAndSwapAtomicEx(volatile OSAtomicVar * ptr,u32 cmp_val,u32 new_val,u32 * ret_orig_val)158 inline BOOL OSCompareAndSwapAtomicEx(volatile OSAtomicVar* ptr, u32 cmp_val, u32 new_val, u32 *ret_orig_val)
159 {
160   u32 orig_val;
161   BOOL ret_val;
162 
163   while(1) {
164     orig_val = (u32)__LWARX((u32*)&ptr->u.u32, 0);
165     if(orig_val == cmp_val) {
166       __DCBST(0, (u32)ptr);
167       if(__STWCX((u32*)&ptr->u.u32, 0, new_val)) {
168 	ret_val = TRUE;
169 	break;
170       }
171     } else {
172       ret_val = FALSE;
173       break;
174     }
175   }
176 
177   *ret_orig_val = orig_val;
178 
179   return ret_val;
180 }
181 
OSTestAndSetAtomic(volatile OSAtomicVar * ptr,u32 bitnum)182 inline BOOL OSTestAndSetAtomic(volatile OSAtomicVar* ptr, u32 bitnum)
183 {
184   u32 bitmask;
185   u32 orig_val;
186   u32 new_val;
187   BOOL ret_val;
188 
189   bitmask = 1 << bitnum;
190 
191   while(1) {
192     orig_val = (u32)__LWARX((u32*)&ptr->u.u32, 0);
193     new_val = orig_val | bitmask;
194     __DCBST(0, (u32)ptr);
195     if(__STWCX((u32*)&ptr->u.u32, 0, new_val)) {
196       ret_val = (orig_val & bitmask) >> bitnum;
197       break;
198     }
199   }
200 
201   return ret_val;
202 }
203 
OSTestAndClearAtomic(volatile OSAtomicVar * ptr,u32 bitnum)204 inline BOOL OSTestAndClearAtomic(volatile OSAtomicVar* ptr, u32 bitnum)
205 {
206   u32 bitmask;
207   u32 orig_val;
208   u32 new_val;
209   BOOL ret_val;
210 
211   bitmask = 1 << bitnum;
212 
213   while(1) {
214     orig_val = (u32)__LWARX((u32*)&ptr->u.u32, 0);
215     new_val = orig_val & (~bitmask);
216     __DCBST(0, (u32)ptr);
217     if(__STWCX((u32*)&ptr->u.u32, 0, new_val)) {
218       ret_val = (orig_val & bitmask) >> bitnum;
219       break;
220     }
221   }
222 
223   return ret_val;
224 }
225 #endif
226 
227 #define OSIncAtomic(ptr) OSAddAtomic(ptr, 1)
228 #define OSDecAtomic(ptr) OSAddAtomic(ptr, -1)
229 
230 
231 // 64-bit atomics
232 
233 typedef struct OSAtomicVar64
234 {
235     union {
236         u64   __private_u64;
237         s64   __private_s64;
238     } u;
239 } OSAtomicVar64;
240 
241 // 64-bit intrinsic atomics
242 
243 u64 OSGetAtomic64(volatile OSAtomicVar64* ptr);
244 u64 OSSetAtomic64(volatile OSAtomicVar64* ptr, u64 val);
245 
246 s64     OSAddAtomic64(volatile OSAtomicVar64* ptr, s64 val);
247 #define OSIncAtomic64(ptr) OSAddAtomic64(ptr, 1)
248 #define OSDecAtomic64(ptr) OSAddAtomic64(ptr, -1)
249 
250 u64     OSOrAtomic64(volatile OSAtomicVar64* ptr, u64 mask);
251 u64     OSAndAtomic64(volatile OSAtomicVar64* ptr, u64 mask);
252 u64     OSXorAtomic64(volatile OSAtomicVar64* ptr, u64 mask);
253 
254 u64     OSSwapAtomic64(volatile OSAtomicVar64* ptr, u64 val);
255 BOOL    OSCompareAndSwapAtomic64(volatile OSAtomicVar64* ptr, u64 cmp_val, u64 new_val);
256 BOOL    OSCompareAndSwapAtomicEx64(volatile OSAtomicVar64* ptr, u64 cmp_val, u64 new_val, u64 *orig_val);
257 
258 BOOL    OSTestAndSetAtomic64(volatile OSAtomicVar64* ptr, u32 bitnum);
259 BOOL    OSTestAndClearAtomic64(volatile OSAtomicVar64* ptr, u32 bitnum);
260 
261 #ifdef __cplusplus
262 }
263 #endif
264 
265 #endif // __OSATOMIC_H__
266 
267