#ifndef _M68K_SYSTEM_H
#define _M68K_SYSTEM_H

#include <linux/config.h> /* get configuration macros */
#include <linux/linkage.h>
#include <asm/segment.h>

#if defined(CONFIG_ATARI) && !defined(CONFIG_AMIGA) && !defined(CONFIG_MAC)
/* block out HSYNC on the atari */
#define sti() __asm__ __volatile__ ("andiw #0xfbff,%/sr": : : "memory")
#else /* portable version */
#define sti() __asm__ __volatile__ ("andiw #0xf8ff,%/sr": : : "memory")
#endif /* machine compilation types */ 
#define cli() __asm__ __volatile__ ("oriw  #0x0700,%/sr": : : "memory")
#define nop() __asm__ __volatile__ ("nop"::)

#define save_flags(x) \
__asm__ __volatile__("movew %/sr,%0":"=d" (x) : /* no input */ :"memory")

#define restore_flags(x) \
__asm__ __volatile__("movew %0,%/sr": /* no outputs */ :"d" (x) : "memory")

#define iret() __asm__ __volatile__ ("rte": : :"memory", "sp", "cc")

/*
 * switch_to(n) should switch tasks to task ptr, first checking that
 * ptr isn't the current task, in which case it does nothing.  This
 * also clears the TS-flag if the task we switched to has used the
 * math co-processor latest.
 */
struct task_struct;
asmlinkage void resume(struct task_struct *tsk, int offset);
#define switch_to(n) resume(n, ((int)(&((struct task_struct *)0)->tss)))

/* The xchg_* functions below would be best implemented by the CAS instruction
 * (like in the #if 0 parts). Unfortunately, some mainboards don't like the
 * read-modify-write cycles generated by CAS, especially if prolonged by a
 * '040 bug(let): if the effaddr is in a dirty cache line, that line is pushed
 * with LOCK asserted. Using a simple swapping with interrupts disabled
 * stabilized the kernel on '040 machines. (It would also be possible to push
 * that line before the CAS manually, but that requires calculating the
 * physical address, which needs too much time.)
 */

extern inline unsigned long xchg_u8(char * m, unsigned long val)
{
#if 0
	__asm__ __volatile__
		("moveb %2,%0\n\t"
		 "1:\n\t"
		 "casb %0,%1,%2\n\t"
		 "jne 1b"
		 : "=&d" (val) : "d" (val), "m" (*m) : "memory");
#else
	unsigned long flags;
	unsigned char tmp;

	save_flags(flags);
	cli();
	tmp = *m;
	*m = val;
	val = tmp;
	restore_flags(flags);
#endif
	return val;
}

extern inline unsigned long xchg_u16(short * m, unsigned long val)
{
#if 0
	__asm__ __volatile__
		("movew %2,%0\n\t"
		 "1:\n\t"
		 "casw %0,%1,%2\n\t"
		 "jne 1b"
		 : "=&d" (val) : "d" (val), "m" (*m) : "memory");
#else
	unsigned long flags;
	unsigned short tmp;

	save_flags(flags);
	cli();
	tmp = *m;
	*m = val;
	val = tmp;
	restore_flags(flags);
#endif
	return val;
}

#define wp_works_ok 1

extern inline unsigned long xchg_u32(int * m, unsigned long val)
{
#if 0
	__asm__ __volatile__
		("movel %2,%0\n\t"
		 "1:\n\t"
		 "casl %0,%1,%2\n\t"
		 "jne 1b"
		 : "=&d" (val) : "d" (val), "m" (*m) : "memory");
#else
	unsigned long flags;
	unsigned long tmp;

	save_flags(flags);
	cli();
	tmp = *m;
	*m = val;
	val = tmp;
	restore_flags(flags);
#endif
	return val;
}

extern inline int tas(char * m)
{
	return xchg_u8(m,1);
}

extern inline void * xchg_ptr(void * m, void * val)
{
	return (void *) xchg_u32(m, (unsigned long) val);
}

#endif /* _M68K_SYSTEM_H */
