/*
 * Definitions for implementing CoCo ISRs in C
 *
 * Copyright 2013 by John W. Linville <linville@tuxdriver.com>
 */

/*
 * INTERRUPT
 *
 *	This macro is used to declare an ISR handler in C.
 *
 *	Inline assembly language is used to define a 'trampoline'
 *	entry point for the ISR.  The trampoline saves the ?temp value
 *	used in code generated by the compiler, calls the handler,
 *	then restores the ?temp value and executes an RTI instruction
 *	to resume normal execution.
 *
 *	The macro munges the passed-in ISR label to create separate
 *	labels for the trampoline and for the C-language ISR.
 *	These labels are used by the GET*() and SET*() macros defined
 *	later in this file.
 *
 *	Example:	INTERRUPT(vsync_handler) { ... };
 */
#define	_SP_
#define INTERRUPT(isr) 				\
extern unsigned _/**/isr/**/VEC;		\
asm {						\
$SE:0	/* Insure code goes in code segment */	\
_/**/isr/**/VEC	EQU	_SP_*			\
	LDD	_SP_?temp			\
	PSHS	D				\
	BSR	_/**/isr/**/ISR			\
	PULS	D				\
	STD	_SP_?temp			\
	RTI					\
}						\
void _/**/isr/**/ISR(void)
#undef	_SP_

/*
 * EXTERN_INTERRUPT
 *
 *	This macro is used to make external declarations for a
 *	C-language ISR defined in a separate source file than where
 *	the ISR is defined.  It uses the label munging mentioned above to
 *	make the declarations required for use of the GET*() and SET*()
 *	macros defined below.
 *
 *	Example:	EXTERN_INTERRUPT(vsync_handler);
 */
#define EXTERN_INTERRUPT(isr)	extern unsigned _/**/isr/**/VEC

/*
 * Addresses of ISRs in CoCo interrupt hooks in RAM
 */
#define SW3VEC		0x0101
#define SW2VEC		0x0104
#define SWIVEC		0x0107
#define NMIVEC		0x010a
#define IRQVEC		0x010d
#define FIRQVEC		0x0110

/*
 * GETSW3, GETSW2, GETSWI, GETNMI, GETIRQ, GETFIRQ
 *
 *	Get the current vector address for a given interrupt type.
 *
 * SETSW3, SETSW2, SETSWI, SETNMI, SETIRQ, SETFIRQ
 *
 *	Set the vector address for a given interrupt type to
 *	point at the passed-in ISR.
 */
#define GETSW3()	((const)*((unsigned *)SW3VEC))
#define SETSW3(isr)	(*((unsigned *)SW3VEC) = (unsigned *)&_/**/isr/**/VEC)

#define GETSW2()	((const)*((unsigned *)SW2VEC))
#define SETSW2(isr)	(*((unsigned *)SW2VEC) = (unsigned *)&_/**/isr/**/VEC)

#define GETSWI()	((const)*((unsigned *)SWIVEC))
#define SETSWI(isr)	(*((unsigned *)SWIVEC) = (unsigned *)&_/**/isr/**/VEC)

#define GETNMI()	((const)*((unsigned *)NMIVEC))
#define SETNMI(isr)	(*((unsigned *)NMIVEC) = (unsigned *)&_/**/isr/**/VEC)

#define GETIRQ()	((const)*((unsigned *)IRQVEC))
#define SETIRQ(isr)	(*((unsigned *)IRQVEC) = (unsigned *)&_/**/isr/**/VEC)

#define GETFIRQ()	((const)*((unsigned *)FIRQVEC))
#define SETFIRQ(isr)	(*((unsigned *)FIRQVEC) = (unsigned *)&_/**/isr/**/VEC)
