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