|
|
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.8 ! root 17: char MFP_rcsid[] = "Hatari $Id: mfp.c,v 1.18 2005/04/05 14:41:30 thothy Exp $";
1.1 root 18:
19: #include "main.h"
1.1.1.8 ! root 20: #include "configuration.h"
1.1 root 21: #include "fdc.h"
22: #include "ikbd.h"
23: #include "int.h"
1.1.1.8 ! root 24: #include "ioMem.h"
1.1 root 25: #include "m68000.h"
26: #include "memorySnapShot.h"
27: #include "mfp.h"
28: #include "psg.h"
1.1.1.8 ! root 29: #include "rs232.h"
1.1 root 30: #include "sound.h"
1.1.1.8 ! root 31: #include "tos.h"
1.1 root 32: #include "video.h"
1.1.1.3 root 33:
1.1 root 34:
35: /*
36: MFP interrupt channel circuit:-
37:
38: EdgeRegister EnableRegister MaskRegister SBit
39: | | | |
40: | | | | ------------------------
41: | | ------------------------ ---\ |---\ | |
42: | o--\ | | AND---o----------------AND---| S InterruptInService |
43: ---\ | AND---| S InterruptPending O |-------/ | |---/ | |
44: XOR----------)--/ | R | | | ------------------------
45: Input -----/ | ------------------------ | |
46: | | InterruptRequest |
47: NOT OR |
48: | | | |
49: -------------------- --------------------------------------o--- PassVector
50: */
51:
1.1.1.7 root 52:
53: /*-----------------------------------------------------------------------*/
54: /* Set clock times for each instruction, see '68000 timing' pages for details */
55: #define ROUND_CYCLES_TO4(var) (((int)(var)+3)&0xfffffffc)
56:
1.1 root 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 */
1.1.1.7 root 75: static int TimerAClockCycles=0;
76: static int TimerBClockCycles=0;
77: static int TimerCClockCycles=0;
78: static int TimerDClockCycles=0;
79:
80: BOOL bAppliedTimerDPatch; /* TRUE if the Timer-D patch has been applied */
1.1.1.8 ! root 81: static int nTimerDFakeValue; /* Faked Timer-D data register for the Timer-D patch */
! 82:
1.1 root 83:
84: /*
85: Number of CPU cycles for Timer C+D
86: These figures were based on 50Hz=160256cycles, so 200Hz=40064
87: Now, Timer C set on a delay of 192($C0) and a preset DIV of 64 is 200Hz
88: This makes the table entry 208.66666*192=40064(200Hz)
89: */
1.1.1.7 root 90: static float MFPTimerToCPUCycleTable[] = {
1.1.1.2 root 91: 0, /* Timer Stop */
92: 13.04166667f, /* Div by 4 */
93: 32.60416667f, /* Div by 10 */
94: 52.16666667f, /* Div by 16 */
95: 163.02083333f, /* Div by 50 */
96: 208.66666667f, /* Div by 64 */
97: 326.04166667f, /* Div by 100 */
98: 652.08333333f /* Div by 200 */
1.1 root 99: };
100:
101:
1.1.1.2 root 102: /*-----------------------------------------------------------------------*/
1.1 root 103: /*
104: Reset all MFP variables and start interrupts on their way!
105: */
106: void MFP_Reset(void)
107: {
1.1.1.2 root 108: /* Reset MFP internal variables */
1.1.1.7 root 109:
110: bAppliedTimerDPatch = FALSE;
111:
112: /* NOTE Matthias Arndt <[email protected]> 9 Aug 2003
113: * according to the Atari ST Profibuch, Bit0 of GPIP Data Register
114: * is the BUSY signal of the printer port
115: * it is SET if no printer is connected or on BUSY
116: * therefor we should assume it to be 0 in Hatari as printer busy is
117: * all handled in the Printer submodule
118: */
119:
120: MFP_GPIP = 0xfe; /* Set GPIP register (all 1's except bit0 = no interrupts) */
1.1 root 121: MFP_AER = MFP_DDR = 0;
122: MFP_IERA = MFP_IERB = 0;
123: MFP_IPRA = MFP_IPRB = 0;
124: MFP_ISRA = MFP_ISRB = 0;
125: MFP_IMRA = MFP_IMRB = 0;
126: MFP_VR = 0;
127: MFP_TACR = MFP_TBCR = MFP_TCDCR = 0;
128: MFP_TADR = MFP_TBDR = 0;
129: MFP_TCDR = MFP_TDDR = 0;
130: MFP_TA_MAINCOUNTER = MFP_TB_MAINCOUNTER = MFP_TC_MAINCOUNTER = MFP_TD_MAINCOUNTER = 0;
131:
1.1.1.2 root 132: /* Clear counters */
1.1 root 133: TimerAClockCycles = TimerBClockCycles = TimerCClockCycles = TimerDClockCycles = 0;
134: }
135:
1.1.1.2 root 136:
137: /*-----------------------------------------------------------------------*/
1.1 root 138: /*
139: Save/Restore snapshot of local variables('MemorySnapShot_Store' handles type)
140: */
141: void MFP_MemorySnapShot_Capture(BOOL bSave)
142: {
1.1.1.2 root 143: /* Save/Restore details */
1.1 root 144: MemorySnapShot_Store(&MFP_GPIP,sizeof(MFP_GPIP));
145: MemorySnapShot_Store(&MFP_AER,sizeof(MFP_AER));
146: MemorySnapShot_Store(&MFP_DDR,sizeof(MFP_DDR));
147: MemorySnapShot_Store(&MFP_IERA,sizeof(MFP_IERA));
148: MemorySnapShot_Store(&MFP_IERB,sizeof(MFP_IERB));
149: MemorySnapShot_Store(&MFP_IPRA,sizeof(MFP_IPRA));
150: MemorySnapShot_Store(&MFP_IPRB,sizeof(MFP_IPRB));
151: MemorySnapShot_Store(&MFP_ISRA,sizeof(MFP_ISRA));
152: MemorySnapShot_Store(&MFP_ISRB,sizeof(MFP_ISRB));
153: MemorySnapShot_Store(&MFP_IMRA,sizeof(MFP_IMRA));
154: MemorySnapShot_Store(&MFP_IMRB,sizeof(MFP_IMRB));
155: MemorySnapShot_Store(&MFP_VR,sizeof(MFP_VR));
156: MemorySnapShot_Store(&MFP_TACR,sizeof(MFP_TACR));
157: MemorySnapShot_Store(&MFP_TBCR,sizeof(MFP_TBCR));
158: MemorySnapShot_Store(&MFP_TCDCR,sizeof(MFP_TCDCR));
159: MemorySnapShot_Store(&MFP_TADR,sizeof(MFP_TADR));
160: MemorySnapShot_Store(&MFP_TBDR,sizeof(MFP_TBDR));
161: MemorySnapShot_Store(&MFP_TCDR,sizeof(MFP_TCDR));
162: MemorySnapShot_Store(&MFP_TDDR,sizeof(MFP_TDDR));
163: MemorySnapShot_Store(&MFP_TA_MAINCOUNTER,sizeof(MFP_TA_MAINCOUNTER));
164: MemorySnapShot_Store(&MFP_TB_MAINCOUNTER,sizeof(MFP_TB_MAINCOUNTER));
165: MemorySnapShot_Store(&MFP_TC_MAINCOUNTER,sizeof(MFP_TC_MAINCOUNTER));
166: MemorySnapShot_Store(&MFP_TD_MAINCOUNTER,sizeof(MFP_TD_MAINCOUNTER));
167: MemorySnapShot_Store(&TimerAClockCycles,sizeof(TimerAClockCycles));
168: MemorySnapShot_Store(&TimerBClockCycles,sizeof(TimerBClockCycles));
169: MemorySnapShot_Store(&TimerCClockCycles,sizeof(TimerCClockCycles));
170: MemorySnapShot_Store(&TimerDClockCycles,sizeof(TimerDClockCycles));
171: }
172:
1.1.1.2 root 173:
174: /*-----------------------------------------------------------------------*/
1.1 root 175: /*
176: Call MFP interrupt - NOTE when the MFP is in Auto interrupt (AEI), the MFP
177: puts the interrupt number on the data bus and then the 68000 reads it, multiplies
178: it by 4 and adds in a base(usually 0x100) to give the vector. Some programs
179: change this offset, eg RoboCod. This offset is stored in the top 4 bits of register
180: 0xfffa17(0x40 is the default=0x100)
181: Many thanks to Steve Bak for that one!
182: */
1.1.1.7 root 183: static void MFP_Exception(int Interrupt)
1.1 root 184: {
185: unsigned int Vec;
186:
187: Vec = (unsigned int)(MFP_VR&0xf0)<<2;
188: Vec += Interrupt<<2;
1.1.1.7 root 189: M68000_Exception(Vec);
1.1 root 190: }
191:
1.1.1.2 root 192:
193: /*-----------------------------------------------------------------------*/
1.1 root 194: /*
195: Test interrupt request to see if can cause exception,return TRUE if pass vector
196: */
1.1.1.8 ! root 197: static BOOL MFP_InterruptRequest(int nMfpException, unsigned char Bit, unsigned char *pPendingReg, unsigned char MaskRegister,
1.1.1.7 root 198: unsigned char PriorityMaskLow, unsigned char PriorityMaskHigh, unsigned char *pInServiceReg)
1.1 root 199: {
1.1.1.2 root 200: /* Are any higher priority interupts in service? */
1.1.1.5 root 201: if ( ((MFP_ISRA&PriorityMaskLow)==0) && ((MFP_ISRB&PriorityMaskHigh)==0) )
202: {
1.1.1.2 root 203: /* Is masked? */
1.1.1.5 root 204: if (MaskRegister&Bit)
205: {
1.1.1.7 root 206: MakeSR();
1.1.1.2 root 207: /* CPU allows interrupt of an MFP level? */
1.1.1.7 root 208: if (6 > FIND_IPL)
1.1.1.5 root 209: {
1.1.1.2 root 210: *pPendingReg &= ~Bit; /* Clear pending bit */
1.1 root 211: MFP_UpdateFlags();
212:
1.1.1.2 root 213: /* Are we in 'auto' interrupt or 'manual'? */
214: if (MFP_VR&0x08) /* Software End-of-Interrupt (SEI) */
215: *pInServiceReg |= Bit; /* Set interrupt in service register */
1.1 root 216: else
1.1.1.2 root 217: *pInServiceReg &= ~Bit; /* Clear interrupt in service register */
1.1 root 218:
1.1.1.2 root 219: /* Call interrupt, adds in base (default 0x100) */
1.1.1.8 ! root 220: MFP_Exception(nMfpException);
1.1 root 221: return(TRUE);
222: }
223: }
224: }
225:
226: return(FALSE);
227: }
228:
1.1.1.2 root 229:
230: /*-----------------------------------------------------------------------*/
1.1 root 231: /*
1.1.1.7 root 232: Check 'pending' registers to see if any MFP interrupts need servicing.
233: Request interrupt if necessary.
1.1 root 234: */
1.1.1.7 root 235: void MFP_CheckPendingInterrupts(void)
1.1 root 236: {
1.1.1.7 root 237: if ((MFP_IPRA & 0x35) == 0 && (MFP_IPRB & 0xf0) == 0)
238: {
239: /* Should never get here, but if do just clear flag (see 'MFP_UpdateFlags') */
240: unset_special(SPCFLAG_MFP);
241: return;
242: }
1.1 root 243:
1.1.1.7 root 244: if (MFP_IPRA & MFP_TIMER_A_BIT) /* Check Timer A (bit 5) */
245: MFP_InterruptRequest(MFP_EXCEPT_TIMERA, MFP_TIMER_A_BIT, &MFP_IPRA, MFP_IMRA, 0xe0, 0x00, &MFP_ISRA);
1.1.1.2 root 246:
1.1.1.7 root 247: if (MFP_IPRA & MFP_RCVBUFFULL_BIT) /* Check Receive buffer full (bit 4) */
248: MFP_InterruptRequest(MFP_EXCEPT_RECBUFFULL, MFP_RCVBUFFULL_BIT, &MFP_IPRA, MFP_IMRA, 0xf0, 0x00, &MFP_ISRA);
249:
250: if (MFP_IPRA & MFP_TRNBUFEMPTY_BIT) /* Check transmit buffer empty (bit 2) */
251: MFP_InterruptRequest(MFP_EXCEPT_TRANSBUFFEMPTY, MFP_TRNBUFEMPTY_BIT, &MFP_IPRA, MFP_IMRA, 0xfb, 0x00, &MFP_ISRA);
252:
253: if (MFP_IPRA & MFP_TIMER_B_BIT) /* Check Timer B (bit 0) */
254: MFP_InterruptRequest(MFP_EXCEPT_TIMERB, MFP_TIMER_B_BIT, &MFP_IPRA, MFP_IMRA, 0xff, 0x00, &MFP_ISRA);
255:
256: if (MFP_IPRB & MFP_FDCHDC_BIT) /* Check FDC (bit 7) */
257: MFP_InterruptRequest(MFP_EXCEPT_GPIP5, MFP_FDCHDC_BIT, &MFP_IPRB, MFP_IMRB, 0xff, 0x80, &MFP_ISRB);
258:
259: if (MFP_IPRB & MFP_ACIA_BIT) /* Check ACIA (Keyboard or MIDI) (bit 6) */
260: MFP_InterruptRequest(MFP_EXCEPT_ACIA, MFP_ACIA_BIT, &MFP_IPRB, MFP_IMRB, 0xff, 0xc0, &MFP_ISRB);
1.1 root 261:
1.1.1.7 root 262: if (MFP_IPRB & MFP_TIMER_C_BIT) /* Check Timer C (bit 5) */
263: MFP_InterruptRequest(MFP_EXCEPT_TIMERC, MFP_TIMER_C_BIT, &MFP_IPRB, MFP_IMRB, 0xff, 0xe0, &MFP_ISRB);
1.1 root 264:
1.1.1.7 root 265: if (MFP_IPRB & MFP_TIMER_D_BIT) /* Check Timer D (bit 4) */
266: MFP_InterruptRequest(MFP_EXCEPT_TIMERD, MFP_TIMER_D_BIT, &MFP_IPRB, MFP_IMRB, 0xff, 0xf0, &MFP_ISRB);
1.1 root 267: }
268:
1.1.1.2 root 269:
270: /*-----------------------------------------------------------------------*/
1.1 root 271: /*
272: This is called whenever the MFP_IPRA or MFP_IPRB registers are modified.
1.1.1.7 root 273: We set the special flag SPCFLAG_MFP accordingly (to say if an MFP interrupt
1.1 root 274: is to be checked) so we only have one compare during the decode
275: instruction loop.
276: */
277: void MFP_UpdateFlags(void)
278: {
1.1.1.7 root 279: if( MFP_IPRA|MFP_IPRB )
280: {
281: set_special(SPCFLAG_MFP);
282: }
1.1 root 283: else
1.1.1.7 root 284: {
285: unset_special(SPCFLAG_MFP);
286: }
1.1 root 287: }
288:
1.1.1.2 root 289:
290: /*-----------------------------------------------------------------------*/
1.1 root 291: /*
292: Interrupt Channel is active, set pending bit so can be serviced
293: */
294: void MFP_InputOnChannel(unsigned char Bit,unsigned char EnableBit,unsigned char *pPendingReg)
295: {
1.1.1.2 root 296: /* Input has occurred on MFP channel, set interrupt pending to request interrupt when able */
1.1 root 297: if (EnableBit&Bit)
1.1.1.2 root 298: *pPendingReg |= Bit; /* Set bit */
1.1 root 299: else
1.1.1.2 root 300: *pPendingReg &= ~Bit; /* Clear bit */
1.1 root 301: MFP_UpdateFlags();
302: }
303:
1.1.1.2 root 304:
305: /*-----------------------------------------------------------------------*/
1.1 root 306: /*
307: Generate Timer A Interrupt when in Event Count mode
308: */
309: void MFP_TimerA_EventCount_Interrupt(void)
310: {
1.1.1.2 root 311: if (MFP_TA_MAINCOUNTER==1) { /* Timer expired? If so, generate interrupt */
312: MFP_TA_MAINCOUNTER = MFP_TADR; /* Reload timer from data register */
1.1 root 313:
1.1.1.2 root 314: /* Acknowledge in MFP circuit, pass bit,enable,pending */
1.1 root 315: MFP_InputOnChannel(MFP_TIMER_A_BIT,MFP_IERA,&MFP_IPRA);
316: }
317: else
1.1.1.2 root 318: MFP_TA_MAINCOUNTER--; /* Subtract timer main counter */
1.1 root 319: }
320:
1.1.1.2 root 321:
322: /*-----------------------------------------------------------------------*/
1.1 root 323: /*
324: Generate Timer B Interrupt when in Event Count mode
325: */
326: void MFP_TimerB_EventCount_Interrupt(void)
327: {
1.1.1.2 root 328: if (MFP_TB_MAINCOUNTER==1) { /* Timer expired? If so, generate interrupt */
329: MFP_TB_MAINCOUNTER = MFP_TBDR; /* Reload timer from data register */
1.1 root 330:
1.1.1.2 root 331: /* Acknowledge in MFP circuit, pass bit,enable,pending */
1.1 root 332: MFP_InputOnChannel(MFP_TIMER_B_BIT,MFP_IERA,&MFP_IPRA);
333: }
334: else
1.1.1.2 root 335: MFP_TB_MAINCOUNTER--; /* Subtract timer main counter */
1.1 root 336: }
337:
1.1.1.2 root 338:
339: /*-----------------------------------------------------------------------*/
1.1 root 340: /*
341: Start Timer A or B - EventCount mode is done in HBL handler to time correctly
342: */
1.1.1.7 root 343: static int MFP_StartTimer_AB(unsigned char TimerControl, unsigned int TimerData, int Handler, BOOL bFirstTimer)
1.1 root 344: {
1.1.1.4 root 345: int TimerClockCycles = 0;
1.1 root 346:
347: /* If we are in event-count mode ignore this(done on HBL) */
348: if (TimerControl!=0x08) {
349: /* Find number of CPU cycles for when timer is due(include preset and counter) */
350: /* As timer occurs very often we multiply by counter to speed up emulator */
351: if (TimerData==0) /* Data=0 is actually Data=256 */
352: TimerData = 256;
353: TimerClockCycles = ROUND_CYCLES_TO4( TimerData*MFPTimerToCPUCycleTable[TimerControl&0x7] );
354:
355: /* And add to our internal interrupt list, if timer cycles is zero then timer is stopped */
356: Int_RemovePendingInterrupt(Handler);
357: if (TimerClockCycles) {
358: /* Start timer from now? If not continue timer so from original offset */
359: if (bFirstTimer)
360: nCyclesOver = 0;
361: Int_AddRelativeInterrupt(TimerClockCycles,Handler);
362: }
363: }
364: else {
365: /* Make sure no outstanding interrupts in list if channel is disabled */
366: Int_RemovePendingInterrupt(Handler);
367: }
368:
369: return(TimerClockCycles);
370: }
371:
1.1.1.2 root 372:
373: /*-----------------------------------------------------------------------*/
1.1 root 374: /*
375: Start Timer C or D
376: */
1.1.1.7 root 377: static int MFP_StartTimer_CD(unsigned char TimerControl, unsigned int TimerData, int Handler, BOOL bFirstTimer)
1.1 root 378: {
1.1.1.4 root 379: int TimerClockCycles = 0;
1.1 root 380:
381: /* Is timer on? */
382: if ((TimerControl&0x7)!=0) {
383: /* Find number of cycles for when timer is due(include preset and counter) */
384: /* As timer occurs very often we multiply by counter to speed up emulator */
385: if (TimerData==0) /* Data=0 is actually Data=256 */
386: TimerData = 256;
387: TimerClockCycles = ROUND_CYCLES_TO4( TimerData*MFPTimerToCPUCycleTable[TimerControl&0x7] );
388:
389: /* And add to our internal interrupt list, if timer cycles is zero then timer is stopped */
390: Int_RemovePendingInterrupt(Handler);
391: if (TimerClockCycles) {
392: /* Start timer from now? If not continue timer so from original offset */
393: if (bFirstTimer)
394: nCyclesOver = 0;
395: Int_AddRelativeInterrupt(TimerClockCycles,Handler);
396: }
397: }
398: else {
399: /* Make sure no outstanding interrupts in list if channel is disabled */
400: Int_RemovePendingInterrupt(Handler);
401: }
402:
403: return(TimerClockCycles);
404: }
405:
1.1.1.2 root 406:
407: /*-----------------------------------------------------------------------*/
1.1 root 408: /*
409: Read Timer A or B - If in EventCount MainCounter already has correct value
410: */
1.1.1.7 root 411: static unsigned char MFP_ReadTimer_AB(unsigned char TimerControl, unsigned char MainCounter, int TimerCycles, int Handler)
1.1 root 412: {
413: int TimerCyclesPassed;
414:
415: /* Find TimerAB count, if no interrupt assume in Event Count mode so already up-to-date as kept by HBL */
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: }
1.1.1.6 root 421:
1.1 root 422: return(MainCounter);
423: }
424:
1.1.1.2 root 425:
426: /*-----------------------------------------------------------------------*/
1.1 root 427: /*
428: Read Timer C or D
429: */
1.1.1.7 root 430: static unsigned char MFP_ReadTimerCD(unsigned char TimerControl,unsigned char TimerData, unsigned char MainCounter, int TimerCycles, int Handler)
1.1 root 431: {
432: int TimerCyclesPassed;
433:
1.1.1.2 root 434: /* Find TimerCD count. If not one then timer should be off and can find count from main counter */
1.1 root 435: if (Int_InterruptActive(Handler)) {
1.1.1.2 root 436: /* Find cycles passed since last interrupt */
1.1 root 437: TimerCyclesPassed = TimerCycles-Int_FindCyclesPassed(Handler);
438: MainCounter = TimerCyclesPassed/(MFPTimerToCPUCycleTable[TimerControl&0x7]);
439: }
440: else {
441: MainCounter = TimerData;
442: }
443:
444: return(MainCounter);
445: }
446:
1.1.1.2 root 447:
448: /*-----------------------------------------------------------------------*/
1.1 root 449: /*
450: Start Timer A
451: (This does not start the EventCount mode time as this is taken care of by the HBL)
452: */
453: void MFP_StartTimerA(void)
454: {
455: TimerAClockCycles = MFP_StartTimer_AB(MFP_TACR,MFP_TADR,INTERRUPT_MFP_TIMERA,TRUE);
456: }
457:
458:
1.1.1.2 root 459: /*-----------------------------------------------------------------------*/
1.1 root 460: /*
461: Read Timer A
462: */
463: void MFP_ReadTimerA(void)
464: {
465: MFP_TA_MAINCOUNTER = MFP_ReadTimer_AB(MFP_TACR,MFP_TA_MAINCOUNTER,TimerAClockCycles,INTERRUPT_MFP_TIMERA);
466: }
467:
468:
1.1.1.2 root 469: /*-----------------------------------------------------------------------*/
1.1 root 470: /*
471: Start Timer B
472: (This does not start the EventCount mode time as this is taken care of by the HBL)
473: */
474: void MFP_StartTimerB(void)
475: {
476: TimerBClockCycles = MFP_StartTimer_AB(MFP_TBCR,MFP_TBDR,INTERRUPT_MFP_TIMERB,TRUE);
477: }
478:
479:
1.1.1.2 root 480: /*-----------------------------------------------------------------------*/
1.1 root 481: /*
482: Read Timer B
483: */
484: void MFP_ReadTimerB(void)
485: {
486: MFP_TB_MAINCOUNTER = MFP_ReadTimer_AB(MFP_TBCR,MFP_TB_MAINCOUNTER,TimerBClockCycles,INTERRUPT_MFP_TIMERB);
487: }
488:
489:
1.1.1.2 root 490: /*-----------------------------------------------------------------------*/
1.1 root 491: /*
492: Start Timer C
493: */
494: void MFP_StartTimerC(void)
495: {
496: TimerCClockCycles = MFP_StartTimer_CD(MFP_TCDCR>>4,MFP_TCDR,INTERRUPT_MFP_TIMERC,TRUE);
497: }
498:
499:
1.1.1.2 root 500: /*-----------------------------------------------------------------------*/
1.1 root 501: /*
502: Read Timer C
503: */
504: void MFP_ReadTimerC(void)
505: {
506: MFP_TC_MAINCOUNTER = MFP_ReadTimerCD(MFP_TCDCR>>4,MFP_TCDR,MFP_TC_MAINCOUNTER,TimerCClockCycles,INTERRUPT_MFP_TIMERC);
507: }
508:
509:
1.1.1.2 root 510: /*-----------------------------------------------------------------------*/
1.1 root 511: /*
512: Start Timer D
513: */
514: void MFP_StartTimerD(void)
515: {
516: TimerDClockCycles = MFP_StartTimer_CD(MFP_TCDCR,MFP_TDDR,INTERRUPT_MFP_TIMERD,TRUE);
517: }
518:
519:
1.1.1.2 root 520: /*-----------------------------------------------------------------------*/
1.1 root 521: /*
522: Read Timer D
523: */
524: void MFP_ReadTimerD(void)
525: {
526: MFP_TD_MAINCOUNTER = MFP_ReadTimerCD(MFP_TCDCR,MFP_TDDR,MFP_TC_MAINCOUNTER,TimerDClockCycles,INTERRUPT_MFP_TIMERD);
527: }
528:
529:
1.1.1.2 root 530: /*-----------------------------------------------------------------------*/
1.1 root 531: /*
532: Handle Timer A Interrupt
533: */
534: void MFP_InterruptHandler_TimerA(void)
535: {
1.1.1.2 root 536: /* Remove this interrupt from list and re-order */
1.1 root 537: Int_AcknowledgeInterrupt();
538:
1.1.1.2 root 539: /* Acknowledge in MFP circuit, pass bit,enable,pending */
540: if ((MFP_TACR&0xf)!=0) /* Is timer OK? */
1.1 root 541: MFP_InputOnChannel(MFP_TIMER_A_BIT,MFP_IERA,&MFP_IPRA);
542:
1.1.1.2 root 543: /* Start next interrupt, if need one - from current cycle count */
1.1 root 544: TimerAClockCycles = MFP_StartTimer_AB(MFP_TACR,MFP_TADR,INTERRUPT_MFP_TIMERA,FALSE);
545: }
546:
547:
1.1.1.2 root 548: /*-----------------------------------------------------------------------*/
1.1 root 549: /*
550: Handle Timer B Interrupt
551: */
552: void MFP_InterruptHandler_TimerB(void)
553: {
1.1.1.2 root 554: /* Remove this interrupt from list and re-order */
1.1 root 555: Int_AcknowledgeInterrupt();
556:
1.1.1.2 root 557: /* Acknowledge in MFP circuit, pass bit, enable, pending */
558: if ((MFP_TBCR&0xf)!=0) /* Is timer OK? */
1.1 root 559: MFP_InputOnChannel(MFP_TIMER_B_BIT,MFP_IERA,&MFP_IPRA);
560:
1.1.1.2 root 561: /* Start next interrupt, if need one - from current cycle count */
1.1 root 562: TimerBClockCycles = MFP_StartTimer_AB(MFP_TBCR,MFP_TBDR,INTERRUPT_MFP_TIMERB,FALSE);
563: }
564:
565:
1.1.1.2 root 566: /*-----------------------------------------------------------------------*/
1.1 root 567: /*
568: Handle Timer C Interrupt
569: */
570: void MFP_InterruptHandler_TimerC(void)
571: {
1.1.1.2 root 572: /* Remove this interrupt from list and re-order */
1.1 root 573: Int_AcknowledgeInterrupt();
574:
1.1.1.2 root 575: /* Acknowledge in MFP circuit, pass bit, enable, pending */
576: if ((MFP_TCDCR&0x70)!=0) /* Is timer OK? */
1.1 root 577: MFP_InputOnChannel(MFP_TIMER_C_BIT,MFP_IERB,&MFP_IPRB);
578:
1.1.1.2 root 579: /* Start next interrupt, if need one - from current cycle count */
1.1 root 580: TimerCClockCycles = MFP_StartTimer_CD(MFP_TCDCR>>4,MFP_TCDR,INTERRUPT_MFP_TIMERC,FALSE);
581: }
582:
583:
1.1.1.2 root 584: /*-----------------------------------------------------------------------*/
1.1 root 585: /*
586: Handle Timer D Interrupt
587: */
588: void MFP_InterruptHandler_TimerD(void)
589: {
1.1.1.2 root 590: /* Remove this interrupt from list and re-order */
1.1 root 591: Int_AcknowledgeInterrupt();
592:
1.1.1.2 root 593: /* Acknowledge in MFP circuit, pass bit, enable, pending */
594: if ((MFP_TCDCR&0x07)!=0) /* Is timer OK? */
1.1 root 595: MFP_InputOnChannel(MFP_TIMER_D_BIT,MFP_IERB,&MFP_IPRB);
596:
1.1.1.2 root 597: /* Start next interrupt, if need one - from current cycle count */
1.1 root 598: TimerDClockCycles = MFP_StartTimer_CD(MFP_TCDCR,MFP_TDDR,INTERRUPT_MFP_TIMERD,FALSE);
599: }
600:
1.1.1.8 ! root 601:
! 602:
! 603: /*-----------------------------------------------------------------------*/
! 604: /*
! 605: Handle read from monochrome monitor/GPIP pins register (0xfffa01).
! 606: */
! 607: void MFP_GPIP_ReadByte(void)
! 608: {
! 609: Uint8 v;
! 610: v = MFP_GPIP & 0x7f; /* Lower 7-bits are GPIP (Top bit is monitor type) */
! 611: if (!bUseHighRes)
! 612: v |= 0x80; /* Color monitor -> set top bit */
! 613:
! 614: IoMem[0xfffa01] = v;
! 615: }
! 616:
! 617: /*-----------------------------------------------------------------------*/
! 618: /*
! 619: Handle read from active edge register (0xfffa03).
! 620: */
! 621: void MFP_ActiveEdge_ReadByte(void)
! 622: {
! 623: IoMem[0xfffa03] = MFP_AER;
! 624: }
! 625:
! 626: /*-----------------------------------------------------------------------*/
! 627: /*
! 628: Handle read from data direction register (0xfffa05).
! 629: */
! 630: void MFP_DataDirection_ReadByte(void)
! 631: {
! 632: IoMem[0xfffa05] = MFP_DDR;
! 633: }
! 634:
! 635: /*-----------------------------------------------------------------------*/
! 636: /*
! 637: Handle read from interupt enable register A (0xfffa07).
! 638: */
! 639: void MFP_EnableA_ReadByte(void)
! 640: {
! 641: IoMem[0xfffa07] = MFP_IERA;
! 642: }
! 643:
! 644: /*-----------------------------------------------------------------------*/
! 645: /*
! 646: Handle read from interupt enable register B (0xfffa09).
! 647: */
! 648: void MFP_EnableB_ReadByte(void)
! 649: {
! 650: IoMem[0xfffa09] = MFP_IERB;
! 651: }
! 652:
! 653: /*-----------------------------------------------------------------------*/
! 654: /*
! 655: Handle read from interupt pending register A (0xfffa0b).
! 656: */
! 657: void MFP_PendingA_ReadByte(void)
! 658: {
! 659: IoMem[0xfffa0b] = MFP_IPRA;
! 660: }
! 661:
! 662: /*-----------------------------------------------------------------------*/
! 663: /*
! 664: Handle read from interupt pending register A (0xfffa0d).
! 665: */
! 666: void MFP_PendingB_ReadByte(void)
! 667: {
! 668: IoMem[0xfffa0d] = MFP_IPRB;
! 669: }
! 670:
! 671: /*-----------------------------------------------------------------------*/
! 672: /*
! 673: Handle read from interupt in service register A (0xfffa0f).
! 674: */
! 675: void MFP_InServiceA_ReadByte(void)
! 676: {
! 677: IoMem[0xfffa0f] = MFP_ISRA;
! 678: }
! 679:
! 680: /*-----------------------------------------------------------------------*/
! 681: /*
! 682: Handle read from interupt in service register B (0xfffa11).
! 683: */
! 684: void MFP_InServiceB_ReadByte(void)
! 685: {
! 686: IoMem[0xfffa11] = MFP_ISRB;
! 687: }
! 688:
! 689: /*-----------------------------------------------------------------------*/
! 690: /*
! 691: Handle read from interupt mask register A (0xfffa13).
! 692: */
! 693: void MFP_MaskA_ReadByte(void)
! 694: {
! 695: IoMem[0xfffa13] = MFP_IMRA;
! 696: }
! 697:
! 698: /*-----------------------------------------------------------------------*/
! 699: /*
! 700: Handle read from interupt mask register B (0xfffa15).
! 701: */
! 702: void MFP_MaskB_ReadByte(void)
! 703: {
! 704: IoMem[0xfffa15] = MFP_IMRB;
! 705: }
! 706:
! 707: /*-----------------------------------------------------------------------*/
! 708: /*
! 709: Handle read from MFP vector register (0xfffa17).
! 710: */
! 711: void MFP_VectorReg_ReadByte(void)
! 712: {
! 713: IoMem[0xfffa17] = MFP_VR;
! 714: }
! 715:
! 716: /*-----------------------------------------------------------------------*/
! 717: /*
! 718: Handle read from timer A control register (0xfffa19).
! 719: */
! 720: void MFP_TimerACtrl_ReadByte(void)
! 721: {
! 722: IoMem[0xfffa19] = MFP_TACR;
! 723: }
! 724:
! 725: /*-----------------------------------------------------------------------*/
! 726: /*
! 727: Handle read from timer B control register (0xfffa1b).
! 728: */
! 729: void MFP_TimerBCtrl_ReadByte(void)
! 730: {
! 731: IoMem[0xfffa1b] = MFP_TBCR;
! 732: }
! 733:
! 734: /*-----------------------------------------------------------------------*/
! 735: /*
! 736: Handle read from timer C/D control register (0xfffa1d).
! 737: */
! 738: void MFP_TimerCDCtrl_ReadByte(void)
! 739: {
! 740: IoMem[0xfffa1d] = MFP_TCDCR;
! 741: }
! 742:
! 743: /*-----------------------------------------------------------------------*/
! 744: /*
! 745: Handle read from timer A data register (0xfffa1f).
! 746: */
! 747: void MFP_TimerAData_ReadByte(void)
! 748: {
! 749: if (MFP_TACR != 8) /* Is event count? Need to re-calculate counter */
! 750: MFP_ReadTimerA(); /* Stores result in 'MFP_TA_MAINCOUNTER' */
! 751:
! 752: IoMem[0xfffa1f] = MFP_TA_MAINCOUNTER;
! 753: }
! 754:
! 755: /*-----------------------------------------------------------------------*/
! 756: /*
! 757: Handle read from timer B data register (0xfffa21).
! 758: */
! 759: void MFP_TimerBData_ReadByte(void)
! 760: {
! 761: if (MFP_TBCR != 8) /* Is event count? Need to re-calculate counter */
! 762: MFP_ReadTimerB(); /* Stores result in 'MFP_TB_MAINCOUNTER' */
! 763:
! 764: IoMem[0xfffa21] = MFP_TB_MAINCOUNTER;
! 765: }
! 766:
! 767: /*-----------------------------------------------------------------------*/
! 768: /*
! 769: Handle read from timer C data register (0xfffa23).
! 770: */
! 771: void MFP_TimerCData_ReadByte(void)
! 772: {
! 773: MFP_ReadTimerC(); /* Stores result in 'MFP_TC_MAINCOUNTER' */
! 774:
! 775: IoMem[0xfffa23] = MFP_TC_MAINCOUNTER;
! 776: }
! 777:
! 778: /*-----------------------------------------------------------------------*/
! 779: /*
! 780: Handle read from timer D data register (0xfffa25).
! 781: */
! 782: void MFP_TimerDData_ReadByte(void)
! 783: {
! 784: Uint32 pc = m68k_getpc();
! 785:
! 786: if (ConfigureParams.System.bPatchTimerD && pc >= TosAddress && pc <= TosAddress + TosSize)
! 787: {
! 788: /* Trick the tos to believe it was changed: */
! 789: IoMem[0xfffa25] = nTimerDFakeValue;
! 790: }
! 791: else
! 792: {
! 793: MFP_ReadTimerD(); /* Stores result in 'MFP_TD_MAINCOUNTER' */
! 794: IoMem[0xfffa25] = MFP_TD_MAINCOUNTER;
! 795: }
! 796: }
! 797:
! 798:
! 799: /*-----------------------------------------------------------------------*/
! 800: /*
! 801: Handle write to GPIP register (0xfffa01).
! 802: */
! 803: void MFP_GPIP_WriteByte(void)
! 804: {
! 805: /* Nothing... */
! 806: /*fprintf(stderr, "Write to GPIP: %x\n", (int)IoMem[0xfffa01]);*/
! 807: /*MFP_GPIP = IoMem[0xfffa01];*/ /* TODO: What are the GPIP pins good for? */
! 808: }
! 809:
! 810: /*-----------------------------------------------------------------------*/
! 811: /*
! 812: Handle write to AER (0xfffa03).
! 813: */
! 814: void MFP_ActiveEdge_WriteByte(void)
! 815: {
! 816: MFP_AER = IoMem[0xfffa03];
! 817: }
! 818:
! 819: /*-----------------------------------------------------------------------*/
! 820: /*
! 821: Handle write to data direction register (0xfffa05).
! 822: */
! 823: void MFP_DataDirection_WriteByte(void)
! 824: {
! 825: MFP_DDR = IoMem[0xfffa05];
! 826: }
! 827:
! 828: /*-----------------------------------------------------------------------*/
! 829: /*
! 830: Handle write to interrupt enable register A (0xfffa07).
! 831: */
! 832: void MFP_EnableA_WriteByte(void)
! 833: {
! 834: MFP_IERA = IoMem[0xfffa07];
! 835: MFP_IPRA &= MFP_IERA;
! 836: MFP_UpdateFlags();
! 837: /* We may have enabled Timer A or B, check */
! 838: MFP_StartTimerA();
! 839: MFP_StartTimerB();
! 840: }
! 841:
! 842: /*-----------------------------------------------------------------------*/
! 843: /*
! 844: Handle write to interrupt enable register B (0xfffa09).
! 845: */
! 846: void MFP_EnableB_WriteByte(void)
! 847: {
! 848: MFP_IERB = IoMem[0xfffa09];
! 849: MFP_IPRB &= MFP_IERB;
! 850: MFP_UpdateFlags();
! 851: /* We may have enabled Timer C or D, check */
! 852: MFP_StartTimerC();
! 853: MFP_StartTimerD();
! 854: }
! 855:
! 856: /*-----------------------------------------------------------------------*/
! 857: /*
! 858: Handle write to interrupt pending register A (0xfffa0b).
! 859: */
! 860: void MFP_PendingA_WriteByte(void)
! 861: {
! 862: MFP_IPRA &= IoMem[0xfffa0b]; /* Cannot set pending bits - only clear via software */
! 863: MFP_UpdateFlags(); /* Check if any interrupts pending */
! 864: }
! 865:
! 866: /*-----------------------------------------------------------------------*/
! 867: /*
! 868: Handle write to interrupt pending register B (0xfffa0d).
! 869: */
! 870: void MFP_PendingB_WriteByte(void)
! 871: {
! 872: MFP_IPRB &= IoMem[0xfffa0d];
! 873: MFP_UpdateFlags(); /* Check if any interrupts pending */
! 874: }
! 875:
! 876: /*-----------------------------------------------------------------------*/
! 877: /*
! 878: Handle write to interrupt in service register A (0xfffa0f).
! 879: */
! 880: void MFP_InServiceA_WriteByte(void)
! 881: {
! 882: MFP_ISRA &= IoMem[0xfffa0f]; /* Cannot set in-service bits - only clear via software */
! 883: }
! 884:
! 885: /*-----------------------------------------------------------------------*/
! 886: /*
! 887: Handle write to interrupt in service register B (0xfffa11).
! 888: */
! 889: void MFP_InServiceB_WriteByte(void)
! 890: {
! 891: MFP_ISRB &= IoMem[0xfffa11]; /* Cannot set in-service bits - only clear via software */
! 892: }
! 893:
! 894: /*-----------------------------------------------------------------------*/
! 895: /*
! 896: Handle write to interrupt mask register A (0xfffa13).
! 897: */
! 898: void MFP_MaskA_WriteByte(void)
! 899: {
! 900: MFP_IMRA = IoMem[0xfffa13];
! 901: }
! 902:
! 903: /*-----------------------------------------------------------------------*/
! 904: /*
! 905: Handle write to interrupt mask register B (0xfffa15).
! 906: */
! 907: void MFP_MaskB_WriteByte(void)
! 908: {
! 909: MFP_IMRB = IoMem[0xfffa15];
! 910: }
! 911:
! 912: /*-----------------------------------------------------------------------*/
! 913: /*
! 914: Handle write to MFP vector register (0xfffa17).
! 915: */
! 916: void MFP_VectorReg_WriteByte(void)
! 917: {
! 918: Uint8 old_vr;
! 919: old_vr = MFP_VR; /* Copy for checking if set mode */
! 920: MFP_VR = IoMem[0xfffa17];
! 921: if ((MFP_VR^old_vr) & 0x08) /* Test change in end-of-interrupt mode */
! 922: {
! 923: if (MFP_VR & 0x08) /* Mode did change but was it to automatic mode? (ie bit is a zero) */
! 924: { /* We are now in automatic mode, so clear all in-service bits! */
! 925: MFP_ISRA = 0;
! 926: MFP_ISRB = 0;
! 927: }
! 928: }
! 929: }
! 930:
! 931: /*-----------------------------------------------------------------------*/
! 932: /*
! 933: Handle write to timer A control register (0xfffa19).
! 934: */
! 935: void MFP_TimerACtrl_WriteByte(void)
! 936: {
! 937: Uint8 old_tacr;
! 938: old_tacr = MFP_TACR; /* Remember old control state */
! 939: MFP_TACR = IoMem[0xfffa19] & 0x0f; /* Mask, Fish (auto160) writes into top nibble! */
! 940: if ((MFP_TACR^old_tacr) & 0x0f) /* Check if Timer A control changed */
! 941: MFP_StartTimerA(); /* Reset timers if need to */
! 942: }
! 943:
! 944: /*-----------------------------------------------------------------------*/
! 945: /*
! 946: Handle write to timer B control register (0xfffa1b).
! 947: */
! 948: void MFP_TimerBCtrl_WriteByte(void)
! 949: {
! 950: Uint8 old_tbcr;
! 951: old_tbcr = MFP_TBCR; /* Remember old control state */
! 952: MFP_TBCR = IoMem[0xfffa1b] & 0x0f; /* Mask, Fish (auto160) writes into top nibble! */
! 953: if ((MFP_TBCR^old_tbcr) & 0x0f) /* Check if Timer B control changed */
! 954: MFP_StartTimerB(); /* Reset timers if need to */
! 955: }
! 956:
! 957: /*-----------------------------------------------------------------------*/
! 958: /*
! 959: Handle write to timer C/D control register (0xfffa1d).
! 960: */
! 961: void MFP_TimerCDCtrl_WriteByte(void)
! 962: {
! 963: Uint8 old_tcdcr;
! 964:
! 965: old_tcdcr = MFP_TCDCR; /* Remember old control state */
! 966: MFP_TCDCR = IoMem[0xfffa1d]; /* Store new one */
! 967:
! 968: if ((MFP_TCDCR^old_tcdcr) & 0x70) /* Check if Timer C control changed */
! 969: MFP_StartTimerC(); /* Reset timers if need to */
! 970:
! 971: if ((MFP_TCDCR^old_tcdcr) & 0x07) /* Check if Timer D control changed */
! 972: {
! 973: Uint32 pc = m68k_getpc();
! 974:
! 975: /* Need to change baud rate of RS232 emulation? */
! 976: if (ConfigureParams.RS232.bEnableRS232)
! 977: {
! 978: RS232_SetBaudRateFromTimerD();
! 979: }
! 980:
! 981: if (ConfigureParams.System.bPatchTimerD && !bAppliedTimerDPatch
! 982: && pc >= TosAddress && pc <= TosAddress + TosSize)
! 983: {
! 984: /* Slow down Timer-D if set from TOS for the first time to gain more
! 985: * desktop performance.
! 986: * Obviously, we need to emulate all timers correctly but TOS sets up
! 987: * Timer-D at a very high rate (every couple of instructions). The
! 988: * interrupt isn't enabled but the emulator still needs to process the
! 989: * interrupt table and this HALVES our frame rate!!!
! 990: * Some games actually reference this timer but don't set it up
! 991: * (eg Paradroid, Speedball I) so we simply intercept the Timer-D setup
! 992: * code in TOS and fix the numbers with more 'laid-back' values.
! 993: * This still keeps 100% compatibility */
! 994: MFP_TCDCR = IoMem[0xfffa1d] = (IoMem[0xfffa1d] & 0xf0) | 7;
! 995: bAppliedTimerDPatch = TRUE;
! 996: }
! 997: MFP_StartTimerD(); /* Reset timers if need to */
! 998: }
! 999: }
! 1000:
! 1001: /*-----------------------------------------------------------------------*/
! 1002: /*
! 1003: Handle write to timer A data register (0xfffa1f).
! 1004: */
! 1005: void MFP_TimerAData_WriteByte(void)
! 1006: {
! 1007: MFP_TADR = IoMem[0xfffa1f]; /* Store into data register */
! 1008: if (MFP_TACR == 0) /* Now check if timer is running - if so do not set */
! 1009: {
! 1010: MFP_TA_MAINCOUNTER = MFP_TADR; /* Timer is off, store to main counter */
! 1011: MFP_StartTimerA(); /* Add our interrupt */
! 1012: }
! 1013: }
! 1014:
! 1015: /*-----------------------------------------------------------------------*/
! 1016: /*
! 1017: Handle write to timer B data register (0xfffa21).
! 1018: */
! 1019: void MFP_TimerBData_WriteByte(void)
! 1020: {
! 1021: MFP_TBDR = IoMem[0xfffa21]; /* Store into data register */
! 1022: if (MFP_TBCR == 0) /* Now check if timer is running - if so do not set */
! 1023: {
! 1024: MFP_TB_MAINCOUNTER = MFP_TBDR; /* Timer is off, store to main counter */
! 1025: MFP_StartTimerB(); /* Add our interrupt */
! 1026: }
! 1027: }
! 1028:
! 1029: /*-----------------------------------------------------------------------*/
! 1030: /*
! 1031: Handle write to timer C data register (0xfffa23).
! 1032: */
! 1033: void MFP_TimerCData_WriteByte(void)
! 1034: {
! 1035: MFP_TCDR = IoMem[0xfffa23]; /* Store into data register */
! 1036: if ((MFP_TCDCR&0x70) == 0) /* Now check if timer is running - if so do not set */
! 1037: {
! 1038: MFP_StartTimerC(); /* Add our interrupt */
! 1039: }
! 1040: }
! 1041:
! 1042: /*-----------------------------------------------------------------------*/
! 1043: /*
! 1044: Handle write to timer D data register (0xfffa25).
! 1045: */
! 1046: void MFP_TimerDData_WriteByte(void)
! 1047: {
! 1048: Uint32 pc = m68k_getpc();
! 1049:
! 1050: /* Need to change baud rate of RS232 emulation? */
! 1051: if (ConfigureParams.RS232.bEnableRS232 && (IoMem[0xfffa1d] & 0x07))
! 1052: {
! 1053: RS232_SetBaudRateFromTimerD();
! 1054: }
! 1055:
! 1056: /* Patch Timer-D for better performance? */
! 1057: if (ConfigureParams.System.bPatchTimerD && pc >= TosAddress && pc <= TosAddress + TosSize)
! 1058: {
! 1059: nTimerDFakeValue = IoMem[0xfffa25];
! 1060: IoMem[0xfffa25] = 0x64; /* Slow down the useless Timer-D setup from the bios */
! 1061: }
! 1062:
! 1063: MFP_TDDR = IoMem[0xfffa25]; /* Store into data register */
! 1064: if ((MFP_TCDCR&0x07) == 0) /* Now check if timer is running - if so do not set */
! 1065: {
! 1066: MFP_StartTimerD(); /* Add our interrupt */
! 1067: }
! 1068: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.