fix typo in filename used in sh port
[musl] / arch / sh / src / atomic.c
1 #include "libc.h"
2
3 #define LLSC_CLOBBERS   "r0", "t", "memory"
4 #define LLSC_START(mem)            \
5         "0:     movli.l @" mem ", r0\n"
6 #define LLSC_END(mem)              \
7         "1:     movco.l r0, @" mem "\n"    \
8         "       bf 0b\n"                   \
9         "       synco\n"
10
11 /* gusa is a hack in the kernel which lets you create a sequence of instructions
12  * which will be restarted if the process is preempted in the middle of the
13  * sequence. It will do for implementing atomics on non-smp systems. ABI is:
14  * r0  = address of first instruction after the atomic sequence
15  * r1  = original stack pointer
16  * r15 = -1 * length of atomic sequence in bytes
17  */
18 #define GUSA_CLOBBERS   "r0", "r1", "memory"
19 #define GUSA_START(mem,old,nop)    \
20         "       .align 2\n"                \
21         "       mova 1f, r0\n"             \
22         nop                            \
23         "       mov r15, r1\n"             \
24         "       mov #(0f-1f), r15\n"       \
25         "0:     mov.l @" mem ", " old "\n"
26 /* the target of mova must be 4 byte aligned, so we may need a nop */
27 #define GUSA_START_ODD(mem,old)  GUSA_START(mem,old,"")
28 #define GUSA_START_EVEN(mem,old) GUSA_START(mem,old,"\tnop\n")
29 #define GUSA_END(mem,new)          \
30         "       mov.l " new ", @" mem "\n" \
31         "1:     mov r1, r15\n"
32
33 #define CPU_HAS_LLSC 0x0040
34
35 int __sh_cas(volatile int *p, int t, int s)
36 {
37         int old;
38         if (__hwcap & CPU_HAS_LLSC) {
39                 __asm__ __volatile__(
40                         LLSC_START("%1")
41                         "       mov r0, %0\n"
42                         "       cmp/eq %0, %2\n"
43                         "       bf 1f\n"
44                         "       mov %3, r0\n"
45                         LLSC_END("%1")
46                         : "=&r"(old) : "r"(p), "r"(t), "r"(s) : LLSC_CLOBBERS);
47         } else {
48                 __asm__ __volatile__(
49                         GUSA_START_EVEN("%1", "%0")
50                         "       cmp/eq %0, %2\n"
51                         "       bf 1f\n"
52                         GUSA_END("%1", "%3")
53                         : "=&r"(old) : "r"(p), "r"(t), "r"(s) : GUSA_CLOBBERS, "t");
54         }
55         return old;
56 }
57
58 int __sh_swap(volatile int *x, int v)
59 {
60         int old;
61         if (__hwcap & CPU_HAS_LLSC) {
62                 __asm__ __volatile__(
63                         LLSC_START("%1")
64                         "       mov r0, %0\n"
65                         "       mov %2, r0\n"
66                         LLSC_END("%1")
67                         : "=&r"(old) : "r"(x), "r"(v) : LLSC_CLOBBERS);
68         } else {
69                 __asm__ __volatile__(
70                         GUSA_START_EVEN("%1", "%0")
71                         GUSA_END("%1", "%2")
72                         : "=&r"(old) : "r"(x), "r"(v) : GUSA_CLOBBERS);
73         }
74         return old;
75 }
76
77 int __sh_fetch_add(volatile int *x, int v)
78 {
79         int old, dummy;
80         if (__hwcap & CPU_HAS_LLSC) {
81                 __asm__ __volatile__(
82                         LLSC_START("%1")
83                         "       mov r0, %0\n"
84                         "       add %2, r0\n"
85                         LLSC_END("%1")
86                         : "=&r"(old) : "r"(x), "r"(v) : LLSC_CLOBBERS);
87         } else {
88                 __asm__ __volatile__(
89                         GUSA_START_EVEN("%2", "%0")
90                         "       mov %0, %1\n"
91                         "       add %3, %1\n"
92                         GUSA_END("%2", "%1")
93                         : "=&r"(old), "=&r"(dummy) : "r"(x), "r"(v) : GUSA_CLOBBERS);
94         }
95         return old;
96 }
97
98 void __sh_store(volatile int *p, int x)
99 {
100         if (__hwcap & CPU_HAS_LLSC) {
101                 __asm__ __volatile__(
102                         "       mov.l %1, @%0\n"
103                         "       synco\n"
104                         : : "r"(p), "r"(x) : "memory");
105         } else {
106                 __asm__ __volatile__(
107                         "       mov.l %1, @%0\n"
108                         : : "r"(p), "r"(x) : "memory");
109         }
110 }
111
112 void __sh_and(volatile int *x, int v)
113 {
114         int dummy;
115         if (__hwcap & CPU_HAS_LLSC) {
116                 __asm__ __volatile__(
117                         LLSC_START("%0")
118                         "       and %1, r0\n"
119                         LLSC_END("%0")
120                         : : "r"(x), "r"(v) : LLSC_CLOBBERS);
121         } else {
122                 __asm__ __volatile__(
123                         GUSA_START_ODD("%1", "%0")
124                         "       and %2, %0\n"
125                         GUSA_END("%1", "%0")
126                         : "=&r"(dummy) : "r"(x), "r"(v) : GUSA_CLOBBERS);
127         }
128 }
129
130 void __sh_or(volatile int *x, int v)
131 {
132         int dummy;
133         if (__hwcap & CPU_HAS_LLSC) {
134                 __asm__ __volatile__(
135                         LLSC_START("%0")
136                         "       or %1, r0\n"
137                         LLSC_END("%0")
138                         : : "r"(x), "r"(v) : LLSC_CLOBBERS);
139         } else {
140                 __asm__ __volatile__(
141                         GUSA_START_ODD("%1", "%0")
142                         "       or %2, %0\n"
143                         GUSA_END("%1", "%0")
144                         : "=&r"(dummy) : "r"(x), "r"(v) : GUSA_CLOBBERS);
145         }
146 }