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