/* Atomic operations.  FR-V version.
   Copyright (C) 2005 Free Software Foundation, Inc.
   This file is part of the GNU C Library.
   Contributed by Mark Salter <msalter@redhat.com>, 2005.

   The GNU C 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 2.1 of the License, or (at your option) any later version.

   The GNU C 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 the GNU C Library; if not, write to the Free
   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
   02111-1307 USA.  */

#ifndef _BITS_ATOMIC_H
#define _BITS_ATOMIC_H	1

/* We have no compare and swap, just test and set.
   The following implementation uses the kernel to do the
   compare and swap atomically. */

#define atomic_compare_and_exchange_val_acq(mem, new, test)             \
({									\
	register __typeof (mem) __mem asm("gr8") = (mem);               \
	register __typeof (*(mem)) __test asm("gr9") = (test);          \
	register __typeof (*(mem)) __new asm("gr10") = (new);           \
	register __typeof (*(mem)) __orig asm("gr5");                   \
									\
	switch (sizeof(__orig)) {					\
	case 4:								\
		__asm __volatile("tira gr0,#120"                        \
			 : "=&r"(__orig), "+m"(*__mem), "+&r"(__test)	\
				 : "r"(__test), "r"(__new), "r"(__mem)  \
				 : "memory", "icc0", "cc4"		\
		    );                                                  \
		break;							\
									\
	default:							\
		abort ();                                               \
		break;							\
	}								\
									\
	__orig;								\
 })

#define atomic_exchange_acq(mem, x)                                     \
({									\
	register __typeof (mem)    __mem  = (mem);			\
	register __typeof (*(mem)) __x    = (x);			\
									\
	switch (sizeof(__x)) {		  			        \
	case 4:								\
		__asm __volatile(					\
			"swap%I0 %M0, %1"				\
			: "+m"(*__mem), "+&r"(__x)     			\
			: "r"(__mem), "r"(__x)			        \
			: "memory"					\
			);						\
		break;							\
									\
	default:							\
		abort ();                                               \
		break;							\
	}								\
									\
	__x;								\
 })

#if 0  /* not tested yet */
# define atomic_exchange_and_add(mem, x)                                \
({                                                                      \
	register __typeof (mem) __mem asm("gr8") = (mem);               \
	register __typeof (*(mem)) __x asm("gr9") = (x);                \
	register __typeof (*(mem)) __orig asm("gr5");                   \
									\
	switch (sizeof(__x)) {						\
	case 4:								\
		__asm __volatile("tira gr0,#126"                        \
			: "=&r"(__orig), "+m"(*__mem), "+&r"(__x)	\
			: "r"(__x), "r"(__mem)  			\
			: "memory", "icc0", "cc4"			\
		    );                                                  \
		break;							\
	default:							\
		abort ();                                               \
		break;							\
	}								\
									\
	__orig;								\
})

# define atomic_bit_test_set(mem, bit) \
({                                                                      \
	register __typeof (mem) __mem asm("gr8") = (mem);               \
	register __typeof (*(mem)) __mask asm("gr9");                   \
	register __typeof (*(mem)) __orig asm("gr5");			\
									\
        __mask = ((__typeof (*(mem))) 1 << (bit));	                \
	switch (sizeof(__orig)) {					\
	case 4:								\
		__asm __volatile("tira gr0,#123"                        \
			: "=&r"(__orig), "+m"(*__mem), "+&r"(__mask)	\
			: "r"(__mask), "r"(__mem)  			\
			: "memory", "icc0", "cc4"			\
		    );                                                  \
	default:							\
		abort ();                                               \
		__orig = 0;						\
		break;							\
	}								\
									\
	__orig & __mask;						\
})

#endif  /* untested bits */

#endif	/* bits/atomic.h */
