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