/*---------------------------------------------------------------------------* Project: OS Library File: OSAtomic.h Copyright (C) Nintendo. All rights reserved. These coded instructions, statements, and computer programs contain proprietary information of Nintendo of America Inc. and/or Nintendo Company Ltd., and are protected by Federal copyright law. They may not be disclosed to third parties or copied or duplicated in any form, in whole or in part, without the prior written consent of Nintendo. *---------------------------------------------------------------------------*/ #ifndef __OSATOMIC_H__ #define __OSATOMIC_H__ #ifdef __cplusplus extern "C" { #endif // 32-bit atomics typedef struct OSAtomicVar { union { u32 u32; s32 s32; void* ptr32; } u; } OSAtomicVar; // 32-bit intrinsic atomics #ifndef __ghs__ #define OS_ATOMIC_DONT_INLINE #endif #ifdef OS_ATOMIC_DONT_INLINE s32 OSAddAtomic(volatile OSAtomicVar* ptr, s32 val); u32 OSOrAtomic(volatile OSAtomicVar* ptr, u32 mask); u32 OSAndAtomic(volatile OSAtomicVar* ptr, u32 mask); u32 OSXorAtomic(volatile OSAtomicVar* ptr, u32 mask); u32 OSSwapAtomic(volatile OSAtomicVar* ptr, u32 val); BOOL OSCompareAndSwapAtomic(volatile OSAtomicVar* ptr, u32 cmp_val, u32 new_val); BOOL OSCompareAndSwapAtomicEx(volatile OSAtomicVar* ptr, u32 cmp_val, u32 new_val, u32 *orig_val); BOOL OSTestAndSetAtomic(volatile OSAtomicVar* ptr, u32 bitnum); BOOL OSTestAndClearAtomic(volatile OSAtomicVar* ptr, u32 bitnum); #else inline s32 OSAddAtomic(volatile OSAtomicVar* ptr, s32 val) { s32 orig_val; s32 new_val; while(1) { orig_val = (s32)__LWARX((u32*)&ptr->u.u32, 0); new_val = orig_val + val; __DCBST(0, (u32)ptr); if(__STWCX((u32*)&ptr->u.u32, 0, new_val)) { break; } } return orig_val; } inline u32 OSOrAtomic(volatile OSAtomicVar* ptr, u32 mask) { u32 orig_val; u32 new_val; while(1) { orig_val = (u32)__LWARX((u32*)&ptr->u.u32, 0); new_val = orig_val | mask; __DCBST(0, (u32)ptr); if(__STWCX((u32*)&ptr->u.u32, 0, new_val)) { break; } } return orig_val; } inline u32 OSAndAtomic(volatile OSAtomicVar* ptr, u32 mask) { u32 orig_val; u32 new_val; while(1) { orig_val = (u32)__LWARX((u32*)&ptr->u.u32, 0); new_val = orig_val & mask; __DCBST(0, (u32)ptr); if(__STWCX((u32*)&ptr->u.u32, 0, new_val)) { break; } } return orig_val; } inline u32 OSXorAtomic(volatile OSAtomicVar* ptr, u32 mask) { u32 orig_val; u32 new_val; while(1) { orig_val = (u32)__LWARX((u32*)&ptr->u.u32, 0); new_val = orig_val ^ mask; __DCBST(0, (u32)ptr); if(__STWCX((u32*)&ptr->u.u32, 0, new_val)) { break; } } return orig_val; } inline u32 OSSwapAtomic(volatile OSAtomicVar* ptr, u32 val) { u32 orig_val; while(1) { orig_val = (u32)__LWARX((u32*)&ptr->u.u32, 0); __DCBST(0, (u32)ptr); if(__STWCX((u32*)&ptr->u.u32, 0, val)) { break; } } return orig_val; } inline BOOL OSCompareAndSwapAtomic(volatile OSAtomicVar* ptr, u32 cmp_val, u32 new_val) { u32 orig_val; BOOL ret_val; while(1) { orig_val = (u32)__LWARX((u32*)&ptr->u.u32, 0); if(orig_val == cmp_val) { __DCBST(0, (u32)ptr); if(__STWCX((u32*)&ptr->u.u32, 0, new_val)) { ret_val = TRUE; break; } } else { ret_val = FALSE; break; } } return ret_val; } inline BOOL OSCompareAndSwapAtomicEx(volatile OSAtomicVar* ptr, u32 cmp_val, u32 new_val, u32 *ret_orig_val) { u32 orig_val; BOOL ret_val; while(1) { orig_val = (u32)__LWARX((u32*)&ptr->u.u32, 0); if(orig_val == cmp_val) { __DCBST(0, (u32)ptr); if(__STWCX((u32*)&ptr->u.u32, 0, new_val)) { ret_val = TRUE; break; } } else { ret_val = FALSE; break; } } *ret_orig_val = orig_val; return ret_val; } inline BOOL OSTestAndSetAtomic(volatile OSAtomicVar* ptr, u32 bitnum) { u32 bitmask; u32 orig_val; u32 new_val; BOOL ret_val; bitmask = 1 << bitnum; while(1) { orig_val = (u32)__LWARX((u32*)&ptr->u.u32, 0); new_val = orig_val | bitmask; __DCBST(0, (u32)ptr); if(__STWCX((u32*)&ptr->u.u32, 0, new_val)) { ret_val = (orig_val & bitmask) >> bitnum; break; } } return ret_val; } inline BOOL OSTestAndClearAtomic(volatile OSAtomicVar* ptr, u32 bitnum) { u32 bitmask; u32 orig_val; u32 new_val; BOOL ret_val; bitmask = 1 << bitnum; while(1) { orig_val = (u32)__LWARX((u32*)&ptr->u.u32, 0); new_val = orig_val & (~bitmask); __DCBST(0, (u32)ptr); if(__STWCX((u32*)&ptr->u.u32, 0, new_val)) { ret_val = (orig_val & bitmask) >> bitnum; break; } } return ret_val; } #endif #define OSIncAtomic(ptr) OSAddAtomic(ptr, 1) #define OSDecAtomic(ptr) OSAddAtomic(ptr, -1) // 64-bit atomics typedef struct OSAtomicVar64 { union { u64 __private_u64; s64 __private_s64; } u; } OSAtomicVar64; // 64-bit intrinsic atomics u64 OSGetAtomic64(volatile OSAtomicVar64* ptr); u64 OSSetAtomic64(volatile OSAtomicVar64* ptr, u64 val); s64 OSAddAtomic64(volatile OSAtomicVar64* ptr, s64 val); #define OSIncAtomic64(ptr) OSAddAtomic64(ptr, 1) #define OSDecAtomic64(ptr) OSAddAtomic64(ptr, -1) u64 OSOrAtomic64(volatile OSAtomicVar64* ptr, u64 mask); u64 OSAndAtomic64(volatile OSAtomicVar64* ptr, u64 mask); u64 OSXorAtomic64(volatile OSAtomicVar64* ptr, u64 mask); u64 OSSwapAtomic64(volatile OSAtomicVar64* ptr, u64 val); BOOL OSCompareAndSwapAtomic64(volatile OSAtomicVar64* ptr, u64 cmp_val, u64 new_val); BOOL OSCompareAndSwapAtomicEx64(volatile OSAtomicVar64* ptr, u64 cmp_val, u64 new_val, u64 *orig_val); BOOL OSTestAndSetAtomic64(volatile OSAtomicVar64* ptr, u32 bitnum); BOOL OSTestAndClearAtomic64(volatile OSAtomicVar64* ptr, u32 bitnum); #ifdef __cplusplus } #endif #endif // __OSATOMIC_H__