1/*
2** Copyright 2003, Axel D��rfler, axeld@pinc-software.de. All rights reserved.
3** Distributed under the terms of the MIT License.
4*/
5
6#include <asm_defs.h>
7
8/*
9 * gcc/config/m68k/m68k.h:CALL_USED_REGISTERS:
10 * d0,d1,a0,a1 are scratch regs, not to be saved.
11 */
12
13/*
14 * see http://mail-index.netbsd.org/amiga/1995/06/
15 * for concerns about TAS, CAS and Amiga.
16 * I suppose as long as we don't use it on a variable in
17 * chip ram it shouldn't be a problem, and since we don't
18 * have any SMP Amiga anyway it should be ok.
19 */
20
21.text
22
23/* int atomic_add(int *value, int increment)
24 */
25FUNCTION(atomic_add):
26		move.l	(4,%a7),%a0
27		move.l	(%a0),%d0
28miss1:	move.l	%d0,%d1
29		add.l	(8,%a7),%d1
30		cas.l	%d0,%d1,(%a0)
31		bne		miss1
32		// d0 = old value
33		rts
34FUNCTION_END(atomic_add)
35
36/* int atomic_and(int *value, int andValue)
37 */
38FUNCTION(atomic_and):
39		move.l	(4,%a7),%a0
40		move.l	(%a0),%d0
41miss2:	move.l	%d0,%d1
42		and.l	(8,%a7),%d1
43		cas.l	%d0,%d1,(%a0)
44		bne		miss2
45		// d0 = old value
46		rts
47FUNCTION_END(atomic_and)
48
49/* int atomic_or(int *value, int orValue)
50 */
51FUNCTION(atomic_or):
52		move.l	(4,%a7),%a0
53		move.l	(%a0),%d0
54miss3:	move.l	%d0,%d1
55		or.l	(8,%a7),%d1
56		cas.l	%d0,%d1,(%a0)
57		bne		miss3
58		rts
59FUNCTION_END(atomic_or)
60
61/* int atomic_set(int *value, int setTo)
62 */
63FUNCTION(atomic_set):
64		move.l	(4,%a7),%a0
65		move.l	(%a0),%d0
66		move.l	(8,%a7),%d1
67miss4:	cas.l	%d0,%d1,(%a0)
68		bne		miss4
69		rts
70FUNCTION_END(atomic_set)
71
72/* int atomic_test_and_set(int *value, int setTo, int testValue)
73 */
74FUNCTION(atomic_test_and_set):
75		move.l	(4,%a7),%a0
76		move.l	(8,%a7),%d1
77		move.l	(12,%a7),%d0
78		cas.l	%d0,%d1,(%a0)
79		rts
80FUNCTION_END(atomic_test_and_set)
81
82/* int atomic_get(int *value)
83 */
84FUNCTION(atomic_get):
85		move.l	(4,%a7),%a0
86		move.l	(%a0),%d0
87		move.l	%d0,%d1
88		cas.l	%d0,%d1,(%a0)
89		// we must use cas... so we change to the same value if matching,
90		// else we get the correct one anyway
91		rts
92FUNCTION_END(atomic_get)
93
94/* m68k elf convention is to return structs in (a0)
95 * but use d0/d1 for int64 and small structs.
96 * d0 MSB, d1 LSB
97 */
98#warning M68K: 68060 doesn't have CAS2: use spinlock ??
99/* see http://retropc.net/x68000/software/develop/as/has060/m68k.htm */
100
101/* int64	atomic_add64(vint64 *value, int64 addValue) */
102FUNCTION(atomic_add64):
103		movem.l	%d2-%d3/%a2,-(%a7)
104		move.l	(4,%a7),%a2
105		lea.l	(4,%a2),%a1
106		// addValue
107		move.l	(12,%a7),%d3	/*LSB*/
108		move.l	(8,%a7),%d2		/*MSB*/
109miss5:	// old value
110		move.l	(%a1),%d1		/*LSB*/
111		move.l	(%a2),%d0		/*MSB*/
112		add.l	%d1,%d3
113		addx.l	%d0,%d2
114		cas2.l	%d0:%d1,%d2:%d3,(%a2):(%a1)
115		bne		miss5
116		// return value d0:d1
117		movem.l	(%a7)+,%d2-%d3/%a2
118		rts
119FUNCTION_END(atomic_add64)
120
121/* int64	atomic_and64(vint64 *value, int64 andValue) */
122FUNCTION(atomic_and64):
123		movem.l	%d2-%d3/%a2,-(%a7)
124		move.l	(4,%a7),%a2
125		lea.l	(4,%a2),%a1
126		// addValue
127		move.l	(12,%a7),%d3	/*LSB*/
128		move.l	(8,%a7),%d2		/*MSB*/
129miss6:	// old value
130		move.l	(%a1),%d1		/*LSB*/
131		move.l	(%a2),%d0		/*MSB*/
132		and.l	%d1,%d3
133		and.l	%d0,%d2
134		cas2.l	%d0:%d1,%d2:%d3,(%a2):(%a1)
135		bne		miss6
136		// return value d0:d1
137		movem.l	(%a7)+,%d2-%d3/%a2
138		rts
139FUNCTION_END(atomic_and64)
140
141/* int64	atomic_or64(vint64 *value, int64 orValue) */
142FUNCTION(atomic_or64):
143		movem.l	%d2-%d3/%a2,-(%a7)
144		move.l	(4,%a7),%a2
145		lea.l	(4,%a2),%a1
146		// addValue
147		move.l	(12,%a7),%d3	/*LSB*/
148		move.l	(8,%a7),%d2		/*MSB*/
149miss7:	// old value
150		move.l	(%a1),%d1		/*LSB*/
151		move.l	(%a2),%d0		/*MSB*/
152		or.l	%d1,%d3
153		or.l	%d0,%d2
154		cas2.l	%d0:%d1,%d2:%d3,(%a2):(%a1)
155		bne		miss7
156		// return value d0:d1
157		movem.l	(%a7)+,%d2-%d3/%a2
158		rts
159FUNCTION_END(atomic_or64)
160
161/* int64	atomic_set64(vint64 *value, int64 newValue) */
162FUNCTION(atomic_set64):
163		movem.l	%d2-%d3/%a2,-(%a7)
164		move.l	(4,%a7),%a2
165		lea.l	(4,%a2),%a1
166		// new value
167		move.l	(12,%a7),%d3	/*LSB*/
168		move.l	(8,%a7),%d2		/*MSB*/
169		// old value
170		move.l	(%a1),%d1		/*LSB*/
171		move.l	(%a2),%d0		/*MSB*/
172miss8:	cas2.l	%d0:%d1,%d2:%d3,(%a2):(%a1)
173		bne		miss8
174		// return value d0:d1
175		movem.l	(%a7)+,%d2-%d3/%a2
176		rts
177FUNCTION_END(atomic_set64)
178
179/* int64	atomic_test_and_set64(vint64 *value, int64 newValue, int64 testAgainst) */
180FUNCTION(atomic_test_and_set64):
181		movem.l	%d2-%d3/%a2,-(%a7)
182		move.l	(4,%a7),%a2
183		lea.l	(4,%a2),%a1
184		// new value
185		move.l	(12,%a7),%d3	/*LSB*/
186		move.l	(8,%a7),%d2		/*MSB*/
187		// test against value
188		move.l	(20,%a7),%d1	/*LSB*/
189		move.l	(16,%a7),%d0	/*MSB*/
190		cas2.l	%d0:%d1,%d2:%d3,(%a2):(%a1)
191		// return value d0:d1
192		movem.l	(%a7)+,%d2-%d3/%a2
193		rts
194FUNCTION_END(atomic_test_and_set64)
195
196/* int64	atomic_get64(vint64 *value) */
197FUNCTION(atomic_get64):
198		movem.l	%d2-%d3/%a2,-(%a7)
199		move.l	(4,%a7),%a2
200		lea.l	(4,%a2),%a1
201		move.l	(%a1),%d1	/*LSB*/
202		move.l	(%a2),%d0		/*MSB*/
203		move.l	%d1,%d3
204		move.l	%d0,%d2
205		// we must use cas... so we change to the same value if matching,
206		// else we get the correct one anyway
207		cas2.l	%d0:%d1,%d2:%d3,(%a2):(%a1)
208		// return value
209		movem.l	(%a7)+,%d2-%d3/%a2
210		rts
211FUNCTION_END(atomic_get64)
212.text
213
214#warning IMPLEMENT GCC 64-bit ATOMICS ON m68k!
215
216/* These are to fill in 64-bit atomic calls emitted by
217 * by GCC when 64-bit atomics are unavailable.
218 */
219
220FUNCTION(__atomic_fetch_add_8):
221		nop
222		rts
223FUNCTION_END(__atomic_fetch_add_8)
224
225FUNCTION(__atomic_store_8):
226		nop
227		rts
228FUNCTION_END(__atomic_store_8)
229
230FUNCTION(__atomic_load_8):
231		nop
232		rts
233FUNCTION_END(__atomic_load_8)
234
235