implemented Setup.hs to build boehm cpp libs and install them;
[hs-boehmgc.git] / gc-7.2 / libatomic_ops / src / atomic_ops / sysdeps / armcc / arm_v6.h
diff --git a/gc-7.2/libatomic_ops/src/atomic_ops/sysdeps/armcc/arm_v6.h b/gc-7.2/libatomic_ops/src/atomic_ops/sysdeps/armcc/arm_v6.h
new file mode 100644 (file)
index 0000000..a239587
--- /dev/null
@@ -0,0 +1,232 @@
+/*
+ * Copyright (c) 2007 by NEC LE-IT:               All rights reserved.
+ * A transcription of ARMv6 atomic operations for the ARM Realview Toolchain.
+ * This code works with armcc from RVDS 3.1
+ * This is based on work in gcc/arm.h by
+ *   Copyright (c) 1991-1994 by Xerox Corporation.  All rights reserved.
+ *   Copyright (c) 1996-1999 by Silicon Graphics.  All rights reserved.
+ *   Copyright (c) 1999-2003 by Hewlett-Packard Company. All rights reserved.
+ *
+ *
+ *
+ * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
+ * OR IMPLIED.  ANY USE IS AT YOUR OWN RISK.
+ *
+ * Permission is hereby granted to use or copy this program
+ * for any purpose,  provided the above notices are retained on all copies.
+ * Permission to modify the code and to distribute modified code is granted,
+ * provided the above notices are retained, and a notice that the code was
+ * modified is included with the above copyright notice.
+ *
+ */
+#include "../read_ordered.h"
+#include "../test_and_set_t_is_ao_t.h" /* Probably suboptimal */
+
+#if __TARGET_ARCH_ARM < 6
+Dont use with ARM instruction sets lower than v6
+#else
+
+#include "../standard_ao_double_t.h"
+
+/* NEC LE-IT: ARMv6 is the first architecture providing support for simple LL/SC
+ * A data memory barrier must be raised via CP15 command (see documentation).
+ *
+ * ARMv7 is compatible to ARMv6 but has a simpler command for issuing a
+ * memory barrier (DMB). Raising it via CP15 should still work as told me by the
+ * support engineers. If it turns out to be much quicker than we should implement
+ * custom code for ARMv7 using the asm { dmb } command.
+ *
+ * If only a single processor is used, we can define AO_UNIPROCESSOR
+ * and do not need to access CP15 for ensuring a DMB at all.
+*/
+
+AO_INLINE void
+AO_nop_full(void)
+{
+# ifndef AO_UNIPROCESSOR
+    unsigned int dest=0;
+    /* issue an data memory barrier (keeps ordering of memory transactions */
+    /* before and after this operation)                                    */
+    __asm {
+            mcr p15,0,dest,c7,c10,5
+            };
+# endif
+}
+#define AO_HAVE_nop_full
+
+AO_INLINE AO_t
+AO_load(const volatile AO_t *addr)
+{
+        /* Cast away the volatile in case it adds fence semantics */
+        return (*(const AO_t *)addr);
+}
+#define AO_HAVE_load
+
+/* NEC LE-IT: atomic "store" - according to ARM documentation this is
+ * the only safe way to set variables also used in LL/SC environment.
+ * A direct write won't be recognized by the LL/SC construct in other CPUs.
+ *
+ * HB: Based on subsequent discussion, I think it would be OK to use an
+ * ordinary store here if we knew that interrupt handlers always cleared
+ * the reservation.  They should, but there is some doubt that this is
+ * currently always the case for e.g. Linux.
+*/
+AO_INLINE void AO_store(volatile AO_t *addr, AO_t value)
+{
+        unsigned long tmp;
+
+retry:
+__asm {
+        ldrex   tmp, [addr]
+        strex   tmp, value, [addr]
+        teq     tmp, #0
+        bne     retry
+        };
+}
+#define AO_HAVE_store
+
+/* NEC LE-IT: replace the SWAP as recommended by ARM:
+
+   "Applies to: ARM11 Cores
+        Though the SWP instruction will still work with ARM V6 cores, it is recommended
+        to use the new V6 synchronization instructions. The SWP instruction produces
+        locked read and write accesses which are atomic, i.e. another operation cannot
+        be done between these locked accesses which ties up external bus (AHB,AXI)
+        bandwidth and can increase worst case interrupt latencies. LDREX,STREX are
+        more flexible, other instructions can be done between the LDREX and STREX accesses.
+   "
+*/
+AO_INLINE AO_TS_VAL_t
+AO_test_and_set(volatile AO_TS_t *addr) {
+
+        AO_TS_VAL_t oldval;
+        unsigned long tmp;
+        unsigned long one = 1;
+retry:
+__asm {
+        ldrex   oldval, [addr]
+        strex   tmp, one, [addr]
+        teq     tmp, #0
+        bne     retry
+        }
+
+        return oldval;
+}
+#define AO_HAVE_test_and_set
+
+/* NEC LE-IT: fetch and add for ARMv6 */
+AO_INLINE AO_t
+AO_fetch_and_add(volatile AO_t *p, AO_t incr)
+{
+        unsigned long tmp,tmp2;
+        AO_t result;
+
+retry:
+__asm {
+        ldrex   result, [p]
+        add     tmp, incr, result
+        strex   tmp2, tmp, [p]
+        teq     tmp2, #0
+        bne     retry
+        }
+
+        return result;
+}
+#define AO_HAVE_fetch_and_add
+
+/* NEC LE-IT: fetch and add1 for ARMv6 */
+AO_INLINE AO_t
+AO_fetch_and_add1(volatile AO_t *p)
+{
+        unsigned long tmp,tmp2;
+        AO_t result;
+
+retry:
+__asm {
+        ldrex   result, [p]
+        add     tmp, result, #1
+        strex   tmp2, tmp, [p]
+        teq     tmp2, #0
+        bne     retry
+        }
+
+        return result;
+}
+#define AO_HAVE_fetch_and_add1
+
+/* NEC LE-IT: fetch and sub for ARMv6 */
+AO_INLINE AO_t
+AO_fetch_and_sub1(volatile AO_t *p)
+{
+        unsigned long tmp,tmp2;
+        AO_t result;
+
+retry:
+__asm {
+        ldrex   result, [p]
+        sub     tmp, result, #1
+        strex   tmp2, tmp, [p]
+        teq     tmp2, #0
+        bne     retry
+        }
+
+        return result;
+}
+#define AO_HAVE_fetch_and_sub1
+
+/* NEC LE-IT: compare and swap */
+/* Returns nonzero if the comparison succeeded. */
+AO_INLINE int
+AO_compare_and_swap(volatile AO_t *addr, AO_t old_val, AO_t new_val)
+{
+         AO_t result,tmp;
+
+retry:
+__asm__ {
+        mov     result, #2
+        ldrex   tmp, [addr]
+        teq     tmp, old_val
+#     ifdef __thumb__
+        it      eq
+#     endif
+        strexeq result, new_val, [addr]
+        teq     result, #1
+        beq     retry
+        }
+
+        return !(result&2);
+}
+#define AO_HAVE_compare_and_swap
+
+/* helper functions for the Realview compiler: LDREXD is not usable
+ * with inline assembler, so use the "embedded" assembler as
+ * suggested by ARM Dev. support (June 2008). */
+__asm inline double_ptr_storage load_ex(volatile AO_double_t *addr) {
+        LDREXD r0,r1,[r0]
+}
+
+__asm inline int store_ex(AO_t val1, AO_t val2, volatile AO_double_t *addr) {
+        STREXD r3,r0,r1,[r2]
+        MOV    r0,r3
+}
+
+AO_INLINE int
+AO_compare_double_and_swap_double(volatile AO_double_t *addr,
+                                  AO_t old_val1, AO_t old_val2,
+                                  AO_t new_val1, AO_t new_val2)
+{
+        double_ptr_storage old_val =
+                        ((double_ptr_storage)old_val2 << 32) | old_val1;
+        double_ptr_storage tmp;
+        int result;
+
+        while(1) {
+                tmp = load_ex(addr);
+                if(tmp != old_val)      return 0;
+                result = store_ex(new_val1, new_val2, addr);
+                if(!result)     return 1;
+        }
+}
+#define AO_HAVE_compare_double_and_swap_double
+
+#endif // __TARGET_ARCH_ARM