source: rtems/cpukit/score/cpu/sparc/sparcv8-atomic.c @ 1f7c5c88

5
Last change on this file since 1f7c5c88 was 1f7c5c88, checked in by Sebastian Huber <sebastian.huber@…>, on 09/25/15 at 19:31:00

score: Fix atomic compare exchange

  • Property mode set to 100644
File size: 3.8 KB
Line 
1/*
2 * Copyright (c) 2014-2015 embedded brains GmbH.  All rights reserved.
3 *
4 *  embedded brains GmbH
5 *  Dornierstr. 4
6 *  82178 Puchheim
7 *  Germany
8 *  <rtems@embedded-brains.de>
9 *
10 * The license and distribution terms for this file may be
11 * found in the file LICENSE in this distribution or at
12 * http://www.rtems.org/license/LICENSE.
13 */
14
15#if HAVE_CONFIG_H
16  #include "config.h"
17#endif
18
19#include <rtems/score/cpuopts.h>
20#include <rtems/score/isrlevel.h>
21
22/*
23 * This file is a dirty hack.  A proper solution would be to add RTEMS support
24 * for libatomic in GCC (see also libatomic/configure.tgt).
25 */
26
27#if defined(RTEMS_SMP)
28static volatile uint32_t _SPARCV8_The_one_lock;
29
30static inline uint32_t _SPARCV8_Atomic_swap(
31  volatile uint32_t *address,
32  uint32_t value
33)
34{
35  asm volatile (
36    "swap [%2], %0"
37    : "=r" (value)
38    : "0" (value), "r" (address)
39    : "memory"
40  );
41
42  return value;
43}
44#endif
45
46static ISR_Level _SPARCV8_Acquire_the_one_lock( void )
47{
48  ISR_Level level;
49
50  _ISR_Disable_without_giant( level );
51
52#if defined(RTEMS_SMP)
53  do {
54    while ( _SPARCV8_The_one_lock ) {
55      /* Wait */
56    }
57  } while ( _SPARCV8_Atomic_swap( &_SPARCV8_The_one_lock, 1 ) );
58#endif
59
60  return level;
61}
62
63static void _SPARCV8_Release_the_one_lock( ISR_Level level )
64{
65#if defined(RTEMS_SMP)
66  _SPARCV8_The_one_lock = 0;
67#endif
68  _ISR_Enable_without_giant( level );
69}
70
71uint8_t __atomic_exchange_1( uint8_t *mem, uint8_t val, int model )
72{
73  uint8_t prev;
74  ISR_Level level;
75
76  level = _SPARCV8_Acquire_the_one_lock();
77
78  prev = *mem;
79  *mem = val;
80
81  _SPARCV8_Release_the_one_lock( level );
82
83  return prev;
84}
85
86/*
87 * In order to get rid of the warning "conflicting types for built-in function
88 * '__atomic_compare_exchange_4' [enabled by default]", you must port libatomic
89 * to SPARC/RTEMS.  The libatomic is provided by GCC.
90 */
91uint32_t __atomic_exchange_4( uint32_t *mem, uint32_t val, int model )
92{
93  uint32_t prev;
94  ISR_Level level;
95
96  level = _SPARCV8_Acquire_the_one_lock();
97
98  prev = *mem;
99  *mem = val;
100
101  _SPARCV8_Release_the_one_lock( level );
102
103  return prev;
104}
105
106/*
107 * You get probably a warning here which can be ignored: "warning: conflicting
108 * types for built-in function '__atomic_compare_exchange_4' [enabled by
109 * default]"
110 */
111bool __atomic_compare_exchange_4(
112  uint32_t *mem,
113  uint32_t *expected,
114  uint32_t desired,
115  int success,
116  int failure
117)
118{
119  bool equal;
120  ISR_Level level;
121  uint32_t actual;
122
123  level = _SPARCV8_Acquire_the_one_lock();
124
125  actual = *mem;
126  equal = ( actual == *expected );
127  if ( equal ) {
128    *mem = desired;
129  } else {
130    *expected = actual;
131  }
132
133  _SPARCV8_Release_the_one_lock( level );
134
135  return equal;
136}
137
138uint32_t __atomic_fetch_add_4( uint32_t *mem, uint32_t val, int model )
139{
140  uint32_t prev;
141  ISR_Level level;
142
143  level = _SPARCV8_Acquire_the_one_lock();
144
145  prev = *mem;
146  *mem = prev + val;
147
148  _SPARCV8_Release_the_one_lock( level );
149
150  return prev;
151}
152
153uint32_t __atomic_fetch_sub_4( uint32_t *mem, uint32_t val, int model )
154{
155  uint32_t prev;
156  ISR_Level level;
157
158  level = _SPARCV8_Acquire_the_one_lock();
159
160  prev = *mem;
161  *mem = prev - val;
162
163  _SPARCV8_Release_the_one_lock( level );
164
165  return prev;
166}
167
168uint32_t __atomic_fetch_and_4( uint32_t *mem, uint32_t val, int model )
169{
170  uint32_t prev;
171  ISR_Level level;
172
173  level = _SPARCV8_Acquire_the_one_lock();
174
175  prev = *mem;
176  *mem = prev & val;
177
178  _SPARCV8_Release_the_one_lock( level );
179
180  return prev;
181}
182
183uint32_t __atomic_fetch_or_4( uint32_t *mem, uint32_t val, int model )
184{
185  uint32_t prev;
186  ISR_Level level;
187
188  level = _SPARCV8_Acquire_the_one_lock();
189
190  prev = *mem;
191  *mem = prev | val;
192
193  _SPARCV8_Release_the_one_lock( level );
194
195  return prev;
196}
197
198uint32_t __atomic_fetch_xor_4( uint32_t *mem, uint32_t val, int model )
199{
200  uint32_t prev;
201  ISR_Level level;
202
203  level = _SPARCV8_Acquire_the_one_lock();
204
205  prev = *mem;
206  *mem = prev ^ val;
207
208  _SPARCV8_Release_the_one_lock( level );
209
210  return prev;
211}
Note: See TracBrowser for help on using the repository browser.