gcc-armv6+.hpp
Go to the documentation of this file.
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


rosatomic
Author(s): Josh Faust
autogenerated on Sat Dec 28 2013 17:34:27