|
|
1.1 ! root 1: /* ! 2: Hatari ! 3: ! 4: MFP - Multi Functional Peripheral. In emulation terms it's the 'chip from hell' - most differences between ! 5: a real machine and an emulator are down to this chip. It seems very simple at first but the implementation ! 6: is very difficult. The following code is the most accurate in an ST emulator to date as it is able to ! 7: perform Spectrum 512 raster effects as well as simulate the quirks found in the chip. ! 8: The easiest way to 'see' the MFP chip is to look at the diagram - this shows the main details of the chip's ! 9: behaviour with regard to interrupts and pending/service bits. ! 10: */ ! 11: ! 12: #include "main.h" ! 13: #include "debug.h" ! 14: #include "decode.h" ! 15: #include "fdc.h" ! 16: #include "ikbd.h" ! 17: #include "int.h" ! 18: #include "m68000.h" ! 19: #include "memAlloc.h" ! 20: #include "memorySnapShot.h" ! 21: #include "mfp.h" ! 22: #include "misc.h" ! 23: #include "psg.h" ! 24: #include "screen.h" ! 25: #include "shortcut.h" ! 26: #include "sound.h" ! 27: #include "stMemory.h" ! 28: #include "ymFormat.h" ! 29: #include "video.h" ! 30: #include "view.h" ! 31: ! 32: /* ! 33: MFP interrupt channel circuit:- ! 34: ! 35: EdgeRegister EnableRegister MaskRegister SBit ! 36: | | | | ! 37: | | | | ------------------------ ! 38: | | ------------------------ ---\ |---\ | | ! 39: | o--\ | | AND---o----------------AND---| S InterruptInService | ! 40: ---\ | AND---| S InterruptPending O |-------/ | |---/ | | ! 41: XOR----------)--/ | R | | | ------------------------ ! 42: Input -----/ | ------------------------ | | ! 43: | | InterruptRequest | ! 44: NOT OR | ! 45: | | | | ! 46: -------------------- --------------------------------------o--- PassVector ! 47: */ ! 48: ! 49: #define IGNORE_FDC_PRIORITY 0xff /* Set 0xff if FDC has higher priority than Keyboard/Midi, or 0x7f if not - Dragon's Breath will now work! */ ! 50: ! 51: // MFP Registers ! 52: unsigned char MFP_GPIP; // General Purpose Pins ! 53: unsigned char MFP_AER,MFP_DDR; // Active Edge Register, Data Direction Register ! 54: unsigned char MFP_IERA,MFP_IERB; // Interrupt Enable Registers A,B 0xfffa07,0xfffa09 ! 55: unsigned char MFP_IPRA,MFP_IPRB; // Interrupt Pending Registers A,B 0xfffa0b,0xfffa0d ! 56: unsigned char MFP_ISRA,MFP_ISRB; // Interrupt In-Service Registers A,B 0xfffa0f,0xfffa11 ! 57: unsigned char MFP_IMRA,MFP_IMRB; // Interrupt Mask Registers A,B 0xfffa13,0xfffa15 ! 58: unsigned char MFP_VR; // Vector Register 0xfffa17 ! 59: unsigned char MFP_TACR,MFP_TBCR,MFP_TCDCR; // Timer A,B,C+D Control Registers ! 60: unsigned char MFP_TADR,MFP_TBDR; // Timer A,B Data Registers ! 61: unsigned char MFP_TCDR,MFP_TDDR; // Timer C,D Data Registers ! 62: unsigned char MFP_TA_MAINCOUNTER; // Timer A Main Counter(internal to MFP) ! 63: unsigned char MFP_TB_MAINCOUNTER; // Timer B Main Counter ! 64: unsigned char MFP_TC_MAINCOUNTER; // Timer C Main Counter(these are temp's, set when read as) ! 65: unsigned char MFP_TD_MAINCOUNTER; // Timer D Main Counter(as done via interrupts) ! 66: ! 67: /* CPU clock cycle counts for each timer */ ! 68: int TimerAClockCycles=0; ! 69: int TimerBClockCycles=0; ! 70: int TimerCClockCycles=0; ! 71: int TimerDClockCycles=0; ! 72: ! 73: /* ! 74: Number of CPU cycles for Timer C+D ! 75: These figures were based on 50Hz=160256cycles, so 200Hz=40064 ! 76: Now, Timer C set on a delay of 192($C0) and a preset DIV of 64 is 200Hz ! 77: This makes the table entry 208.66666*192=40064(200Hz) ! 78: */ ! 79: float MFPTimerToCPUCycleTable[] = { ! 80: 0, // Timer Stop ! 81: 13.04166667f, // Div by 4 ! 82: 32.60416667f, // Div by 10 ! 83: 52.16666667f, // Div by 16 ! 84: 163.02083333f, // Div by 50 ! 85: 208.66666667f, // Div by 64 ! 86: 326.04166667f, // Div by 100 ! 87: 652.08333333f // Div by 200 ! 88: }; ! 89: ! 90: ! 91: //----------------------------------------------------------------------- ! 92: /* ! 93: Reset all MFP variables and start interrupts on their way! ! 94: */ ! 95: void MFP_Reset(void) ! 96: { ! 97: // Reset MFP internal variables ! 98: MFP_GPIP = 0xff; /* Set GPIP register (all 1's = no interrupts) */ ! 99: MFP_AER = MFP_DDR = 0; ! 100: MFP_IERA = MFP_IERB = 0; ! 101: MFP_IPRA = MFP_IPRB = 0; ! 102: MFP_ISRA = MFP_ISRB = 0; ! 103: MFP_IMRA = MFP_IMRB = 0; ! 104: MFP_VR = 0; ! 105: MFP_TACR = MFP_TBCR = MFP_TCDCR = 0; ! 106: MFP_TADR = MFP_TBDR = 0; ! 107: MFP_TCDR = MFP_TDDR = 0; ! 108: MFP_TA_MAINCOUNTER = MFP_TB_MAINCOUNTER = MFP_TC_MAINCOUNTER = MFP_TD_MAINCOUNTER = 0; ! 109: ! 110: // Clear counters ! 111: TimerAClockCycles = TimerBClockCycles = TimerCClockCycles = TimerDClockCycles = 0; ! 112: } ! 113: ! 114: //----------------------------------------------------------------------- ! 115: /* ! 116: Save/Restore snapshot of local variables('MemorySnapShot_Store' handles type) ! 117: */ ! 118: void MFP_MemorySnapShot_Capture(BOOL bSave) ! 119: { ! 120: // Save/Restore details ! 121: MemorySnapShot_Store(&MFP_GPIP,sizeof(MFP_GPIP)); ! 122: MemorySnapShot_Store(&MFP_AER,sizeof(MFP_AER)); ! 123: MemorySnapShot_Store(&MFP_DDR,sizeof(MFP_DDR)); ! 124: MemorySnapShot_Store(&MFP_IERA,sizeof(MFP_IERA)); ! 125: MemorySnapShot_Store(&MFP_IERB,sizeof(MFP_IERB)); ! 126: MemorySnapShot_Store(&MFP_IPRA,sizeof(MFP_IPRA)); ! 127: MemorySnapShot_Store(&MFP_IPRB,sizeof(MFP_IPRB)); ! 128: MemorySnapShot_Store(&MFP_ISRA,sizeof(MFP_ISRA)); ! 129: MemorySnapShot_Store(&MFP_ISRB,sizeof(MFP_ISRB)); ! 130: MemorySnapShot_Store(&MFP_IMRA,sizeof(MFP_IMRA)); ! 131: MemorySnapShot_Store(&MFP_IMRB,sizeof(MFP_IMRB)); ! 132: MemorySnapShot_Store(&MFP_VR,sizeof(MFP_VR)); ! 133: MemorySnapShot_Store(&MFP_TACR,sizeof(MFP_TACR)); ! 134: MemorySnapShot_Store(&MFP_TBCR,sizeof(MFP_TBCR)); ! 135: MemorySnapShot_Store(&MFP_TCDCR,sizeof(MFP_TCDCR)); ! 136: MemorySnapShot_Store(&MFP_TADR,sizeof(MFP_TADR)); ! 137: MemorySnapShot_Store(&MFP_TBDR,sizeof(MFP_TBDR)); ! 138: MemorySnapShot_Store(&MFP_TCDR,sizeof(MFP_TCDR)); ! 139: MemorySnapShot_Store(&MFP_TDDR,sizeof(MFP_TDDR)); ! 140: MemorySnapShot_Store(&MFP_TA_MAINCOUNTER,sizeof(MFP_TA_MAINCOUNTER)); ! 141: MemorySnapShot_Store(&MFP_TB_MAINCOUNTER,sizeof(MFP_TB_MAINCOUNTER)); ! 142: MemorySnapShot_Store(&MFP_TC_MAINCOUNTER,sizeof(MFP_TC_MAINCOUNTER)); ! 143: MemorySnapShot_Store(&MFP_TD_MAINCOUNTER,sizeof(MFP_TD_MAINCOUNTER)); ! 144: MemorySnapShot_Store(&TimerAClockCycles,sizeof(TimerAClockCycles)); ! 145: MemorySnapShot_Store(&TimerBClockCycles,sizeof(TimerBClockCycles)); ! 146: MemorySnapShot_Store(&TimerCClockCycles,sizeof(TimerCClockCycles)); ! 147: MemorySnapShot_Store(&TimerDClockCycles,sizeof(TimerDClockCycles)); ! 148: } ! 149: ! 150: //----------------------------------------------------------------------- ! 151: /* ! 152: Call MFP interrupt - NOTE when the MFP is in Auto interrupt (AEI), the MFP ! 153: puts the interrupt number on the data bus and then the 68000 reads it, multiplies ! 154: it by 4 and adds in a base(usually 0x100) to give the vector. Some programs ! 155: change this offset, eg RoboCod. This offset is stored in the top 4 bits of register ! 156: 0xfffa17(0x40 is the default=0x100) ! 157: Many thanks to Steve Bak for that one! ! 158: */ ! 159: void MFP_Exception(int Interrupt) ! 160: { ! 161: unsigned int Vec; ! 162: ! 163: Vec = (unsigned int)(MFP_VR&0xf0)<<2; ! 164: Vec += Interrupt<<2; ! 165: ExceptionVector = Vec; ! 166: M68000_Exception(); ! 167: } ! 168: ! 169: //----------------------------------------------------------------------- ! 170: /* ! 171: Test interrupt request to see if can cause exception,return TRUE if pass vector ! 172: */ ! 173: BOOL InterruptRequest(int Exception,unsigned char Bit,unsigned long EnableAddr,unsigned char *pPendingReg,unsigned char MaskRegister,unsigned char PriorityMaskLow,unsigned char PriorityMaskHigh,unsigned char *pInServiceReg) ! 174: { ! 175: // Are any higher priority interupts in service? ! 176: if ( ((MFP_ISRA&PriorityMaskLow)==0) && ((MFP_ISRB&PriorityMaskHigh)==0) ) { ! 177: // Is masked? ! 178: if (MaskRegister&Bit) { ! 179: //u if (7>FIND_IPL) { ! 180: //u *pPendingReg &= ~Bit; // Clear pending bit ! 181: //u MFP_UpdateFlags(); ! 182: //u } ! 183: ! 184: // CPU allows interrupt of an MFP level? ! 185: if (6>FIND_IPL) { ! 186: *pPendingReg &= ~Bit; // Clear pending bit ! 187: MFP_UpdateFlags(); ! 188: ! 189: // Are we in 'auto' interrupt or 'manual'? ! 190: if (MFP_VR&0x08) // Software End-of-Interrupt (SEI) ! 191: *pInServiceReg |= Bit; // Set interrupt in service register ! 192: else ! 193: *pInServiceReg &= ~Bit; // Clear interrupt in service register ! 194: ! 195: // Call interrupt, adds in base(default 0x100) ! 196: MFP_Exception(Exception); ! 197: return(TRUE); ! 198: } ! 199: } ! 200: } ! 201: ! 202: return(FALSE); ! 203: } ! 204: ! 205: //----------------------------------------------------------------------- ! 206: /* ! 207: MFP circuit has pending interrupt, request ! 208: */ ! 209: void MFP_RequestInterrupt_TimerA(void) ! 210: { ! 211: InterruptRequest(MFP_EXCEPT_TIMERA,MFP_TIMER_A_BIT,MFP_IERA,&MFP_IPRA,MFP_IMRA,0xe0,0x00&IGNORE_FDC_PRIORITY,&MFP_ISRA); ! 212: } ! 213: void MFP_RequestInterrupt_TimerB(void) ! 214: { ! 215: InterruptRequest(MFP_EXCEPT_TIMERB,MFP_TIMER_B_BIT,MFP_IERA,&MFP_IPRA,MFP_IMRA,0xff,0x00&IGNORE_FDC_PRIORITY,&MFP_ISRA); ! 216: } ! 217: void MFP_RequestInterrupt_TimerC(void) ! 218: { ! 219: InterruptRequest(MFP_EXCEPT_TIMERC,MFP_TIMER_C_BIT,MFP_IERB,&MFP_IPRB,MFP_IMRB,0xff,0xe0&IGNORE_FDC_PRIORITY,&MFP_ISRB); ! 220: } ! 221: void MFP_RequestInterrupt_TimerD(void) ! 222: { ! 223: InterruptRequest(MFP_EXCEPT_TIMERD,MFP_TIMER_D_BIT,MFP_IERB,&MFP_IPRB,MFP_IMRB,0xff,0xf0&IGNORE_FDC_PRIORITY,&MFP_ISRB); ! 224: } ! 225: void MFP_RequestInterrupt_Keyboard(void) ! 226: { ! 227: InterruptRequest(MFP_EXCEPT_KEYBOARD,MFP_KEYBOARD_BIT,MFP_IERB,&MFP_IPRB,MFP_IMRB,0xff,0xc0&IGNORE_FDC_PRIORITY,&MFP_ISRB); ! 228: } ! 229: void MFP_RequestInterrupt_Floppy(void) ! 230: { ! 231: InterruptRequest(MFP_EXCEPT_GPIP5,MFP_FDCHDC_BIT,MFP_IERB,&MFP_IPRB,MFP_IMRB,0xff,0x80&IGNORE_FDC_PRIORITY,&MFP_ISRB); ! 232: } ! 233: ! 234: //----------------------------------------------------------------------- ! 235: /* ! 236: Check 'pending' registers to see if any MFP interrupts need servicing ! 237: */ ! 238: void MFP_CheckPendingInterrupts(void) ! 239: { ! 240: unsigned short i; ! 241: ! 242: i = (MFP_IPRA<<8) | MFP_IPRB; ! 243: ! 244: if( (i&0x21f0)==0 ) ! 245: { /* Should never get here, but if do just clear flag (see 'MFP_UpdateFlags') */ ! 246: PendingInterruptFlag &= CLEAR_PENDING_INTERRUPT_FLAG_MFP; ! 247: return; ! 248: } ! 249: ! 250: if( i&0x2000 ) MFP_RequestInterrupt_TimerA(); /* Check Timer A (bit 5) */ ! 251: if( i&0x0100 ) MFP_RequestInterrupt_TimerB(); /* Check Timer B (bit 0) */ ! 252: if( i&0x0080 ) MFP_RequestInterrupt_Floppy(); /* Check FDC (bit 7) */ ! 253: if( i&0x0040 ) MFP_RequestInterrupt_Keyboard(); /* Check Keyboard (bit 6) */ ! 254: if( i&0x0020 ) MFP_RequestInterrupt_TimerC(); /* Check Timer C (bit 5) */ ! 255: if( i&0x0010 ) MFP_RequestInterrupt_TimerD(); /* Check Timer D (bit 4) */ ! 256: } ! 257: ! 258: //----------------------------------------------------------------------- ! 259: /* ! 260: This is called whenever the MFP_IPRA or MFP_IPRB registers are modified. ! 261: We set the 'PendingInterruptFlag' accordingly (to say if an MFP interrupt ! 262: is to be checked) so we only have one compare during the decode ! 263: instruction loop. ! 264: */ ! 265: void MFP_UpdateFlags(void) ! 266: { ! 267: if( MFP_IPRA|MFP_IPRB ) ! 268: { ! 269: PendingInterruptFlag |= PENDING_INTERRUPT_FLAG_MFP; ! 270: } ! 271: else ! 272: { ! 273: PendingInterruptFlag &= CLEAR_PENDING_INTERRUPT_FLAG_MFP; ! 274: } ! 275: } ! 276: ! 277: //----------------------------------------------------------------------- ! 278: /* ! 279: Interrupt Channel is active, set pending bit so can be serviced ! 280: */ ! 281: void MFP_InputOnChannel(unsigned char Bit,unsigned char EnableBit,unsigned char *pPendingReg) ! 282: { ! 283: // Input has occurred on MFP channel, set interrupt pending to request interrupt when able ! 284: if (EnableBit&Bit) ! 285: *pPendingReg |= Bit; // Set bit ! 286: else ! 287: *pPendingReg &= ~Bit; // Clear bit ! 288: MFP_UpdateFlags(); ! 289: } ! 290: ! 291: //----------------------------------------------------------------------- ! 292: /* ! 293: Generate Timer A Interrupt when in Event Count mode ! 294: */ ! 295: void MFP_TimerA_EventCount_Interrupt(void) ! 296: { ! 297: if (MFP_TA_MAINCOUNTER==1) { // Timer expired? If so, generate interrupt ! 298: MFP_TA_MAINCOUNTER = MFP_TADR; // Reload timer from data register ! 299: ! 300: // Acknowledge in MFP circuit, pass bit,enable,pending ! 301: MFP_InputOnChannel(MFP_TIMER_A_BIT,MFP_IERA,&MFP_IPRA); ! 302: } ! 303: else ! 304: MFP_TA_MAINCOUNTER--; // Subtract timer main counter ! 305: } ! 306: ! 307: //----------------------------------------------------------------------- ! 308: /* ! 309: Generate Timer B Interrupt when in Event Count mode ! 310: */ ! 311: void MFP_TimerB_EventCount_Interrupt(void) ! 312: { ! 313: if (MFP_TB_MAINCOUNTER==1) { // Timer expired? If so, generate interrupt ! 314: MFP_TB_MAINCOUNTER = MFP_TBDR; // Reload timer from data register ! 315: ! 316: // Acknowledge in MFP circuit, pass bit,enable,pending ! 317: MFP_InputOnChannel(MFP_TIMER_B_BIT,MFP_IERA,&MFP_IPRA); ! 318: } ! 319: else ! 320: MFP_TB_MAINCOUNTER--; // Subtract timer main counter ! 321: } ! 322: ! 323: //----------------------------------------------------------------------- ! 324: /* ! 325: Start Timer A or B - EventCount mode is done in HBL handler to time correctly ! 326: */ ! 327: int MFP_StartTimer_AB(unsigned char TimerControl, unsigned int TimerData, int Handler, BOOL bFirstTimer) ! 328: { ! 329: int TimerClockCycles; ! 330: ! 331: /* If we are in event-count mode ignore this(done on HBL) */ ! 332: if (TimerControl!=0x08) { ! 333: /* Find number of CPU cycles for when timer is due(include preset and counter) */ ! 334: /* As timer occurs very often we multiply by counter to speed up emulator */ ! 335: if (TimerData==0) /* Data=0 is actually Data=256 */ ! 336: TimerData = 256; ! 337: TimerClockCycles = ROUND_CYCLES_TO4( TimerData*MFPTimerToCPUCycleTable[TimerControl&0x7] ); ! 338: ! 339: /* And add to our internal interrupt list, if timer cycles is zero then timer is stopped */ ! 340: Int_RemovePendingInterrupt(Handler); ! 341: if (TimerClockCycles) { ! 342: /* Start timer from now? If not continue timer so from original offset */ ! 343: if (bFirstTimer) ! 344: nCyclesOver = 0; ! 345: Int_AddRelativeInterrupt(TimerClockCycles,Handler); ! 346: } ! 347: } ! 348: else { ! 349: /* Make sure no outstanding interrupts in list if channel is disabled */ ! 350: Int_RemovePendingInterrupt(Handler); ! 351: } ! 352: ! 353: return(TimerClockCycles); ! 354: } ! 355: ! 356: //----------------------------------------------------------------------- ! 357: /* ! 358: Start Timer C or D ! 359: */ ! 360: int MFP_StartTimer_CD(unsigned char TimerControl, unsigned int TimerData, int Handler, BOOL bFirstTimer) ! 361: { ! 362: int TimerClockCycles; ! 363: ! 364: /* Is timer on? */ ! 365: if ((TimerControl&0x7)!=0) { ! 366: /* Find number of cycles for when timer is due(include preset and counter) */ ! 367: /* As timer occurs very often we multiply by counter to speed up emulator */ ! 368: if (TimerData==0) /* Data=0 is actually Data=256 */ ! 369: TimerData = 256; ! 370: TimerClockCycles = ROUND_CYCLES_TO4( TimerData*MFPTimerToCPUCycleTable[TimerControl&0x7] ); ! 371: ! 372: /* And add to our internal interrupt list, if timer cycles is zero then timer is stopped */ ! 373: Int_RemovePendingInterrupt(Handler); ! 374: if (TimerClockCycles) { ! 375: /* Start timer from now? If not continue timer so from original offset */ ! 376: if (bFirstTimer) ! 377: nCyclesOver = 0; ! 378: Int_AddRelativeInterrupt(TimerClockCycles,Handler); ! 379: } ! 380: } ! 381: else { ! 382: /* Make sure no outstanding interrupts in list if channel is disabled */ ! 383: Int_RemovePendingInterrupt(Handler); ! 384: } ! 385: ! 386: return(TimerClockCycles); ! 387: } ! 388: ! 389: //----------------------------------------------------------------------- ! 390: /* ! 391: Read Timer A or B - If in EventCount MainCounter already has correct value ! 392: */ ! 393: unsigned char MFP_ReadTimer_AB(unsigned char TimerControl, unsigned char MainCounter, int TimerCycles, int Handler) ! 394: { ! 395: int TimerCyclesPassed; ! 396: ! 397: /* Find TimerAB count, if no interrupt assume in Event Count mode so already up-to-date as kept by HBL */ ! 398: if (Int_InterruptActive(Handler)) { ! 399: /* Find cycles passed since last interrupt */ ! 400: TimerCyclesPassed = TimerCycles-Int_FindCyclesPassed(Handler); ! 401: MainCounter = TimerCyclesPassed/(MFPTimerToCPUCycleTable[TimerControl&0x7]); ! 402: } ! 403: ! 404: return(MainCounter); ! 405: } ! 406: ! 407: //----------------------------------------------------------------------- ! 408: /* ! 409: Read Timer C or D ! 410: */ ! 411: unsigned char MFP_ReadTimerCD(unsigned char TimerControl,unsigned char TimerData, unsigned char MainCounter, int TimerCycles, int Handler) ! 412: { ! 413: int TimerCyclesPassed; ! 414: ! 415: // Find TimerCD count. If not one then timer should be off and can find count from main counter ! 416: if (Int_InterruptActive(Handler)) { ! 417: // Find cycles passed since last interrupt ! 418: TimerCyclesPassed = TimerCycles-Int_FindCyclesPassed(Handler); ! 419: MainCounter = TimerCyclesPassed/(MFPTimerToCPUCycleTable[TimerControl&0x7]); ! 420: } ! 421: else { ! 422: MainCounter = TimerData; ! 423: } ! 424: ! 425: return(MainCounter); ! 426: } ! 427: ! 428: //----------------------------------------------------------------------- ! 429: /* ! 430: Start Timer A ! 431: (This does not start the EventCount mode time as this is taken care of by the HBL) ! 432: */ ! 433: void MFP_StartTimerA(void) ! 434: { ! 435: TimerAClockCycles = MFP_StartTimer_AB(MFP_TACR,MFP_TADR,INTERRUPT_MFP_TIMERA,TRUE); ! 436: } ! 437: ! 438: ! 439: //----------------------------------------------------------------------- ! 440: /* ! 441: Read Timer A ! 442: */ ! 443: void MFP_ReadTimerA(void) ! 444: { ! 445: MFP_TA_MAINCOUNTER = MFP_ReadTimer_AB(MFP_TACR,MFP_TA_MAINCOUNTER,TimerAClockCycles,INTERRUPT_MFP_TIMERA); ! 446: } ! 447: ! 448: ! 449: //----------------------------------------------------------------------- ! 450: /* ! 451: Start Timer B ! 452: (This does not start the EventCount mode time as this is taken care of by the HBL) ! 453: */ ! 454: void MFP_StartTimerB(void) ! 455: { ! 456: TimerBClockCycles = MFP_StartTimer_AB(MFP_TBCR,MFP_TBDR,INTERRUPT_MFP_TIMERB,TRUE); ! 457: } ! 458: ! 459: ! 460: //----------------------------------------------------------------------- ! 461: /* ! 462: Read Timer B ! 463: */ ! 464: void MFP_ReadTimerB(void) ! 465: { ! 466: MFP_TB_MAINCOUNTER = MFP_ReadTimer_AB(MFP_TBCR,MFP_TB_MAINCOUNTER,TimerBClockCycles,INTERRUPT_MFP_TIMERB); ! 467: } ! 468: ! 469: ! 470: //----------------------------------------------------------------------- ! 471: /* ! 472: Start Timer C ! 473: */ ! 474: void MFP_StartTimerC(void) ! 475: { ! 476: TimerCClockCycles = MFP_StartTimer_CD(MFP_TCDCR>>4,MFP_TCDR,INTERRUPT_MFP_TIMERC,TRUE); ! 477: } ! 478: ! 479: ! 480: //----------------------------------------------------------------------- ! 481: /* ! 482: Read Timer C ! 483: */ ! 484: void MFP_ReadTimerC(void) ! 485: { ! 486: MFP_TC_MAINCOUNTER = MFP_ReadTimerCD(MFP_TCDCR>>4,MFP_TCDR,MFP_TC_MAINCOUNTER,TimerCClockCycles,INTERRUPT_MFP_TIMERC); ! 487: } ! 488: ! 489: ! 490: //----------------------------------------------------------------------- ! 491: /* ! 492: Start Timer D ! 493: */ ! 494: void MFP_StartTimerD(void) ! 495: { ! 496: TimerDClockCycles = MFP_StartTimer_CD(MFP_TCDCR,MFP_TDDR,INTERRUPT_MFP_TIMERD,TRUE); ! 497: } ! 498: ! 499: ! 500: //----------------------------------------------------------------------- ! 501: /* ! 502: Read Timer D ! 503: */ ! 504: void MFP_ReadTimerD(void) ! 505: { ! 506: MFP_TD_MAINCOUNTER = MFP_ReadTimerCD(MFP_TCDCR,MFP_TDDR,MFP_TC_MAINCOUNTER,TimerDClockCycles,INTERRUPT_MFP_TIMERD); ! 507: } ! 508: ! 509: ! 510: //----------------------------------------------------------------------- ! 511: /* ! 512: Handle Timer A Interrupt ! 513: */ ! 514: void MFP_InterruptHandler_TimerA(void) ! 515: { ! 516: // Remove this interrupt from list and re-order ! 517: Int_AcknowledgeInterrupt(); ! 518: ! 519: // Acknowledge in MFP circuit, pass bit,enable,pending ! 520: if ((MFP_TACR&0xf)!=0) // Is timer OK? ! 521: MFP_InputOnChannel(MFP_TIMER_A_BIT,MFP_IERA,&MFP_IPRA); ! 522: ! 523: // Start next interrupt, if need one - from current cycle count ! 524: TimerAClockCycles = MFP_StartTimer_AB(MFP_TACR,MFP_TADR,INTERRUPT_MFP_TIMERA,FALSE); ! 525: } ! 526: ! 527: ! 528: //----------------------------------------------------------------------- ! 529: /* ! 530: Handle Timer B Interrupt ! 531: */ ! 532: void MFP_InterruptHandler_TimerB(void) ! 533: { ! 534: // Remove this interrupt from list and re-order ! 535: Int_AcknowledgeInterrupt(); ! 536: ! 537: // Acknowledge in MFP circuit, pass bit,enable,pending ! 538: if ((MFP_TBCR&0xf)!=0) // Is timer OK? ! 539: MFP_InputOnChannel(MFP_TIMER_B_BIT,MFP_IERA,&MFP_IPRA); ! 540: ! 541: // Start next interrupt, if need one - from current cycle count ! 542: TimerBClockCycles = MFP_StartTimer_AB(MFP_TBCR,MFP_TBDR,INTERRUPT_MFP_TIMERB,FALSE); ! 543: } ! 544: ! 545: ! 546: //----------------------------------------------------------------------- ! 547: /* ! 548: Handle Timer C Interrupt ! 549: */ ! 550: void MFP_InterruptHandler_TimerC(void) ! 551: { ! 552: // Remove this interrupt from list and re-order ! 553: Int_AcknowledgeInterrupt(); ! 554: ! 555: // Acknowledge in MFP circuit, pass bit,enable,pending ! 556: if ((MFP_TCDCR&0x70)!=0) // Is timer OK? ! 557: MFP_InputOnChannel(MFP_TIMER_C_BIT,MFP_IERB,&MFP_IPRB); ! 558: ! 559: // Start next interrupt, if need one - from current cycle count ! 560: TimerCClockCycles = MFP_StartTimer_CD(MFP_TCDCR>>4,MFP_TCDR,INTERRUPT_MFP_TIMERC,FALSE); ! 561: } ! 562: ! 563: ! 564: //----------------------------------------------------------------------- ! 565: /* ! 566: Handle Timer D Interrupt ! 567: */ ! 568: void MFP_InterruptHandler_TimerD(void) ! 569: { ! 570: // Remove this interrupt from list and re-order ! 571: Int_AcknowledgeInterrupt(); ! 572: ! 573: // Acknowledge in MFP circuit, pass bit,enable,pending ! 574: if ((MFP_TCDCR&0x07)!=0) // Is timer OK? ! 575: MFP_InputOnChannel(MFP_TIMER_D_BIT,MFP_IERB,&MFP_IPRB); ! 576: ! 577: // Start next interrupt, if need one - from current cycle count ! 578: TimerDClockCycles = MFP_StartTimer_CD(MFP_TCDCR,MFP_TDDR,INTERRUPT_MFP_TIMERD,FALSE); ! 579: } ! 580:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.