1 /*---------------------------------------------------------------------------*
2 Project: OS Library
3 File: OSAtomic.h
4
5 Copyright (C) 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