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