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