~ubuntu-branches/ubuntu/quantal/libgc/quantal

« back to all changes in this revision

Viewing changes to libatomic_ops-1.2/src/atomic_ops/sysdeps/armcc/arm_v6.h

  • Committer: Bazaar Package Importer
  • Author(s): Christoph Egger
  • Date: 2011-02-19 12:19:56 UTC
  • mfrom: (1.3.2 upstream) (0.1.5 experimental)
  • mto: This revision was merged to the branch mainline in revision 14.
  • Revision ID: james.westby@ubuntu.com-20110219121956-67rb69xlt5nud3v2
Tags: 1:7.1-5
Upload to unstable

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* 
 
2
 * Copyright (c) 2007 by NEC LE-IT:               All rights reserved.
 
3
 * A transcription of ARMv6 atomic operations for the ARM Realview Toolchain.
 
4
 * This code works with armcc from RVDS 3.1
 
5
 * This is based on work in gcc/arm.h by
 
6
 *   Copyright (c) 1991-1994 by Xerox Corporation.  All rights reserved.
 
7
 *   Copyright (c) 1996-1999 by Silicon Graphics.  All rights reserved.
 
8
 *   Copyright (c) 1999-2003 by Hewlett-Packard Company. All rights reserved.
 
9
 * 
 
10
 *
 
11
 *
 
12
 * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
 
13
 * OR IMPLIED.  ANY USE IS AT YOUR OWN RISK.
 
14
 *
 
15
 * Permission is hereby granted to use or copy this program
 
16
 * for any purpose,  provided the above notices are retained on all copies.
 
17
 * Permission to modify the code and to distribute modified code is granted,
 
18
 * provided the above notices are retained, and a notice that the code was
 
19
 * modified is included with the above copyright notice.
 
20
 *
 
21
 */
 
22
#include "../read_ordered.h"
 
23
#include "../test_and_set_t_is_ao_t.h" /* Probably suboptimal */
 
24
 
 
25
#if __TARGET_ARCH_ARM < 6
 
26
Dont use with ARM instruction sets lower than v6
 
27
#endif
 
28
 
 
29
/* NEC LE-IT: ARMv6 is the first architecture providing support for simple LL/SC
 
30
 * A data memory barrier must be raised via CP15 command (see documentation).   
 
31
 *                                                                                      
 
32
 * ARMv7 is compatible to ARMv6 but has a simpler command for issuing a                 
 
33
 * memory barrier (DMB). Raising it via CP15 should still work as told me by the
 
34
 * support engineers. If it turns out to be much quicker than we should implement
 
35
 * custom code for ARMv7 using the asm { dmb } command.                                 
 
36
 *
 
37
 * If only a single processor is used, we can define AO_UNIPROCESSOR
 
38
 * and do not need to access CP15 for ensuring a DMB at all.
 
39
*/
 
40
 
 
41
AO_INLINE void
 
42
AO_nop_full()
 
43
{
 
44
# ifndef AO_UNIPROCESSOR
 
45
    unsigned int dest=0;
 
46
    /* issue an data memory barrier (keeps ordering of memory transactions      */
 
47
    /* before and after this operation)                                         */
 
48
        __asm { mcr p15,0,dest,c7,c10,5 } ;
 
49
# endif
 
50
}
 
51
 
 
52
#define AO_HAVE_nop_full
 
53
 
 
54
AO_INLINE AO_t
 
55
AO_load(volatile AO_t *addr)
 
56
{
 
57
  /* Cast away the volatile in case it adds fence semantics.            */
 
58
  return (*(AO_t *)addr);
 
59
}
 
60
#define AO_HAVE_load
 
61
 
 
62
/* NEC LE-IT: atomic "store" - according to ARM documentation this is
 
63
 * the only safe way to set variables also used in LL/SC environment.
 
64
 * A direct write won't be recognized by the LL/SC construct in other CPUs.
 
65
 *
 
66
 * HB: Based on subsequent discussion, I think it would be OK to use an
 
67
 * ordinary store here if we knew that interrupt handlers always cleared
 
68
 * the reservation.  They should, but there is some doubt that this is
 
69
 * currently always the case for e.g. Linux.
 
70
*/
 
71
AO_INLINE void AO_store(volatile AO_t *addr, AO_t value)
 
72
{
 
73
        unsigned long tmp;
 
74
        
 
75
retry:
 
76
__asm { 
 
77
                ldrex   tmp, [addr]
 
78
                strex   tmp, value, [addr]
 
79
                teq     tmp, #0
 
80
                bne     retry
 
81
          };
 
82
}
 
