$search
00001 #ifndef BOOST_DETAIL_ATOMIC_GCC_ARMV6P_HPP 00002 #define BOOST_DETAIL_ATOMIC_GCC_ARMV6P_HPP 00003 00004 // Distributed under the Boost Software License, Version 1.0. 00005 // See accompanying file LICENSE_1_0.txt or copy at 00006 // http://www.boost.org/LICENSE_1_0.txt) 00007 // 00008 // Copyright (c) 2009 Helge Bahmann 00009 // Copyright (c) 2009 Phil Endecott 00010 // ARM Code by Phil Endecott, based on other architectures. 00011 00012 // From the ARM Architecture Reference Manual for architecture v6: 00013 // 00014 // LDREX{<cond>} <Rd>, [<Rn>] 00015 // <Rd> Specifies the destination register for the memory word addressed by <Rd> 00016 // <Rn> Specifies the register containing the address. 00017 // 00018 // STREX{<cond>} <Rd>, <Rm>, [<Rn>] 00019 // <Rd> Specifies the destination register for the returned status value. 00020 // 0 if the operation updates memory 00021 // 1 if the operation fails to update memory 00022 // <Rm> Specifies the register containing the word to be stored to memory. 00023 // <Rn> Specifies the register containing the address. 00024 // Rd must not be the same register as Rm or Rn. 00025 // 00026 // ARM v7 is like ARM v6 plus: 00027 // There are half-word and byte versions of the LDREX and STREX instructions, 00028 // LDREXH, LDREXB, STREXH and STREXB. 00029 // There are also double-word versions, LDREXD and STREXD. 00030 // (Actually it looks like these are available from version 6k onwards.) 00031 // FIXME these are not yet used; should be mostly a matter of copy-and-paste. 00032 // I think you can supply an immediate offset to the address. 00033 // 00034 // A memory barrier is effected using a "co-processor 15" instruction, 00035 // though a separate assembler mnemonic is available for it in v7. 00036 00037 #define BOOST_ATOMIC_CHAR_LOCK_FREE 2 00038 #define BOOST_ATOMIC_CHAR16_T_LOCK_FREE 2 00039 #define BOOST_ATOMIC_CHAR32_T_LOCK_FREE 2 00040 #define BOOST_ATOMIC_WCHAR_T_LOCK_FREE 2 00041 #define BOOST_ATOMIC_SHORT_LOCK_FREE 2 00042 #define BOOST_ATOMIC_INT_LOCK_FREE 2 00043 #define BOOST_ATOMIC_LONG_LOCK_FREE 2 00044 #define BOOST_ATOMIC_LLONG_LOCK_FREE 0 00045 #define BOOST_ATOMIC_ADDRESS_LOCK_FREE 2 00046 #define BOOST_ATOMIC_BOOL_LOCK_FREE 2 00047 00048 namespace boost { 00049 namespace detail { 00050 namespace atomic { 00051 00052 // "Thumb 1" is a subset of the ARM instruction set that uses a 16-bit encoding. It 00053 // doesn't include all instructions and in particular it doesn't include the co-processor 00054 // instruction used for the memory barrier or the load-locked/store-conditional 00055 // instructions. So, if we're compiling in "Thumb 1" mode, we need to wrap all of our 00056 // asm blocks with code to temporarily change to ARM mode. 00057 // 00058 // You can only change between ARM and Thumb modes when branching using the bx instruction. 00059 // bx takes an address specified in a register. The least significant bit of the address 00060 // indicates the mode, so 1 is added to indicate that the destination code is Thumb. 00061 // A temporary register is needed for the address and is passed as an argument to these 00062 // macros. It must be one of the "low" registers accessible to Thumb code, specified 00063 // usng the "l" attribute in the asm statement. 00064 // 00065 // Architecture v7 introduces "Thumb 2", which does include (almost?) all of the ARM 00066 // instruction set. So in v7 we don't need to change to ARM mode; we can write "universal 00067 // assembler" which will assemble to Thumb 2 or ARM code as appropriate. The only thing 00068 // we need to do to make this "universal" assembler mode work is to insert "IT" instructions 00069 // to annotate the conditional instructions. These are ignored in other modes (e.g. v6), 00070 // so they can always be present. 00071 00072 #if defined(__thumb__) && !defined(__ARM_ARCH_7A__) 00073 // FIXME also other v7 variants. 00074 #define BOOST_ATOMIC_ARM_ASM_START(TMPREG) "adr " #TMPREG ", 1f\n" "bx " #TMPREG "\n" ".arm\n" ".align 4\n" "1: " 00075 #define BOOST_ATOMIC_ARM_ASM_END(TMPREG) "adr " #TMPREG ", 1f + 1\n" "bx " #TMPREG "\n" ".thumb\n" ".align 2\n" "1: " 00076 00077 #else 00078 // The tmpreg is wasted in this case, which is non-optimal. 00079 #define BOOST_ATOMIC_ARM_ASM_START(TMPREG) 00080 #define BOOST_ATOMIC_ARM_ASM_END(TMPREG) 00081 #endif 00082 00083 #if defined(__ARM_ARCH_7A__) 00084 // FIXME ditto. 00085 #define BOOST_ATOMIC_ARM_DMB "dmb\n" 00086 #else 00087 #define BOOST_ATOMIC_ARM_DMB "mcr\tp15, 0, r0, c7, c10, 5\n" 00088 #endif 00089 00090 static inline void 00091 arm_barrier(void) 00092 { 00093 int brtmp; 00094 __asm__ __volatile__ ( 00095 BOOST_ATOMIC_ARM_ASM_START(%0) 00096 BOOST_ATOMIC_ARM_DMB 00097 BOOST_ATOMIC_ARM_ASM_END(%0) 00098 : "=&l" (brtmp) :: "memory" 00099 ); 00100 } 00101 00102 static inline void 00103 platform_fence_before(memory_order order) 00104 { 00105 switch(order) { 00106 case memory_order_release: 00107 case memory_order_acq_rel: 00108 case memory_order_seq_cst: 00109 arm_barrier(); 00110 case memory_order_consume: 00111 default:; 00112 } 00113 } 00114 00115 static inline void 00116 platform_fence_after(memory_order order) 00117 { 00118 switch(order) { 00119 case memory_order_acquire: 00120 case memory_order_acq_rel: 00121 case memory_order_seq_cst: 00122 arm_barrier(); 00123 default:; 00124 } 00125 } 00126 00127 static inline void 00128 platform_fence_before_store(memory_order order) 00129 { 00130 platform_fence_before(order); 00131 } 00132 00133 static inline void 00134 platform_fence_after_store(memory_order order) 00135 { 00136 if (order == memory_order_seq_cst) 00137 arm_barrier(); 00138 } 00139 00140 static inline void 00141 platform_fence_after_load(memory_order order) 00142 { 00143 platform_fence_after(order); 00144 } 00145 00146 template<typename T> 00147 bool 00148 platform_cmpxchg32(T & expected, T desired, volatile T * ptr) 00149 { 00150 int success; 00151 int tmp; 00152 __asm__ ( 00153 BOOST_ATOMIC_ARM_ASM_START(%2) 00154 "mov %1, #0\n" // success = 0 00155 "ldrex %0, %3\n" // expected' = *(&i) 00156 "teq %0, %4\n" // flags = expected'==expected 00157 "ittt eq\n" 00158 "strexeq %2, %5, %3\n" // if (flags.equal) *(&i) = desired, tmp = !OK 00159 "teqeq %2, #0\n" // if (flags.equal) flags = tmp==0 00160 "moveq %1, #1\n" // if (flags.equal) success = 1 00161 BOOST_ATOMIC_ARM_ASM_END(%2) 00162 : "=&r" (expected), // %0 00163 "=&r" (success), // %1 00164 "=&l" (tmp), // %2 00165 "+Q" (*ptr) // %3 00166 : "r" (expected), // %4 00167 "r" (desired) // %5 00168 : "cc" 00169 ); 00170 return success; 00171 } 00172 00173 00174 } 00175 } 00176 00177 #define BOOST_ATOMIC_THREAD_FENCE 2 00178 static inline void 00179 atomic_thread_fence(memory_order order) 00180 { 00181 switch(order) { 00182 case memory_order_acquire: 00183 case memory_order_release: 00184 case memory_order_acq_rel: 00185 case memory_order_seq_cst: 00186 detail::atomic::arm_barrier(); 00187 default:; 00188 } 00189 } 00190 00191 #define BOOST_ATOMIC_SIGNAL_FENCE 2 00192 static inline void 00193 atomic_signal_fence(memory_order) 00194 { 00195 __asm__ __volatile__ ("" ::: "memory"); 00196 } 00197 00198 } 00199 00200 #undef BOOST_ATOMIC_ARM_ASM_START 00201 #undef BOOST_ATOMIC_ARM_ASM_END 00202 00203 #include <boost/atomic/detail/cas32weak.hpp> 00204 00205 #endif