|
|
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:
1.1.1.2 ! root 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) */
1.1 root 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[] = {
1.1.1.2 ! root 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 */
1.1 root 88: };
89:
90:
1.1.1.2 ! root 91: /*-----------------------------------------------------------------------*/
1.1 root 92: /*
93: Reset all MFP variables and start interrupts on their way!
94: */
95: void MFP_Reset(void)
96: {
1.1.1.2 ! root 97: /* Reset MFP internal variables */
1.1 root 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:
1.1.1.2 ! root 110: /* Clear counters */
1.1 root 111: TimerAClockCycles = TimerBClockCycles = TimerCClockCycles = TimerDClockCycles = 0;
112: }
113:
1.1.1.2 ! root 114:
! 115: /*-----------------------------------------------------------------------*/
1.1 root 116: /*
117: Save/Restore snapshot of local variables('MemorySnapShot_Store' handles type)
118: */
119: void MFP_MemorySnapShot_Capture(BOOL bSave)
120: {
1.1.1.2 ! root 121: /* Save/Restore details */
1.1 root 122: MemorySnapShot_Store(&MFP_GPIP,sizeof(MFP_GPIP));
123: MemorySnapShot_Store(&MFP_AER,sizeof(MFP_AER));
124: MemorySnapShot_Store(&MFP_DDR,sizeof(MFP_DDR));
125: MemorySnapShot_Store(&MFP_IERA,sizeof(MFP_IERA));
126: MemorySnapShot_Store(&MFP_IERB,sizeof(MFP_IERB));
127: MemorySnapShot_Store(&MFP_IPRA,sizeof(MFP_IPRA));
128: MemorySnapShot_Store(&MFP_IPRB,sizeof(MFP_IPRB));
129: MemorySnapShot_Store(&MFP_ISRA,sizeof(MFP_ISRA));
130: MemorySnapShot_Store(&MFP_ISRB,sizeof(MFP_ISRB));
131: MemorySnapShot_Store(&MFP_IMRA,sizeof(MFP_IMRA));
132: MemorySnapShot_Store(&MFP_IMRB,sizeof(MFP_IMRB));
133: MemorySnapShot_Store(&MFP_VR,sizeof(MFP_VR));
134: MemorySnapShot_Store(&MFP_TACR,sizeof(MFP_TACR));
135: MemorySnapShot_Store(&MFP_TBCR,sizeof(MFP_TBCR));
136: MemorySnapShot_Store(&MFP_TCDCR,sizeof(MFP_TCDCR));
137: MemorySnapShot_Store(&MFP_TADR,sizeof(MFP_TADR));
138: MemorySnapShot_Store(&MFP_TBDR,sizeof(MFP_TBDR));
139: MemorySnapShot_Store(&MFP_TCDR,sizeof(MFP_TCDR));
140: MemorySnapShot_Store(&MFP_TDDR,sizeof(MFP_TDDR));
141: MemorySnapShot_Store(&MFP_TA_MAINCOUNTER,sizeof(MFP_TA_MAINCOUNTER));
142: MemorySnapShot_Store(&MFP_TB_MAINCOUNTER,sizeof(MFP_TB_MAINCOUNTER));
143: MemorySnapShot_Store(&MFP_TC_MAINCOUNTER,sizeof(MFP_TC_MAINCOUNTER));
144: MemorySnapShot_Store(&MFP_TD_MAINCOUNTER,sizeof(MFP_TD_MAINCOUNTER));
145: MemorySnapShot_Store(&TimerAClockCycles,sizeof(TimerAClockCycles));
146: MemorySnapShot_Store(&TimerBClockCycles,sizeof(TimerBClockCycles));
147: MemorySnapShot_Store(&TimerCClockCycles,sizeof(TimerCClockCycles));
148: MemorySnapShot_Store(&TimerDClockCycles,sizeof(TimerDClockCycles));
149: }
150:
1.1.1.2 ! root 151:
! 152: /*-----------------------------------------------------------------------*/
1.1 root 153: /*
154: Call MFP interrupt - NOTE when the MFP is in Auto interrupt (AEI), the MFP
155: puts the interrupt number on the data bus and then the 68000 reads it, multiplies
156: it by 4 and adds in a base(usually 0x100) to give the vector. Some programs
157: change this offset, eg RoboCod. This offset is stored in the top 4 bits of register
158: 0xfffa17(0x40 is the default=0x100)
159: Many thanks to Steve Bak for that one!
160: */
161: void MFP_Exception(int Interrupt)
162: {
163: unsigned int Vec;
164:
165: Vec = (unsigned int)(MFP_VR&0xf0)<<2;
166: Vec += Interrupt<<2;
167: ExceptionVector = Vec;
168: M68000_Exception();
169: }
170:
1.1.1.2 ! root 171:
! 172: /*-----------------------------------------------------------------------*/
1.1 root 173: /*
174: Test interrupt request to see if can cause exception,return TRUE if pass vector
175: */
176: 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)
177: {
1.1.1.2 ! root 178: /* Are any higher priority interupts in service? */
1.1 root 179: if ( ((MFP_ISRA&PriorityMaskLow)==0) && ((MFP_ISRB&PriorityMaskHigh)==0) ) {
1.1.1.2 ! root 180: /* Is masked? */
1.1 root 181: if (MaskRegister&Bit) {
182: //u if (7>FIND_IPL) {
1.1.1.2 ! root 183: //u *pPendingReg &= ~Bit; /* Clear pending bit */
1.1 root 184: //u MFP_UpdateFlags();
185: //u }
186:
1.1.1.2 ! root 187: /* CPU allows interrupt of an MFP level? */
1.1 root 188: if (6>FIND_IPL) {
1.1.1.2 ! root 189: *pPendingReg &= ~Bit; /* Clear pending bit */
1.1 root 190: MFP_UpdateFlags();
191:
1.1.1.2 ! root 192: /* Are we in 'auto' interrupt or 'manual'? */
! 193: if (MFP_VR&0x08) /* Software End-of-Interrupt (SEI) */
! 194: *pInServiceReg |= Bit; /* Set interrupt in service register */
1.1 root 195: else
1.1.1.2 ! root 196: *pInServiceReg &= ~Bit; /* Clear interrupt in service register */
1.1 root 197:
1.1.1.2 ! root 198: /* Call interrupt, adds in base (default 0x100) */
1.1 root 199: MFP_Exception(Exception);
200: return(TRUE);
201: }
202: }
203: }
204:
205: return(FALSE);
206: }
207:
1.1.1.2 ! root 208:
! 209: /*-----------------------------------------------------------------------*/
1.1 root 210: /*
211: MFP circuit has pending interrupt, request
212: */
213: void MFP_RequestInterrupt_TimerA(void)
214: {
215: InterruptRequest(MFP_EXCEPT_TIMERA,MFP_TIMER_A_BIT,MFP_IERA,&MFP_IPRA,MFP_IMRA,0xe0,0x00&IGNORE_FDC_PRIORITY,&MFP_ISRA);
216: }
217: void MFP_RequestInterrupt_TimerB(void)
218: {
219: InterruptRequest(MFP_EXCEPT_TIMERB,MFP_TIMER_B_BIT,MFP_IERA,&MFP_IPRA,MFP_IMRA,0xff,0x00&IGNORE_FDC_PRIORITY,&MFP_ISRA);
220: }
221: void MFP_RequestInterrupt_TimerC(void)
222: {
223: InterruptRequest(MFP_EXCEPT_TIMERC,MFP_TIMER_C_BIT,MFP_IERB,&MFP_IPRB,MFP_IMRB,0xff,0xe0&IGNORE_FDC_PRIORITY,&MFP_ISRB);
224: }
225: void MFP_RequestInterrupt_TimerD(void)
226: {
227: InterruptRequest(MFP_EXCEPT_TIMERD,MFP_TIMER_D_BIT,MFP_IERB,&MFP_IPRB,MFP_IMRB,0xff,0xf0&IGNORE_FDC_PRIORITY,&MFP_ISRB);
228: }
229: void MFP_RequestInterrupt_Keyboard(void)
230: {
231: InterruptRequest(MFP_EXCEPT_KEYBOARD,MFP_KEYBOARD_BIT,MFP_IERB,&MFP_IPRB,MFP_IMRB,0xff,0xc0&IGNORE_FDC_PRIORITY,&MFP_ISRB);
232: }
233: void MFP_RequestInterrupt_Floppy(void)
234: {
235: InterruptRequest(MFP_EXCEPT_GPIP5,MFP_FDCHDC_BIT,MFP_IERB,&MFP_IPRB,MFP_IMRB,0xff,0x80&IGNORE_FDC_PRIORITY,&MFP_ISRB);
236: }
237:
1.1.1.2 ! root 238:
! 239: /*-----------------------------------------------------------------------*/
1.1 root 240: /*
241: Check 'pending' registers to see if any MFP interrupts need servicing
242: */
243: void MFP_CheckPendingInterrupts(void)
244: {
245: unsigned short i;
246:
247: i = (MFP_IPRA<<8) | MFP_IPRB;
248:
249: if( (i&0x21f0)==0 )
250: { /* Should never get here, but if do just clear flag (see 'MFP_UpdateFlags') */
251: PendingInterruptFlag &= CLEAR_PENDING_INTERRUPT_FLAG_MFP;
252: return;
253: }
254:
255: if( i&0x2000 ) MFP_RequestInterrupt_TimerA(); /* Check Timer A (bit 5) */
256: if( i&0x0100 ) MFP_RequestInterrupt_TimerB(); /* Check Timer B (bit 0) */
257: if( i&0x0080 ) MFP_RequestInterrupt_Floppy(); /* Check FDC (bit 7) */
258: if( i&0x0040 ) MFP_RequestInterrupt_Keyboard(); /* Check Keyboard (bit 6) */
259: if( i&0x0020 ) MFP_RequestInterrupt_TimerC(); /* Check Timer C (bit 5) */
260: if( i&0x0010 ) MFP_RequestInterrupt_TimerD(); /* Check Timer D (bit 4) */
261: }
262:
1.1.1.2 ! root 263:
! 264: /*-----------------------------------------------------------------------*/
1.1 root 265: /*
266: This is called whenever the MFP_IPRA or MFP_IPRB registers are modified.
267: We set the 'PendingInterruptFlag' accordingly (to say if an MFP interrupt
268: is to be checked) so we only have one compare during the decode
269: instruction loop.
270: */
271: void MFP_UpdateFlags(void)
272: {
273: if( MFP_IPRA|MFP_IPRB )
274: {
275: PendingInterruptFlag |= PENDING_INTERRUPT_FLAG_MFP;
276: }
277: else
278: {
279: PendingInterruptFlag &= CLEAR_PENDING_INTERRUPT_FLAG_MFP;
280: }
281: }
282:
1.1.1.2 ! root 283:
! 284: /*-----------------------------------------------------------------------*/
1.1 root 285: /*
286: Interrupt Channel is active, set pending bit so can be serviced
287: */
288: void MFP_InputOnChannel(unsigned char Bit,unsigned char EnableBit,unsigned char *pPendingReg)
289: {
1.1.1.2 ! root 290: /* Input has occurred on MFP channel, set interrupt pending to request interrupt when able */
1.1 root 291: if (EnableBit&Bit)
1.1.1.2 ! root 292: *pPendingReg |= Bit; /* Set bit */
1.1 root 293: else
1.1.1.2 ! root 294: *pPendingReg &= ~Bit; /* Clear bit */
1.1 root 295: MFP_UpdateFlags();
296: }
297:
1.1.1.2 ! root 298:
! 299: /*-----------------------------------------------------------------------*/
1.1 root 300: /*
301: Generate Timer A Interrupt when in Event Count mode
302: */
303: void MFP_TimerA_EventCount_Interrupt(void)
304: {
1.1.1.2 ! root 305: if (MFP_TA_MAINCOUNTER==1) { /* Timer expired? If so, generate interrupt */
! 306: MFP_TA_MAINCOUNTER = MFP_TADR; /* Reload timer from data register */
1.1 root 307:
1.1.1.2 ! root 308: /* Acknowledge in MFP circuit, pass bit,enable,pending */
1.1 root 309: MFP_InputOnChannel(MFP_TIMER_A_BIT,MFP_IERA,&MFP_IPRA);
310: }
311: else
1.1.1.2 ! root 312: MFP_TA_MAINCOUNTER--; /* Subtract timer main counter */
1.1 root 313: }
314:
1.1.1.2 ! root 315:
! 316: /*-----------------------------------------------------------------------*/
1.1 root 317: /*
318: Generate Timer B Interrupt when in Event Count mode
319: */
320: void MFP_TimerB_EventCount_Interrupt(void)
321: {
1.1.1.2 ! root 322: if (MFP_TB_MAINCOUNTER==1) { /* Timer expired? If so, generate interrupt */
! 323: MFP_TB_MAINCOUNTER = MFP_TBDR; /* Reload timer from data register */
1.1 root 324:
1.1.1.2 ! root 325: /* Acknowledge in MFP circuit, pass bit,enable,pending */
1.1 root 326: MFP_InputOnChannel(MFP_TIMER_B_BIT,MFP_IERA,&MFP_IPRA);
327: }
328: else
1.1.1.2 ! root 329: MFP_TB_MAINCOUNTER--; /* Subtract timer main counter */
1.1 root 330: }
331:
1.1.1.2 ! root 332:
! 333: /*-----------------------------------------------------------------------*/
1.1 root 334: /*
335: Start Timer A or B - EventCount mode is done in HBL handler to time correctly
336: */
337: int MFP_StartTimer_AB(unsigned char TimerControl, unsigned int TimerData, int Handler, BOOL bFirstTimer)
338: {
339: int TimerClockCycles;
340:
341: /* If we are in event-count mode ignore this(done on HBL) */
342: if (TimerControl!=0x08) {
343: /* Find number of CPU cycles for when timer is due(include preset and counter) */
344: /* As timer occurs very often we multiply by counter to speed up emulator */
345: if (TimerData==0) /* Data=0 is actually Data=256 */
346: TimerData = 256;
347: TimerClockCycles = ROUND_CYCLES_TO4( TimerData*MFPTimerToCPUCycleTable[TimerControl&0x7] );
348:
349: /* And add to our internal interrupt list, if timer cycles is zero then timer is stopped */
350: Int_RemovePendingInterrupt(Handler);
351: if (TimerClockCycles) {
352: /* Start timer from now? If not continue timer so from original offset */
353: if (bFirstTimer)
354: nCyclesOver = 0;
355: Int_AddRelativeInterrupt(TimerClockCycles,Handler);
356: }
357: }
358: else {
359: /* Make sure no outstanding interrupts in list if channel is disabled */
360: Int_RemovePendingInterrupt(Handler);
361: }
362:
363: return(TimerClockCycles);
364: }
365:
1.1.1.2 ! root 366:
! 367: /*-----------------------------------------------------------------------*/
1.1 root 368: /*
369: Start Timer C or D
370: */
371: int MFP_StartTimer_CD(unsigned char TimerControl, unsigned int TimerData, int Handler, BOOL bFirstTimer)
372: {
373: int TimerClockCycles;
374:
375: /* Is timer on? */
376: if ((TimerControl&0x7)!=0) {
377: /* Find number of cycles for when timer is due(include preset and counter) */
378: /* As timer occurs very often we multiply by counter to speed up emulator */
379: if (TimerData==0) /* Data=0 is actually Data=256 */
380: TimerData = 256;
381: TimerClockCycles = ROUND_CYCLES_TO4( TimerData*MFPTimerToCPUCycleTable[TimerControl&0x7] );
382:
383: /* And add to our internal interrupt list, if timer cycles is zero then timer is stopped */
384: Int_RemovePendingInterrupt(Handler);
385: if (TimerClockCycles) {
386: /* Start timer from now? If not continue timer so from original offset */
387: if (bFirstTimer)
388: nCyclesOver = 0;
389: Int_AddRelativeInterrupt(TimerClockCycles,Handler);
390: }
391: }
392: else {
393: /* Make sure no outstanding interrupts in list if channel is disabled */
394: Int_RemovePendingInterrupt(Handler);
395: }
396:
397: return(TimerClockCycles);
398: }
399:
1.1.1.2 ! root 400:
! 401: /*-----------------------------------------------------------------------*/
1.1 root 402: /*
403: Read Timer A or B - If in EventCount MainCounter already has correct value
404: */
405: unsigned char MFP_ReadTimer_AB(unsigned char TimerControl, unsigned char MainCounter, int TimerCycles, int Handler)
406: {
407: int TimerCyclesPassed;
408:
409: /* Find TimerAB count, if no interrupt assume in Event Count mode so already up-to-date as kept by HBL */
410: if (Int_InterruptActive(Handler)) {
411: /* Find cycles passed since last interrupt */
412: TimerCyclesPassed = TimerCycles-Int_FindCyclesPassed(Handler);
413: MainCounter = TimerCyclesPassed/(MFPTimerToCPUCycleTable[TimerControl&0x7]);
414: }
415:
416: return(MainCounter);
417: }
418:
1.1.1.2 ! root 419:
! 420: /*-----------------------------------------------------------------------*/
1.1 root 421: /*
422: Read Timer C or D
423: */
424: unsigned char MFP_ReadTimerCD(unsigned char TimerControl,unsigned char TimerData, unsigned char MainCounter, int TimerCycles, int Handler)
425: {
426: int TimerCyclesPassed;
427:
1.1.1.2 ! root 428: /* Find TimerCD count. If not one then timer should be off and can find count from main counter */
1.1 root 429: if (Int_InterruptActive(Handler)) {
1.1.1.2 ! root 430: /* Find cycles passed since last interrupt */
1.1 root 431: TimerCyclesPassed = TimerCycles-Int_FindCyclesPassed(Handler);
432: MainCounter = TimerCyclesPassed/(MFPTimerToCPUCycleTable[TimerControl&0x7]);
433: }
434: else {
435: MainCounter = TimerData;
436: }
437:
438: return(MainCounter);
439: }
440:
1.1.1.2 ! root 441:
! 442: /*-----------------------------------------------------------------------*/
1.1 root 443: /*
444: Start Timer A
445: (This does not start the EventCount mode time as this is taken care of by the HBL)
446: */
447: void MFP_StartTimerA(void)
448: {
449: TimerAClockCycles = MFP_StartTimer_AB(MFP_TACR,MFP_TADR,INTERRUPT_MFP_TIMERA,TRUE);
450: }
451:
452:
1.1.1.2 ! root 453: /*-----------------------------------------------------------------------*/
1.1 root 454: /*
455: Read Timer A
456: */
457: void MFP_ReadTimerA(void)
458: {
459: MFP_TA_MAINCOUNTER = MFP_ReadTimer_AB(MFP_TACR,MFP_TA_MAINCOUNTER,TimerAClockCycles,INTERRUPT_MFP_TIMERA);
460: }
461:
462:
1.1.1.2 ! root 463: /*-----------------------------------------------------------------------*/
1.1 root 464: /*
465: Start Timer B
466: (This does not start the EventCount mode time as this is taken care of by the HBL)
467: */
468: void MFP_StartTimerB(void)
469: {
470: TimerBClockCycles = MFP_StartTimer_AB(MFP_TBCR,MFP_TBDR,INTERRUPT_MFP_TIMERB,TRUE);
471: }
472:
473:
1.1.1.2 ! root 474: /*-----------------------------------------------------------------------*/
1.1 root 475: /*
476: Read Timer B
477: */
478: void MFP_ReadTimerB(void)
479: {
480: MFP_TB_MAINCOUNTER = MFP_ReadTimer_AB(MFP_TBCR,MFP_TB_MAINCOUNTER,TimerBClockCycles,INTERRUPT_MFP_TIMERB);
481: }
482:
483:
1.1.1.2 ! root 484: /*-----------------------------------------------------------------------*/
1.1 root 485: /*
486: Start Timer C
487: */
488: void MFP_StartTimerC(void)
489: {
490: TimerCClockCycles = MFP_StartTimer_CD(MFP_TCDCR>>4,MFP_TCDR,INTERRUPT_MFP_TIMERC,TRUE);
491: }
492:
493:
1.1.1.2 ! root 494: /*-----------------------------------------------------------------------*/
1.1 root 495: /*
496: Read Timer C
497: */
498: void MFP_ReadTimerC(void)
499: {
500: MFP_TC_MAINCOUNTER = MFP_ReadTimerCD(MFP_TCDCR>>4,MFP_TCDR,MFP_TC_MAINCOUNTER,TimerCClockCycles,INTERRUPT_MFP_TIMERC);
501: }
502:
503:
1.1.1.2 ! root 504: /*-----------------------------------------------------------------------*/
1.1 root 505: /*
506: Start Timer D
507: */
508: void MFP_StartTimerD(void)
509: {
510: TimerDClockCycles = MFP_StartTimer_CD(MFP_TCDCR,MFP_TDDR,INTERRUPT_MFP_TIMERD,TRUE);
511: }
512:
513:
1.1.1.2 ! root 514: /*-----------------------------------------------------------------------*/
1.1 root 515: /*
516: Read Timer D
517: */
518: void MFP_ReadTimerD(void)
519: {
520: MFP_TD_MAINCOUNTER = MFP_ReadTimerCD(MFP_TCDCR,MFP_TDDR,MFP_TC_MAINCOUNTER,TimerDClockCycles,INTERRUPT_MFP_TIMERD);
521: }
522:
523:
1.1.1.2 ! root 524: /*-----------------------------------------------------------------------*/
1.1 root 525: /*
526: Handle Timer A Interrupt
527: */
528: void MFP_InterruptHandler_TimerA(void)
529: {
1.1.1.2 ! root 530: /* Remove this interrupt from list and re-order */
1.1 root 531: Int_AcknowledgeInterrupt();
532:
1.1.1.2 ! root 533: /* Acknowledge in MFP circuit, pass bit,enable,pending */
! 534: if ((MFP_TACR&0xf)!=0) /* Is timer OK? */
1.1 root 535: MFP_InputOnChannel(MFP_TIMER_A_BIT,MFP_IERA,&MFP_IPRA);
536:
1.1.1.2 ! root 537: /* Start next interrupt, if need one - from current cycle count */
1.1 root 538: TimerAClockCycles = MFP_StartTimer_AB(MFP_TACR,MFP_TADR,INTERRUPT_MFP_TIMERA,FALSE);
539: }
540:
541:
1.1.1.2 ! root 542: /*-----------------------------------------------------------------------*/
1.1 root 543: /*
544: Handle Timer B Interrupt
545: */
546: void MFP_InterruptHandler_TimerB(void)
547: {
1.1.1.2 ! root 548: /* Remove this interrupt from list and re-order */
1.1 root 549: Int_AcknowledgeInterrupt();
550:
1.1.1.2 ! root 551: /* Acknowledge in MFP circuit, pass bit, enable, pending */
! 552: if ((MFP_TBCR&0xf)!=0) /* Is timer OK? */
1.1 root 553: MFP_InputOnChannel(MFP_TIMER_B_BIT,MFP_IERA,&MFP_IPRA);
554:
1.1.1.2 ! root 555: /* Start next interrupt, if need one - from current cycle count */
1.1 root 556: TimerBClockCycles = MFP_StartTimer_AB(MFP_TBCR,MFP_TBDR,INTERRUPT_MFP_TIMERB,FALSE);
557: }
558:
559:
1.1.1.2 ! root 560: /*-----------------------------------------------------------------------*/
1.1 root 561: /*
562: Handle Timer C Interrupt
563: */
564: void MFP_InterruptHandler_TimerC(void)
565: {
1.1.1.2 ! root 566: /* Remove this interrupt from list and re-order */
1.1 root 567: Int_AcknowledgeInterrupt();
568:
1.1.1.2 ! root 569: /* Acknowledge in MFP circuit, pass bit, enable, pending */
! 570: if ((MFP_TCDCR&0x70)!=0) /* Is timer OK? */
1.1 root 571: MFP_InputOnChannel(MFP_TIMER_C_BIT,MFP_IERB,&MFP_IPRB);
572:
1.1.1.2 ! root 573: /* Start next interrupt, if need one - from current cycle count */
1.1 root 574: TimerCClockCycles = MFP_StartTimer_CD(MFP_TCDCR>>4,MFP_TCDR,INTERRUPT_MFP_TIMERC,FALSE);
575: }
576:
577:
1.1.1.2 ! root 578: /*-----------------------------------------------------------------------*/
1.1 root 579: /*
580: Handle Timer D Interrupt
581: */
582: void MFP_InterruptHandler_TimerD(void)
583: {
1.1.1.2 ! root 584: /* Remove this interrupt from list and re-order */
1.1 root 585: Int_AcknowledgeInterrupt();
586:
1.1.1.2 ! root 587: /* Acknowledge in MFP circuit, pass bit, enable, pending */
! 588: if ((MFP_TCDCR&0x07)!=0) /* Is timer OK? */
1.1 root 589: MFP_InputOnChannel(MFP_TIMER_D_BIT,MFP_IERB,&MFP_IPRB);
590:
1.1.1.2 ! root 591: /* Start next interrupt, if need one - from current cycle count */
1.1 root 592: TimerDClockCycles = MFP_StartTimer_CD(MFP_TCDCR,MFP_TDDR,INTERRUPT_MFP_TIMERD,FALSE);
593: }
594:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.