diff options
author | Stefan Kristiansson <stefan.kristiansson@saunalahti.fi> | 2014-07-17 22:09:10 +0300 |
---|---|---|
committer | Rich Felker <dalias@aerifal.cx> | 2014-07-18 14:10:23 -0400 |
commit | 200d15479c0bc48471ee7b8e538ce33af990f82e (patch) | |
tree | 864cc38895b9277384ed3a956f4ad324de2c4455 /arch/or1k/atomic.h | |
parent | 7bece9c2095ee81f14b1088f6b0ba2f37fecb283 (diff) | |
download | musl-200d15479c0bc48471ee7b8e538ce33af990f82e.tar.gz musl-200d15479c0bc48471ee7b8e538ce33af990f82e.tar.xz musl-200d15479c0bc48471ee7b8e538ce33af990f82e.zip |
add or1k (OpenRISC 1000) architecture port
With the exception of a fenv implementation, the port is fully featured. The port has been tested in or1ksim, the golden reference functional simulator for OpenRISC 1000. It passes all libc-test tests (except the math tests that requires a fenv implementation). The port assumes an or1k implementation that has support for atomic instructions (l.lwa/l.swa). Although it passes all the libc-test tests, the port is still in an experimental state, and has yet experienced very little 'real-world' use.
Diffstat (limited to 'arch/or1k/atomic.h')
-rw-r--r-- | arch/or1k/atomic.h | 122 |
1 files changed, 122 insertions, 0 deletions
diff --git a/arch/or1k/atomic.h b/arch/or1k/atomic.h new file mode 100644 index 00000000..0fb61de1 --- /dev/null +++ b/arch/or1k/atomic.h @@ -0,0 +1,122 @@ +#ifndef _INTERNAL_ATOMIC_H +#define _INTERNAL_ATOMIC_H + +#include <stdint.h> + +static inline int a_ctz_l(unsigned long x) +{ + static const char debruijn32[32] = { + 0, 1, 23, 2, 29, 24, 19, 3, 30, 27, 25, 11, 20, 8, 4, 13, + 31, 22, 28, 18, 26, 10, 7, 12, 21, 17, 9, 6, 16, 5, 15, 14 + }; + return debruijn32[(x&-x)*0x076be629 >> 27]; +} + +static inline int a_ctz_64(uint64_t x) +{ + uint32_t y = x; + if (!y) { + y = x>>32; + return 32 + a_ctz_l(y); + } + return a_ctz_l(y); +} + +static inline int a_cas(volatile int *p, int t, int s) +{ + __asm__("1: l.lwa %0, %1\n" + " l.sfeq %0, %2\n" + " l.bnf 1f\n" + " l.nop\n" + " l.swa %1, %3\n" + " l.bnf 1b\n" + " l.nop\n" + "1: \n" + : "=&r"(t), "+m"(*p) : "r"(t), "r"(s) : "cc", "memory" ); + return t; +} + +static inline void *a_cas_p(volatile void *p, void *t, void *s) +{ + return (void *)a_cas(p, (int)t, (int)s); +} + +static inline long a_cas_l(volatile void *p, long t, long s) +{ + return a_cas(p, t, s); +} + +static inline int a_swap(volatile int *x, int v) +{ + int old; + do old = *x; + while (a_cas(x, old, v) != old); + return old; +} + +static inline int a_fetch_add(volatile int *x, int v) +{ + int old; + do old = *x; + while (a_cas(x, old, old+v) != old); + return old; +} + +static inline void a_inc(volatile int *x) +{ + a_fetch_add(x, 1); +} + +static inline void a_dec(volatile int *x) +{ + a_fetch_add(x, -1); +} + +static inline void a_store(volatile int *p, int x) +{ + *p=x; +} + +static inline void a_spin() +{ +} + +static inline void a_crash() +{ + *(volatile char *)0=0; +} + +static inline void a_and(volatile int *p, int v) +{ + int old; + do old = *p; + while (a_cas(p, old, old&v) != old); +} + +static inline void a_or(volatile int *p, int v) +{ + int old; + do old = *p; + while (a_cas(p, old, old|v) != old); +} + +static inline void a_or_l(volatile void *p, long v) +{ + a_or(p, v); +} + +static inline void a_and_64(volatile uint64_t *p, uint64_t v) +{ + union { uint64_t v; uint32_t r[2]; } u = { v }; + a_and((int *)p, u.r[0]); + a_and((int *)p+1, u.r[1]); +} + +static inline void a_or_64(volatile uint64_t *p, uint64_t v) +{ + union { uint64_t v; uint32_t r[2]; } u = { v }; + a_or((int *)p, u.r[0]); + a_or((int *)p+1, u.r[1]); +} + +#endif |