//////////////////////////////////////////////////////////////////////////////// // / // 2012-2020 (c) Baical / // / // This library is free software; you can redistribute it and/or / // modify it under the terms of the GNU Lesser General Public / // License as published by the Free Software Foundation; either / // version 3.0 of the License, or (at your option) any later version. / // / // This library is distributed in the hope that it will be useful, / // but WITHOUT ANY WARRANTY; without even the implied warranty of / // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU / // Lesser General Public License for more details. / // / // You should have received a copy of the GNU Lesser General Public / // License along with this library. / // / //////////////////////////////////////////////////////////////////////////////// #ifndef PATOMIC_H #define PATOMIC_H #ifdef __ARM_ARCH_5TEJ__ //Source: //http://svn.dd-wrt.com/browser/src/linux/xscale/linux-2.6.23/arch/arm/kernel/entry-armv.S?rev=8329 // Reference prototype: // // int __kernel_cmpxchg(int oldval, int newval, int *ptr) // // Input: // // r0 = oldval // r1 = newval // r2 = ptr // lr = return address // // Output: // // r0 = returned value (zero or non-zero) // C flag = set if r0 == 0, clear if r0 != 0 // // Clobbered: // // r3, ip, flags // // Definition and user space usage example: // // typedef int (__kernel_cmpxchg_t)(int oldval, int newval, int *ptr); // #define __kernel_cmpxchg (*(__kernel_cmpxchg_t *)0xffff0fc0) // // Atomically store newval in *ptr if *ptr is equal to oldval for user space. // Return zero if *ptr was changed or non-zero if no exchange happened. // The C flag is also set if *ptr was changed to allow for assembly // optimization in the calling code. // // Notes: // // - This routine already includes memory barriers as needed. // // - A failure might be transient, i.e. it is possible, although unlikely, // that "failure" be returned even if *ptr == oldval. // //Another implementations: //http://upc.lbl.gov/web-translator/2.8.0/runtime/inst/opt/include/gasnet_atomic_bits.h //http://upc.lbl.gov/web-translator/ - in last versions very interesting // For arm 6 & 7: //http://lxr.free-electrons.com/source/arch/arm/include/asm/atomic.h #define ATOMIC_ADD(ptr, val) \ __extension__ ({ volatile register tINT32 *__ptr asm("r2") = (ptr); \ register tINT32 __result asm("r1"); \ asm volatile ( \ "1: @ atomic_add\n\t" \ "ldr r0, [r2]\n\t" \ "mov r3, #0xffff0fff\n\t" \ "add lr, pc, #4\n\t" \ "add r1, r0, %2\n\t" \ "add pc, r3, #(0xffff0fc0 - 0xffff0fff)\n\t" \ "bcc 1b" \ : "=&r" (__result) \ : "r" (__ptr), "rIL" (val) \ : "r0","r3","ip","lr","cc","memory" ); \ __result; }) #define ATOMIC_SUB(ptr, val) \ __extension__ ({ volatile register tINT32 *__ptr asm("r2") = (ptr); \ register tINT32 __result asm("r1"); \ asm volatile ( \ "1: @ atomic_add\n\t" \ "ldr r0, [r2]\n\t" \ "mov r3, #0xffff0fff\n\t" \ "add lr, pc, #4\n\t" \ "sub r1, r0, %2\n\t" \ "add pc, r3, #(0xffff0fc0 - 0xffff0fff)\n\t" \ "bcc 1b" \ : "=&r" (__result) \ : "r" (__ptr), "rIL" (val) \ : "r0","r3","ip","lr","cc","memory" ); \ __result; }) //#ifdef __ARM_ARCH_5TEJ__ #elif defined(__ARM_ARCH_7A__) || defined(__ARM_ARCH_7__) || defined(__ARM_ARCH_6__) #define ATOMIC_ADD(ptr, val) \ __extension__ ({ int32_t tmp; \ int result; \ __asm__ __volatile__("@ atomic_add\n" \ "1: ldrex %0, [%3]\n" \ " add %0, %0, %4\n" \ " strex %1, %0, [%3]\n" \ " teq %1, #0\n" \ " bne 1b" \ : "=&r" (result), "=&r" (tmp), "+Qo" (*ptr) \ : "r" (ptr), "Ir" (val) \ : "cc"); \ result;}) #define ATOMIC_SUB(ptr, val) \ __extension__ ({ unsigned long tmp; \ int result; \ __asm__ __volatile__("@ atomic_sub\n" \ "1: ldrex %0, [%3]\n" \ " sub %0, %0, %4\n" \ " strex %1, %0, [%3]\n" \ " teq %1, #0\n" \ " bne 1b" \ : "=&r" (result), "=&r" (tmp), "+Qo" (*ptr) \ : "r" (ptr), "Ir" (val) \ : "cc"); \ result;}) #else //#elif defined(__ARM_ARCH_7A__) || defined(__ARM_ARCH_7__) || defined(__ARM_ARCH_6__) #define ATOMIC_ADD(io_Val, i_Add) __sync_add_and_fetch(io_Val, i_Add) #define ATOMIC_SUB(io_Val, i_Add) __sync_sub_and_fetch(io_Val, i_Add) #define ATOMIC_SET(io_Var, i_Val) __sync_lock_test_and_set(io_Var, i_Val) #endif //#ifdef __ARM_ARCH_5TEJ__ #define ATOMIC_INC(io_Val) ATOMIC_ADD(io_Val, 1) #define ATOMIC_DEC(io_Val) ATOMIC_SUB(io_Val, 1) #endif //PATOMIC_H