/*  File XCInts.h  */
/* needs to have this done ahead of its load: #include "XCDefs.h"  */

/* the following two conditional compilation switche
   must be set outside this file */

/* #define xcpcode	/* if def'd this code used for driving the real XCP code */


/* ======================================================================== */
/*   macros and globals for normal mode 2 interrupt code		   */
/* ======================================================================== */
#define INTLOC 0XC9FE
/*	AGETSADDR: A <-- 0C9.  The C9 must be the high-order byte of INTLOC. */
#define AGETSADDR DB 03EH,0C9H
/*	LD←I←A is   I reg   <--    A reg. */
#define LD←I←A DB 0EDH,047H
#define IM2 DB 0EDH,05EH

#define call6502 0XFF58
#define RETI DB 0EDH,04DH
#define EI DB 0FBH
#define JMP 0X0C3

static char *jmpvector = INTLOC;
static unsigned *intvector = INTLOC+1;

#ifndef xcpcode
static unsigned Aints;
static unsigned Bints;
#endif

static unsigned appleReturn;	/* when calling apple, store its ret PC here */
				/* Communication loc for 6502. */
static int *avecp = 0XF3D0;	/*  poke this loc with apple rom addr to call*/
static int *apStack = 0XF049;	/* 6502 stack pointer on exit from subr */

/* ======================================================================== */
/* 	PIO card definitions						    */
/* ======================================================================== */
/* HiEnable enables interrupts on positive transitions of that signal */
#define HiEnable 0X03
#define LoEnable 0X01
#define IRQ1 0X80		/* this works for the timer's register too */
#define PERREG 0X04

static char *CReg1A = 0XE501;	/* Control Register PIO1, reg A */
static char *CReg1B = 0XE503;
static char *CReg2A = 0XE505;
static char *CReg2B = 0XE507;
static char *CReg3A = 0XE511;
static char *CReg3B = 0XE513;
static char *PDR1A = 0XE500;	/* Peripheral OR Data register		*/
static char *PDR1B = 0XE502;	/* Peripheral OR Data Register for B	*/
static char *PDR2A = 0XE504;
static char *PDR2B = 0XE506;
static char *PDR3A = 0XE510;
static char *PDR3B = 0XE512;

/* ======================================================================== */
/* 	Timer Definitions						    */
/* ======================================================================== */
#define intBit 0X40
#define selCR1Bit 0X01
#define preset 0X01
#define T1Access 0X01

static int iterate = 0;
static char alarm = FALSE;
static int timInts = 0;	/* a count of # of timer ints		   */
static unsigned latchCount = 0; /* loaded into latches for timer interval  */
static char *CRegT2 = 0XE509;	/* address of ReadStatusRegister and	   */
				/*  WriteControlRegister2		   */
static char *CRegT1 = 0XE508;	/* must acces this reg to hold timer still */

/* *timLatches is defined as pointing to an unsigned to the WriteMSBBuffer
   This will cause a 2-byte write. The second byte will go into the latches
   register.  The Z80 writes this word backwords. latchCount is therefore
   stored with its bytes reversed */

static unsigned *timLatches = 0XE50C;
static char *TDReg2 = 0XE50C;	     /* this addresses timer2 data register */

/* ======================================================================== */
/* 	startInterrupts						    */
/* ======================================================================== */
startInterrupts(foo)
unsigned foo;
{/*char garbage;*/
/* Clear the PIO control registers */
	*CReg3B = *CReg3A = *CReg2B = *CReg2A = *CReg1B = *CReg1A = PERREG;
/*  Not doing anything yet about setting the data directions of the reg's */
/*	garbage = *TDReg2;	/* clear any timer interrupts		  */
	*CReg1A = LoEnable | PERREG;/* enable interrupts for neg trans	  */
	*CReg1B = LoEnable | PERREG;	/* this watches zero clock		  */

	*jmpvector = JMP;
	*intvector = foo;	/* address of the interrupt routine */

/* tell Z80 which page to vector to */
#asm
	IM2
	PUSH PSW		/* gonna smash it */
	AGETSADDR		/* A <- high byte of int addr */
	LD←I←A			/* I <-- contents of A */
	POP PSW
	EI
#endasm
}

/* ======================================================================== */
/* 	inthandle							    */
/* ======================================================================== */
inthandle(){
	static char BData = '\0';
	static char AData = '\0';
	static char *zcpu = 0XF3DE;

#asm
	PUSH PSW
	PUSH B			/*Save all registers */
	PUSH H
	PUSH D
#endasm
/* Do the interrupt processing before re-enabling the 6502 */
	if (IRQ1 & *CReg1B)	/* get status of IRQB1: the zero clock */
		{ /* Read data register to clear the interrupt */
	  	*CReg1B = PERREG;	/* Select the Peripheral Register */
	  	BData = *PDR1B;	/* clear int by getting data */
/* Enable interrupts on B again and allow writes to go to Per Data Reg*/
	  	*CReg1B = LoEnable | PERREG;

#ifdef xcpcode
		zeroEvent = TRUE;
#else
	  	++Bints;
#endif
	 	}
	else if (IRQ1 & *CReg1A)
	 	{*CReg1A = PERREG;
	  	AData = *PDR1A;
	  	*CReg1A = LoEnable | PERREG;
#ifdef xcpcode
		++curEvent;
#else
	  	++Aints;
#endif
	 	}
	else if (IRQ1 & *CRegT2)
		{if (--iterate <= 0)
			 /* clear interrrupt enable bit ...  and get out */
			{*CRegT2 = T1Access; /* leave access to CRegT1 on */
			 *CRegT1 = preset;	   /* turn all timers off */
		     	  alarm = TRUE;	   /* tell others we're done */
		    	 };
	 	 else	   				 /* Restart timer. Doing */
		    *timLatches = latchCount;	 /* so this way reenables ints */
		};


	appleReturn = *apStack;	/*Get 6502's return PC (if it was in subrtn)*/
	*avecp = call6502;	/*Have 6502 call this routine when started */
				/* it will have the 6502 return from int. */
	*zcpu = '\0';		/*Send a 0 to softcard address (starts 6502) */
	*apStack = appleReturn;	/* restore the 6502's return PC */

#asm
	POP D
	POP H
	POP B
	POP PSW
	EI
#endasm
}

#ifndef xcpcode
/* ======================================================================== */
/* 	IntMsWait	Wait n Ms using the programmable counter		   */
/* ======================================================================== */
IntMsWait(n)
int n;
{static char startTimer = '\0';
static char t2Ints = (intBit | selCR1Bit);/* to ena ints and sel CR1 */

/* initially set up to get interrupts every 10 ms */
	latchCount = 0X2727;	/* 0X2710 is 10000 in backwards byte order */
	iterate = n/10;		/* while 2727 is 10023 */
	if (iterate == 0) iterate = 1;
	alarm = FALSE;
	timInts = 0;

	*CRegT2 = t2Ints;	/* now we can address CRegT1 */

	*CRegT1 = preset;	/* tell all timers to disable */
	/* supposedly, a write to the latches starts the timer. */
	/* but with preset asserted, it will wait till we take preset away */
	*timLatches = latchCount;/* a 2-byte write */
	*CRegT1 = startTimer;	/* a '0' to CR10 enables timers */
	while (~(alarm)) latchCount = 0X2727;
}

#endif