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