1 /*---------------------------------------------------------------------------*
2   Project:  Horizon
3   File:     fnd_Interlocked.cpp
4 
5   Copyright (C)2009-2012 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: 46347 $
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]        // Loads the *pTarget value to r3
34     cmp     r3, r1          // Compares r3 to value.
35     bne     NN_FSYM(2)      // Because branching and clrex cannot conditionally execute
36 
37     // When comparison succeeds
38     strex   r3, r2, [r0]    // Writes swap to *pTarget
39 
40     cmp     r3, #0          // Did writing succeed?
41     bne     NN_BSYM(1)      // Start from the beginning if it failed
42 
43     mov     r0, r1          // Return value is comp because comparison succeeded
44     bx      lr
45 
46     // When comparison fails
47 NN_LSYM(2)
48     clrex                   // Clear exclusive monitoring
49     mov     r0, r3          // Return value is the *pTarget value
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]            // Loads the *pTarget value to r2
59     strex   r3, r1, [r0]        // Writes the value value to *pTarget
60 
61     cmp     r3, #0              // Did writing succeed?
62     bne     NN_BSYM(2)          // Start from the beginning if it failed
63 
64     mov     r0, r2              // Return value is the *pTarget value immediately before writing succeeded
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]            // Loads the *pTarget value to r2
74     add     r2, r2, #1          // Increment r2
75     strex   r3, r2, [r0]        // Writes the r2 value to *pTarget
76 
77     cmp     r3, #0              // Did writing succeed?
78     bne     NN_BSYM(3)          // Start from the beginning if it failed
79 
80     mov     r0, r2              // Return value is the *pTarget value when writing succeeds
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]            // Loads the *pTarget value to r2
90     sub     r2, r2, #1          // Decrement r2
91     strex   r3, r2, [r0]        // Writes the r2 value to *pTarget
92 
93     cmp     r3, #0              // Did writing succeed?
94     bne     NN_BSYM(4)          // Start from the beginning if it failed
95 
96     mov     r0, r2              // Return value is the *pTarget value when writing succeeds
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]            // Loads the *pTarget value to r2
106     add     r2, r2, r1          // Adds value to r2
107     strex   r3, r2, [r0]        // Writes the r2 value to *pTarget
108 
109     cmp     r3, #0              // Did writing succeed?
110     bne     NN_BSYM(5)          // Start from the beginning if it failed
111 
112     mov     r0, r2              // Return value is the *pTarget value when writing succeeds
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]            // Loads the *pTarget value to r2
122     sub     r2, r2, r1          // Subtracts value from r2
123     strex   r3, r2, [r0]        // Writes the r2 value to *pTarget
124 
125     cmp     r3, #0              // Did writing succeed?
126     bne     NN_BSYM(6)          // Start from the beginning if it failed
127 
128     mov     r0, r2              // Return value is the *pTarget value when writing succeeds
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]            // Loads the *pTarget value to r2
138     orr     r2, r2, r1          // OR of r2 and value
139     strex   r3, r2, [r0]        // Writes the r2 value to *pTarget
140 
141     cmp     r3, #0              // Did writing succeed?
142     bne     NN_BSYM(7)          // Start from the beginning if it failed
143 
144     mov     r0, r2              // Return value is the *pTarget value when writing succeeds
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]            // Loads the *pTarget value to r2
154     and     r2, r2, r1          // AND of r2 and value
155     strex   r3, r2, [r0]        // Writes the r2 value to *pTarget
156 
157     cmp     r3, #0              // Did writing succeed?
158     bne     NN_BSYM(8)          // Start from the beginning if it failed
159 
160     mov     r0, r2              // Return value is the *pTarget value when writing succeeds
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]            // Loads the *pTarget value to r2
170     eor     r2, r2, r1          // XOR of r2 and value
171     strex   r3, r2, [r0]        // Writes the r2 value to *pTarget
172 
173     cmp     r3, #0              // Did writing succeed?
174     bne     NN_BSYM(9)          // Start from the beginning if it failed
175 
176     mov     r0, r2              // Return value is the *pTarget value when writing succeeds
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]            // Loads the *pTarget value to r2
186     mvn     r2, r2              // NOT r2
187     strex   r3, r2, [r0]        // Writes the r2 value to *pTarget
188 
189     cmp     r3, #0              // Did writing succeed?
190     bne     NN_BSYM(10)         // Start from the beginning if it failed
191 
192     mov     r0, r2              // Return value is the *pTarget value when writing succeeds
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