1 /*---------------------------------------------------------------------------*
2   Project:  Horizon
3   File:     fnd_Interlocked.cpp
4 
5   Copyright (C)2009 Nintendo Co., Ltd.  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   $Rev: 12449 $
14  *---------------------------------------------------------------------------*/
15 
16 #include <nn/config.h>
17 #include <nn/fnd/ARMv6/fnd_Interlocked.h>
18 
19 #include <nn/hw/ARM/code32.h>
20 
21 namespace nn
22 {
23     namespace fnd
24     {
25         namespace ARMv6
26         {
27 
CompareAndSwap(s32 * pTarget NN_IS_UNUSED_VAR,s32 comp NN_IS_UNUSED_VAR,s32 swap NN_IS_UNUSED_VAR)28 asm s32 Interlocked::CompareAndSwap(s32* pTarget NN_IS_UNUSED_VAR, s32 comp NN_IS_UNUSED_VAR, s32 swap NN_IS_UNUSED_VAR)
29 {
30     PRESERVE8
31 
32 NN_LSYM(1)
33     ldrex   r3, [r0]        // *pTarget の値を r3 にロード
34     cmp     r3, r1          // r3 を value と比較。
35     bne     NN_FSYM(2)      // 分岐、clrex が条件実行できないため
36 
37     // 比較に成功した場合
38     strex   r3, r2, [r0]    // swap を *pTarget に書き込み
39 
40     cmp     r3, #0          // 書き込みが成功したか?
41     bne     NN_BSYM(1)      // 失敗なら最初から
42 
43     mov     r0, r1          // 比較に成功しているため返り値は comp
44     bx      lr
45 
46     // 比較に失敗した場合
47 NN_LSYM(2)
48     clrex                   // 排他モニタのクリア
49     mov     r0, r3          // 返り値は *pTarget の値
50     bx      lr
51 }
52 
Swap(s32 * pTarget NN_IS_UNUSED_VAR,s32 value NN_IS_UNUSED_VAR)53 asm s32 Interlocked::Swap(s32* pTarget NN_IS_UNUSED_VAR, s32 value NN_IS_UNUSED_VAR)
54 {
55     PRESERVE8
56 
57 NN_LSYM(2)
58     ldrex   r2, [r0]            // *pTarget の値を r2 にロード
59     strex   r3, r1, [r0]        // value の値を *pTarget に書き込み
60 
61     cmp     r3, #0              // 書き込みが成功したか?
62     bne     NN_BSYM(2)          // 失敗なら最初から
63 
64     mov     r0, r2              // 書き込みが成功した直前の *pTarget の値を返り値とする
65     bx      lr
66 }
67 
Increment(s32 * pTarget NN_IS_UNUSED_VAR)68 asm s32 Interlocked::Increment(s32* pTarget NN_IS_UNUSED_VAR)
69 {
70     PRESERVE8
71 
72 NN_LSYM(3)
73     ldrex   r2, [r0]            // *pTarget の値を r2 にロード
74     add     r2, r2, #1          // r2 をインクリメント
75     strex   r3, r2, [r0]        // r2 の値を *pTarget に書き込み
76 
77     cmp     r3, #0              // 書き込みが成功したか?
78     bne     NN_BSYM(3)          // 失敗なら最初から
79 
80     mov     r0, r2              // 書き込みが成功した時の *pTarget の値を返り値とする
81     bx      lr
82 }
83 
Decrement(s32 * pTarget NN_IS_UNUSED_VAR)84 asm s32 Interlocked::Decrement(s32* pTarget NN_IS_UNUSED_VAR)
85 {
86     PRESERVE8
87 
88 NN_LSYM(4)
89     ldrex   r2, [r0]            // *pTarget の値を r2 にロード
90     sub     r2, r2, #1          // r2 をデクリメント
91     strex   r3, r2, [r0]        // r2 の値を *pTarget に書き込み
92 
93     cmp     r3, #0              // 書き込みが成功したか?
94     bne     NN_BSYM(4)          // 失敗なら最初から
95 
96     mov     r0, r2              // 書き込みが成功した時の *pTarget の値を返り値とする
97     bx      lr
98 }
99 
Add(s32 * pTarget NN_IS_UNUSED_VAR,s32 value NN_IS_UNUSED_VAR)100 asm s32 Interlocked::Add(s32* pTarget NN_IS_UNUSED_VAR, s32 value NN_IS_UNUSED_VAR)
101 {
102     PRESERVE8
103 
104 NN_LSYM(5)
105     ldrex   r2, [r0]            // *pTarget の値を r2 にロード
106     add     r2, r2, r1          // r2 に value を加算
107     strex   r3, r2, [r0]        // r2 の値を *pTarget に書き込み
108 
109     cmp     r3, #0              // 書き込みが成功したか?
110     bne     NN_BSYM(5)          // 失敗なら最初から
111 
112     mov     r0, r2              // 書き込みが成功した時の *pTarget の値を返り値とする
113     bx      lr
114 }
115 
Substract(s32 * pTarget NN_IS_UNUSED_VAR,s32 value NN_IS_UNUSED_VAR)116 asm s32 Interlocked::Substract(s32* pTarget NN_IS_UNUSED_VAR, s32 value NN_IS_UNUSED_VAR)
117 {
118     PRESERVE8
119 
120 NN_LSYM(6)
121     ldrex   r2, [r0]            // *pTarget の値を r2 にロード
122     sub     r2, r2, r1          // r2 から value を減算
123     strex   r3, r2, [r0]        // r2 の値を *pTarget に書き込み
124 
125     cmp     r3, #0              // 書き込みが成功したか?
126     bne     NN_BSYM(6)          // 失敗なら最初から
127 
128     mov     r0, r2              // 書き込みが成功した時の *pTarget の値を返り値とする
129     bx      lr
130 }
131 
BitwiseOr(s32 * pTarget NN_IS_UNUSED_VAR,s32 value NN_IS_UNUSED_VAR)132 asm s32 Interlocked::BitwiseOr(s32* pTarget NN_IS_UNUSED_VAR, s32 value NN_IS_UNUSED_VAR)
133 {
134     PRESERVE8
135 
136 NN_LSYM(7)
137     ldrex   r2, [r0]            // *pTarget の値を r2 にロード
138     orr     r2, r2, r1          // r2 と value を OR
139     strex   r3, r2, [r0]        // r2 の値を *pTarget に書き込み
140 
141     cmp     r3, #0              // 書き込みが成功したか?
142     bne     NN_BSYM(7)          // 失敗なら最初から
143 
144     mov     r0, r2              // 書き込みが成功した時の *pTarget の値を返り値とする
145     bx      lr
146 }
147 
BitwiseAnd(s32 * pTarget NN_IS_UNUSED_VAR,s32 value NN_IS_UNUSED_VAR)148 asm s32 Interlocked::BitwiseAnd(s32* pTarget NN_IS_UNUSED_VAR, s32 value NN_IS_UNUSED_VAR)
149 {
150     PRESERVE8
151 
152 NN_LSYM(8)
153     ldrex   r2, [r0]            // *pTarget の値を r2 にロード
154     and     r2, r2, r1          // r2 と value を AND
155     strex   r3, r2, [r0]        // r2 の値を *pTarget に書き込み
156 
157     cmp     r3, #0              // 書き込みが成功したか?
158     bne     NN_BSYM(8)          // 失敗なら最初から
159 
160     mov     r0, r2              // 書き込みが成功した時の *pTarget の値を返り値とする
161     bx      lr
162 }
163 
BitwiseXor(s32 * pTarget NN_IS_UNUSED_VAR,s32 value NN_IS_UNUSED_VAR)164 asm s32 Interlocked::BitwiseXor(s32* pTarget NN_IS_UNUSED_VAR, s32 value NN_IS_UNUSED_VAR)
165 {
166     PRESERVE8
167 
168 NN_LSYM(9)
169     ldrex   r2, [r0]            // *pTarget の値を r2 にロード
170     eor     r2, r2, r1          // r2 と value を XOR
171     strex   r3, r2, [r0]        // r2 の値を *pTarget に書き込み
172 
173     cmp     r3, #0              // 書き込みが成功したか?
174     bne     NN_BSYM(9)          // 失敗なら最初から
175 
176     mov     r0, r2              // 書き込みが成功した時の *pTarget の値を返り値とする
177     bx      lr
178 }
179 
BitwiseNot(s32 * pTarget NN_IS_UNUSED_VAR)180 asm s32 Interlocked::BitwiseNot(s32* pTarget NN_IS_UNUSED_VAR)
181 {
182     PRESERVE8
183 
184 NN_LSYM(10)
185     ldrex   r2, [r0]            // *pTarget の値を r2 にロード
186     mvn     r2, r2              // r2 を NOT
187     strex   r3, r2, [r0]        // r2 の値を *pTarget に書き込み
188 
189     cmp     r3, #0              // 書き込みが成功したか?
190     bne     NN_BSYM(10)         // 失敗なら最初から
191 
192     mov     r0, r2              // 書き込みが成功した時の *pTarget の値を返り値とする
193     bx      lr
194 }
195 
CompareAndSwap(u64 * pTarget,const u64 & comp,u64 swap)196 u64 Interlocked::CompareAndSwap(u64* pTarget, const u64& comp, u64 swap)
197 {
198     while (true)
199     {
200         u64 x = __ldrexd(pTarget);
201         if (x == comp)
202         {
203             if (__strexd(swap, pTarget) == 0)
204             {
205                 return comp;
206             }
207         }
208         else
209         {
210             __clrex();
211             return x;
212         }
213     }
214 }
215 
216         }
217     }
218 }
219 
220