/*---------------------------------------------------------------------------* Project: Horizon File: fnd_Interlocked.cpp Copyright (C)2009 Nintendo Co., Ltd. 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. $Rev: 12449 $ *---------------------------------------------------------------------------*/ #include #include #include namespace nn { namespace fnd { namespace ARMv6 { asm s32 Interlocked::CompareAndSwap(s32* pTarget NN_IS_UNUSED_VAR, s32 comp NN_IS_UNUSED_VAR, s32 swap NN_IS_UNUSED_VAR) { PRESERVE8 NN_LSYM(1) ldrex r3, [r0] // *pTarget の値を r3 にロード cmp r3, r1 // r3 を value と比較。 bne NN_FSYM(2) // 分岐、clrex が条件実行できないため // 比較に成功した場合 strex r3, r2, [r0] // swap を *pTarget に書き込み cmp r3, #0 // 書き込みが成功したか? bne NN_BSYM(1) // 失敗なら最初から mov r0, r1 // 比較に成功しているため返り値は comp bx lr // 比較に失敗した場合 NN_LSYM(2) clrex // 排他モニタのクリア mov r0, r3 // 返り値は *pTarget の値 bx lr } asm s32 Interlocked::Swap(s32* pTarget NN_IS_UNUSED_VAR, s32 value NN_IS_UNUSED_VAR) { PRESERVE8 NN_LSYM(2) ldrex r2, [r0] // *pTarget の値を r2 にロード strex r3, r1, [r0] // value の値を *pTarget に書き込み cmp r3, #0 // 書き込みが成功したか? bne NN_BSYM(2) // 失敗なら最初から mov r0, r2 // 書き込みが成功した直前の *pTarget の値を返り値とする bx lr } asm s32 Interlocked::Increment(s32* pTarget NN_IS_UNUSED_VAR) { PRESERVE8 NN_LSYM(3) ldrex r2, [r0] // *pTarget の値を r2 にロード add r2, r2, #1 // r2 をインクリメント strex r3, r2, [r0] // r2 の値を *pTarget に書き込み cmp r3, #0 // 書き込みが成功したか? bne NN_BSYM(3) // 失敗なら最初から mov r0, r2 // 書き込みが成功した時の *pTarget の値を返り値とする bx lr } asm s32 Interlocked::Decrement(s32* pTarget NN_IS_UNUSED_VAR) { PRESERVE8 NN_LSYM(4) ldrex r2, [r0] // *pTarget の値を r2 にロード sub r2, r2, #1 // r2 をデクリメント strex r3, r2, [r0] // r2 の値を *pTarget に書き込み cmp r3, #0 // 書き込みが成功したか? bne NN_BSYM(4) // 失敗なら最初から mov r0, r2 // 書き込みが成功した時の *pTarget の値を返り値とする bx lr } asm s32 Interlocked::Add(s32* pTarget NN_IS_UNUSED_VAR, s32 value NN_IS_UNUSED_VAR) { PRESERVE8 NN_LSYM(5) ldrex r2, [r0] // *pTarget の値を r2 にロード add r2, r2, r1 // r2 に value を加算 strex r3, r2, [r0] // r2 の値を *pTarget に書き込み cmp r3, #0 // 書き込みが成功したか? bne NN_BSYM(5) // 失敗なら最初から mov r0, r2 // 書き込みが成功した時の *pTarget の値を返り値とする bx lr } asm s32 Interlocked::Substract(s32* pTarget NN_IS_UNUSED_VAR, s32 value NN_IS_UNUSED_VAR) { PRESERVE8 NN_LSYM(6) ldrex r2, [r0] // *pTarget の値を r2 にロード sub r2, r2, r1 // r2 から value を減算 strex r3, r2, [r0] // r2 の値を *pTarget に書き込み cmp r3, #0 // 書き込みが成功したか? bne NN_BSYM(6) // 失敗なら最初から mov r0, r2 // 書き込みが成功した時の *pTarget の値を返り値とする bx lr } asm s32 Interlocked::BitwiseOr(s32* pTarget NN_IS_UNUSED_VAR, s32 value NN_IS_UNUSED_VAR) { PRESERVE8 NN_LSYM(7) ldrex r2, [r0] // *pTarget の値を r2 にロード orr r2, r2, r1 // r2 と value を OR strex r3, r2, [r0] // r2 の値を *pTarget に書き込み cmp r3, #0 // 書き込みが成功したか? bne NN_BSYM(7) // 失敗なら最初から mov r0, r2 // 書き込みが成功した時の *pTarget の値を返り値とする bx lr } asm s32 Interlocked::BitwiseAnd(s32* pTarget NN_IS_UNUSED_VAR, s32 value NN_IS_UNUSED_VAR) { PRESERVE8 NN_LSYM(8) ldrex r2, [r0] // *pTarget の値を r2 にロード and r2, r2, r1 // r2 と value を AND strex r3, r2, [r0] // r2 の値を *pTarget に書き込み cmp r3, #0 // 書き込みが成功したか? bne NN_BSYM(8) // 失敗なら最初から mov r0, r2 // 書き込みが成功した時の *pTarget の値を返り値とする bx lr } asm s32 Interlocked::BitwiseXor(s32* pTarget NN_IS_UNUSED_VAR, s32 value NN_IS_UNUSED_VAR) { PRESERVE8 NN_LSYM(9) ldrex r2, [r0] // *pTarget の値を r2 にロード eor r2, r2, r1 // r2 と value を XOR strex r3, r2, [r0] // r2 の値を *pTarget に書き込み cmp r3, #0 // 書き込みが成功したか? bne NN_BSYM(9) // 失敗なら最初から mov r0, r2 // 書き込みが成功した時の *pTarget の値を返り値とする bx lr } asm s32 Interlocked::BitwiseNot(s32* pTarget NN_IS_UNUSED_VAR) { PRESERVE8 NN_LSYM(10) ldrex r2, [r0] // *pTarget の値を r2 にロード mvn r2, r2 // r2 を NOT strex r3, r2, [r0] // r2 の値を *pTarget に書き込み cmp r3, #0 // 書き込みが成功したか? bne NN_BSYM(10) // 失敗なら最初から mov r0, r2 // 書き込みが成功した時の *pTarget の値を返り値とする bx lr } u64 Interlocked::CompareAndSwap(u64* pTarget, const u64& comp, u64 swap) { while (true) { u64 x = __ldrexd(pTarget); if (x == comp) { if (__strexd(swap, pTarget) == 0) { return comp; } } else { __clrex(); return x; } } } } } }