83
#define AO_HAVE_store
 
84
 
 
85
/* NEC LE-IT: replace the SWAP as recommended by ARM:
 
86
 
 
87
   "Applies to: ARM11 Cores
 
88
        Though the SWP instruction will still work with ARM V6 cores, it is recommended
 
89
        to use the new V6 synchronization instructions. The SWP instruction produces
 
90
        locked read and write accesses which are atomic, i.e. another operation cannot
 
91
        be done between these locked accesses which ties up external bus (AHB,AXI)
 
92
        bandwidth and can increase worst case interrupt latencies. LDREX,STREX are
 
93
        more flexible, other instructions can be done between the LDREX and STREX accesses. 
 
94
   "
 
95
*/
 
96
AO_INLINE AO_TS_t
 
97
AO_test_and_set(volatile AO_TS_t *addr) {
 
98
        
 
99
        AO_TS_t oldval;
 
100
        unsigned long tmp;
 
101
        unsigned long one = 1;
 
102
retry:
 
103
__asm { 
 
104
                ldrex   oldval, [addr]
 
105
                strex   tmp, one, [addr]
 
106
                teq             tmp, #0
 
107
                bne     retry
 
108
          }
 
109
 
 
110
        return oldval;
 
111
}
 
112
 
 
113
#define AO_HAVE_test_and_set
 
114
 
 
115
/* NEC LE-IT: fetch and add for ARMv6 */
 
116
AO_INLINE AO_t
 
117
AO_fetch_and_add(volatile AO_t *p, AO_t incr)
 
118
{
 
119
        unsigned long tmp,tmp2;
 
120
        AO_t result;
 
121
 
 
122
retry:
 
123
__asm {
 
124
        ldrex   result, [p]
 
125
        add     tmp, incr, result
 
126
        strex   tmp2, tmp, [p]
 
127
        teq     tmp2, #0
 
128
        bne     retry }
 
129
 
 
130
        return result;
 
131
}
 
132
 
 
133
#define AO_HAVE_fetch_and_add
 
134
 
 
135
/* NEC LE-IT: fetch and add1 for ARMv6 */
 
136
AO_INLINE AO_t
 
137
AO_fetch_and_add1(volatile AO_t *p)
 
138
{
 
139
        unsigned long tmp,tmp2;
 
140
        AO_t result;
 
141
 
 
142
retry:
 
143
__asm {
 
144
        ldrex   result, [p]
 
145
        add     tmp, result, #1
 
146
        strex   tmp2, tmp, [p]
 
147
        teq             tmp2, #0
 
148
        bne     retry
 
149
        }
 
150
 
 
151
        return result;
 
152
}
 
153
 
 
154
#define AO_HAVE_fetch_and_add1
 
155
 
 
156
/* NEC LE-IT: fetch and sub for ARMv6 */
 
157
AO_INLINE AO_t
 
158
AO_fetch_and_sub1(volatile AO_t *p)
 
159
{
 
160
        unsigned long tmp,tmp2;
 
161
        AO_t result;
 
162
 
 
163
retry:
 
164
__asm {
 
165
        ldrex   result, [p]
 
166
        sub     tmp, result, #1
 
167
        strex   tmp2, tmp, [p]
 
168
        teq             tmp2, #0
 
169
        bne     retry
 
170
        }
 
171
 
 
172
        return result;
 
173
}
 
174
 
 
175
#define AO_HAVE_fetch_and_sub1
 
176
 
 
177
/* NEC LE-IT: compare and swap */
 
178
/* Returns nonzero if the comparison succeeded. */
 
179
AO_INLINE int
 
180
AO_compare_and_swap(volatile AO_t *addr,
 
181
                                AO_t old_val, AO_t new_val) 
 
182
{
 
183
         AO_t result,tmp;
 
184
 
 
185
retry:
 
186
__asm__ {
 
187
        ldrex   tmp, [addr]
 
188
        mov             result, #2
 
189
        teq             tmp, old_val
 
190
        strexeq result, new_val, [addr]
 
191
        teq             result, #1
 
192
        beq             retry
 
193
        }
 
194
        
 
195
        return (result^2)>>1;
 
196
}
 
197
#define AO_HAVE_compare_and_swap
 
198
 
 
199
#endif // __TARGET_ARCH_ARM