|
|
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.