/* 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