|
|
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.11! root 17:
! 18: /* 2007/04/18 [NP] - Better values for MFPTimerToCPUCycleTable. */
! 19: /* - Don't restart the timers in MFP_EnableA_WriteByte and */
! 20: /* MFP_EnableB_WriteByte, this gives wrong results. */
! 21: /* 2007/05/05 [NP] - When a timer is looping (counter reaches 0), we must use */
! 22: /* PendingCyclesOver to restart it with Int_AddRelativeInterrupt. */
! 23: /* PendingCyclesOver is the value of PendingInterruptCount when */
! 24: /* the timer expired. */
! 25: /* - MFP_ReadTimer_AB/CD was wrong (returned the elapsed counter */
! 26: /* changes since start, instead of the remainging counter value). */
! 27: /* (ULM DSOTS Demos and Overscan Demos). */
! 28: /* 2007/09/25 [NP] Replace printf by calls to HATARI_TRACE. */
! 29: /* 2007/10/21 [NP] Use 'Int_AddRelativeInterruptWithOffset' when an MFP timer is */
! 30: /* looping. Gives better accuracy when using '4' as a divisor. */
! 31: /* (fix ULM DSOTS Demos and Overscan Demos). */
! 32: /* 2007/10/24 [NP] Handle the possibility to resume a timer after stopping it. */
! 33: /* After writing 0 to ctrl, writing a >0 in ctrl should continue */
! 34: /* the timer with the value that was stored in data reg when timer */
! 35: /* was stopped. The value is saved in MFP_Tx_MAINCOUNTER whenever */
! 36: /* 0 is written in ctrl reg (Froggies Over The Fence by STCNX). */
! 37: /* 2007/10/28 [NP] Function 'Int_ResumeStoppedInterrupt' to better handle the */
! 38: /* possibility to resume a timer that was stopped with ctrl=0 */
! 39: /* (ST CNX screen in Punish Your Machine). */
! 40: /* 2007/12/27 [NP] When adding a new MFP interrupt (ctrl != 0 ), we must take */
! 41: /* into account the number of cycles of the current instruction, as*/
! 42: /* well as the accumulated wait state cycles, else the int counter */
! 43: /* will be started between 8 - 20 cycles earlier, which can break */
! 44: /* some too strict code : the int counter must start after the */
! 45: /* current instruction is processed, not before. The write is */
! 46: /* considered effective 4 cycles before the end of the current */
! 47: /* instruction. */
! 48: /* (fix ULM Dark Side Of The Spoon and Decade Demo's Wow Scroll 2).*/
! 49: /* 2008/02/06 [NP] Handle "fast" timers as those started by the TOS for the RS232 */
! 50: /* baud rate generator. In that case, the timers could be too fast */
! 51: /* to be handled by the CPU, which means PendingCyclesOver can be */
! 52: /* >= INT_CONVERT_TO_INTERNAL ( TimerClockCycles , INT_MFP_CYCLE ) */
! 53: /* and this will give wrong results when the timer restarts if */
! 54: /* we call Int_AddRelativeInterruptWithOffset. We use a modulo to */
! 55: /* limit PendingCyclesOver to not more than the number of cycles */
! 56: /* of one int (which means we "skip" the ints that could not be */
! 57: /* processed). */
! 58: /* 2008/03/08 [NP] Add traces when writing to vector register fffa17. */
! 59: /* Use M68000_INT_MFP when calling M68000_Exception(). */
! 60:
! 61: const char MFP_rcsid[] = "Hatari $Id: mfp.c,v 1.35 2008/03/09 12:53:26 npomarede Exp $";
1.1 root 62:
63: #include "main.h"
1.1.1.8 root 64: #include "configuration.h"
1.1.1.9 root 65: #include "dmaSnd.h"
1.1 root 66: #include "fdc.h"
67: #include "ikbd.h"
68: #include "int.h"
1.1.1.8 root 69: #include "ioMem.h"
1.1.1.9 root 70: #include "joy.h"
1.1 root 71: #include "m68000.h"
72: #include "memorySnapShot.h"
73: #include "mfp.h"
74: #include "psg.h"
1.1.1.8 root 75: #include "rs232.h"
1.1 root 76: #include "sound.h"
1.1.1.8 root 77: #include "tos.h"
1.1 root 78: #include "video.h"
1.1.1.11! root 79: #include "trace.h"
1.1.1.3 root 80:
1.1 root 81:
82: /*
83: MFP interrupt channel circuit:-
84:
85: EdgeRegister EnableRegister MaskRegister SBit
86: | | | |
87: | | | | ------------------------
88: | | ------------------------ ---\ |---\ | |
89: | o--\ | | AND---o----------------AND---| S InterruptInService |
90: ---\ | AND---| S InterruptPending O |-------/ | |---/ | |
91: XOR----------)--/ | R | | | ------------------------
92: Input -----/ | ------------------------ | |
93: | | InterruptRequest |
94: NOT OR |
95: | | | |
96: -------------------- --------------------------------------o--- PassVector
97: */
98:
1.1.1.7 root 99:
100: /*-----------------------------------------------------------------------*/
1.1 root 101:
1.1.1.2 root 102: /* MFP Registers */
1.1.1.9 root 103: Uint8 MFP_GPIP; /* General Purpose Pins */
1.1.1.11! root 104: Uint8 MFP_VR; /* Vector Register 0xfffa17 */
1.1.1.9 root 105: Uint8 MFP_IERA,MFP_IERB; /* Interrupt Enable Registers A,B 0xfffa07,0xfffa09 */
106: Uint8 MFP_IPRA,MFP_IPRB; /* Interrupt Pending Registers A,B 0xfffa0b,0xfffa0d */
1.1.1.11! root 107: Uint8 MFP_TACR,MFP_TBCR; /* Timer A,B Control Registers */
1.1.1.10 root 108:
1.1.1.11! root 109: static Uint8 MFP_TCDCR; /* C+D Control Registers */
1.1.1.10 root 110: static Uint8 MFP_AER,MFP_DDR; /* Active Edge Register, Data Direction Register */
111: static Uint8 MFP_ISRA,MFP_ISRB; /* Interrupt In-Service Registers A,B 0xfffa0f,0xfffa11 */
112: static Uint8 MFP_IMRA,MFP_IMRB; /* Interrupt Mask Registers A,B 0xfffa13,0xfffa15 */
113: static Uint8 MFP_TADR,MFP_TBDR; /* Timer A,B Data Registers */
114: static Uint8 MFP_TCDR,MFP_TDDR; /* Timer C,D Data Registers */
115: static Uint8 MFP_TA_MAINCOUNTER; /* Timer A Main Counter (internal to MFP) */
116: static Uint8 MFP_TB_MAINCOUNTER; /* Timer B Main Counter */
117: static Uint8 MFP_TC_MAINCOUNTER; /* Timer C Main Counter (these are temp's, set when read as) */
118: static Uint8 MFP_TD_MAINCOUNTER; /* Timer D Main Counter (as done via interrupts) */
1.1 root 119:
120: /* CPU clock cycle counts for each timer */
1.1.1.7 root 121: static int TimerAClockCycles=0;
122: static int TimerBClockCycles=0;
123: static int TimerCClockCycles=0;
124: static int TimerDClockCycles=0;
125:
1.1.1.11! root 126: /* If a timer is stopped then restarted later without writing to the data register, */
! 127: /* we must resume the timer from where we left in the interrupts table, instead of */
! 128: /* computing a new number of clock cycles to restart the interrupt. */
! 129: static BOOL TimerACanResume = FALSE;
! 130: static BOOL TimerBCanResume = FALSE;
! 131: static BOOL TimerCCanResume = FALSE;
! 132: static BOOL TimerDCanResume = FALSE;
! 133:
1.1.1.9 root 134: BOOL bAppliedTimerDPatch; /* TRUE if the Timer-D patch has been applied */
135: static int nTimerDFakeValue; /* Faked Timer-D data register for the Timer-D patch */
1.1.1.8 root 136:
1.1.1.11! root 137: static int PendingCyclesOver = 0; /* >= 0 value, used to "loop" a timer when data counter reaches 0 */
1.1 root 138:
1.1.1.11! root 139: static const Uint16 MFPDiv[] =
! 140: {
! 141: 0,
! 142: 4,
! 143: 10,
! 144: 16,
! 145: 50,
! 146: 64,
! 147: 100,
! 148: 200
1.1 root 149: };
150:
1.1.1.11! root 151: /* Convert data/ctrl register to a number of mfp cycles */
! 152: #define MFP_REG_TO_CYCLES(data,ctrl) ( data * MFPDiv[ ctrl&0x7 ] )
! 153: /* Determine the data register corresponding to a number of mfp cycles/ctrl register */
! 154: /* (we round to the closest higher integer) */
! 155: #define MFP_CYCLE_TO_REG(cyc,ctrl) ( ( cyc + MFPDiv[ ctrl&0x7 ] - 1 ) / MFPDiv[ ctrl&0x7 ] )
! 156: //#define MFP_CYCLE_TO_REG(cyc,ctrl) ( cyc / MFPDiv[ ctrl&0x7 ] )
! 157:
1.1 root 158:
1.1.1.2 root 159: /*-----------------------------------------------------------------------*/
1.1.1.11! root 160: /**
! 161: * Reset all MFP variables and start interrupts on their way!
! 162: */
1.1 root 163: void MFP_Reset(void)
164: {
1.1.1.11! root 165: /* Reset MFP internal variables */
1.1.1.7 root 166:
1.1.1.11! root 167: bAppliedTimerDPatch = FALSE;
1.1.1.7 root 168:
1.1.1.11! root 169: MFP_GPIP = 0xff;
! 170: MFP_AER = MFP_DDR = 0;
! 171: MFP_IERA = MFP_IERB = 0;
! 172: MFP_IPRA = MFP_IPRB = 0;
! 173: MFP_ISRA = MFP_ISRB = 0;
! 174: MFP_IMRA = MFP_IMRB = 0;
! 175: MFP_VR = 0;
! 176: MFP_TACR = MFP_TBCR = MFP_TCDCR = 0;
! 177: MFP_TADR = MFP_TBDR = 0;
! 178: MFP_TCDR = MFP_TDDR = 0;
! 179: MFP_TA_MAINCOUNTER = MFP_TB_MAINCOUNTER = 0;
! 180: MFP_TC_MAINCOUNTER = MFP_TD_MAINCOUNTER = 0;
1.1 root 181:
1.1.1.11! root 182: /* Clear counters */
! 183: TimerAClockCycles = TimerBClockCycles = 0;
! 184: TimerCClockCycles = TimerDClockCycles = 0;
1.1 root 185: }
186:
1.1.1.2 root 187:
188: /*-----------------------------------------------------------------------*/
1.1.1.11! root 189: /**
! 190: * Save/Restore snapshot of local variables('MemorySnapShot_Store' handles type)
! 191: */
1.1 root 192: void MFP_MemorySnapShot_Capture(BOOL bSave)
193: {
1.1.1.11! root 194: /* Save/Restore details */
! 195: MemorySnapShot_Store(&MFP_GPIP, sizeof(MFP_GPIP));
! 196: MemorySnapShot_Store(&MFP_AER, sizeof(MFP_AER));
! 197: MemorySnapShot_Store(&MFP_DDR, sizeof(MFP_DDR));
! 198: MemorySnapShot_Store(&MFP_IERA, sizeof(MFP_IERA));
! 199: MemorySnapShot_Store(&MFP_IERB, sizeof(MFP_IERB));
! 200: MemorySnapShot_Store(&MFP_IPRA, sizeof(MFP_IPRA));
! 201: MemorySnapShot_Store(&MFP_IPRB, sizeof(MFP_IPRB));
! 202: MemorySnapShot_Store(&MFP_ISRA, sizeof(MFP_ISRA));
! 203: MemorySnapShot_Store(&MFP_ISRB, sizeof(MFP_ISRB));
! 204: MemorySnapShot_Store(&MFP_IMRA, sizeof(MFP_IMRA));
! 205: MemorySnapShot_Store(&MFP_IMRB, sizeof(MFP_IMRB));
! 206: MemorySnapShot_Store(&MFP_VR, sizeof(MFP_VR));
! 207: MemorySnapShot_Store(&MFP_TACR, sizeof(MFP_TACR));
! 208: MemorySnapShot_Store(&MFP_TBCR, sizeof(MFP_TBCR));
! 209: MemorySnapShot_Store(&MFP_TCDCR, sizeof(MFP_TCDCR));
! 210: MemorySnapShot_Store(&MFP_TADR, sizeof(MFP_TADR));
! 211: MemorySnapShot_Store(&MFP_TBDR, sizeof(MFP_TBDR));
! 212: MemorySnapShot_Store(&MFP_TCDR, sizeof(MFP_TCDR));
! 213: MemorySnapShot_Store(&MFP_TDDR, sizeof(MFP_TDDR));
! 214: MemorySnapShot_Store(&MFP_TA_MAINCOUNTER, sizeof(MFP_TA_MAINCOUNTER));
! 215: MemorySnapShot_Store(&MFP_TB_MAINCOUNTER, sizeof(MFP_TB_MAINCOUNTER));
! 216: MemorySnapShot_Store(&MFP_TC_MAINCOUNTER, sizeof(MFP_TC_MAINCOUNTER));
! 217: MemorySnapShot_Store(&MFP_TD_MAINCOUNTER, sizeof(MFP_TD_MAINCOUNTER));
! 218: MemorySnapShot_Store(&TimerAClockCycles, sizeof(TimerAClockCycles));
! 219: MemorySnapShot_Store(&TimerBClockCycles, sizeof(TimerBClockCycles));
! 220: MemorySnapShot_Store(&TimerCClockCycles, sizeof(TimerCClockCycles));
! 221: MemorySnapShot_Store(&TimerDClockCycles, sizeof(TimerDClockCycles));
! 222: MemorySnapShot_Store(&TimerACanResume, sizeof(TimerACanResume));
! 223: MemorySnapShot_Store(&TimerBCanResume, sizeof(TimerBCanResume));
! 224: MemorySnapShot_Store(&TimerCCanResume, sizeof(TimerCCanResume));
! 225: MemorySnapShot_Store(&TimerDCanResume, sizeof(TimerDCanResume));
1.1 root 226: }
227:
1.1.1.2 root 228:
229: /*-----------------------------------------------------------------------*/
1.1.1.11! root 230: /**
! 231: * Call MFP interrupt - NOTE when the MFP is in Auto interrupt (AEI), the MFP
! 232: * puts the interrupt number on the data bus and then the 68000 reads it, multiplies
! 233: * it by 4 and adds in a base(usually 0x100) to give the vector. Some programs
! 234: * change this offset, eg RoboCod. This offset is stored in the top 4 bits of register
! 235: * 0xfffa17(0x40 is the default=0x100)
! 236: * Many thanks to Steve Bak for that one!
! 237: */
1.1.1.7 root 238: static void MFP_Exception(int Interrupt)
1.1 root 239: {
1.1.1.11! root 240: unsigned int Vec;
1.1 root 241:
1.1.1.11! root 242: Vec = (unsigned int)(MFP_VR&0xf0)<<2;
! 243: Vec += Interrupt<<2;
! 244:
! 245: if ( HATARI_TRACE_LEVEL ( HATARI_TRACE_MFP_EXCEPTION ) )
! 246: {
! 247: int nFrameCycles = Cycles_GetCounter(CYCLES_COUNTER_VIDEO);;
! 248: int nLineCycles = nFrameCycles % nCyclesPerLine;
! 249: HATARI_TRACE_PRINT ( "mfp excep int=%d vec=0x%x new_pc=0x%x video_cyc=%d %d@%d\n" ,
! 250: Interrupt, Vec, get_long ( Vec ), nFrameCycles, nLineCycles, nHBL );
! 251: }
! 252:
! 253: M68000_Exception ( Vec , M68000_INT_MFP );
1.1 root 254: }
255:
1.1.1.2 root 256:
257: /*-----------------------------------------------------------------------*/
1.1.1.11! root 258: /**
! 259: * This is called whenever the MFP_IPRA or MFP_IPRB registers are modified.
! 260: * We set the special flag SPCFLAG_MFP accordingly (to say if an MFP interrupt
! 261: * is to be checked) so we only have one compare during the decode
! 262: * instruction loop.
! 263: */
1.1.1.10 root 264: static void MFP_UpdateFlags(void)
265: {
1.1.1.11! root 266: if (MFP_IPRA|MFP_IPRB)
! 267: {
! 268: M68000_SetSpecial(SPCFLAG_MFP);
! 269: }
! 270: else
! 271: {
! 272: M68000_UnsetSpecial(SPCFLAG_MFP);
! 273: }
1.1.1.10 root 274: }
275:
276:
277: /*-----------------------------------------------------------------------*/
1.1.1.11! root 278: /**
! 279: * Test interrupt request to see if can cause exception,return TRUE if pass vector
! 280: */
1.1.1.9 root 281: static BOOL MFP_InterruptRequest(int nMfpException, Uint8 Bit, Uint8 *pPendingReg, Uint8 MaskRegister,
282: Uint8 PriorityMaskLow, Uint8 PriorityMaskHigh, Uint8 *pInServiceReg)
1.1 root 283: {
1.1.1.11! root 284: /* Are any higher priority interupts in service? */
! 285: if (((MFP_ISRA&PriorityMaskLow) == 0) && ((MFP_ISRB&PriorityMaskHigh) == 0))
! 286: {
! 287: /* Is masked? */
! 288: if (MaskRegister&Bit)
! 289: {
! 290: /* CPU allows interrupt of an MFP level? */
! 291: if (6 > FIND_IPL)
! 292: {
! 293: *pPendingReg &= ~Bit; /* Clear pending bit */
! 294: MFP_UpdateFlags();
! 295:
! 296: /* Are we in 'auto' interrupt or 'manual'? */
! 297: if (MFP_VR&0x08) /* Software End-of-Interrupt (SEI) */
! 298: *pInServiceReg |= Bit; /* Set interrupt in service register */
! 299: else
! 300: *pInServiceReg &= ~Bit; /* Clear interrupt in service register */
! 301:
! 302: /* Call interrupt, adds in base (default 0x100) */
! 303: MFP_Exception(nMfpException);
! 304: return TRUE;
! 305: }
! 306: }
! 307: }
1.1 root 308:
1.1.1.11! root 309: return FALSE;
1.1 root 310: }
311:
1.1.1.2 root 312:
313: /*-----------------------------------------------------------------------*/
1.1.1.11! root 314: /**
! 315: * Check 'pending' registers to see if any MFP interrupts need servicing.
! 316: * Request interrupt if necessary.
! 317: */
1.1.1.7 root 318: void MFP_CheckPendingInterrupts(void)
1.1 root 319: {
1.1.1.11! root 320: if ((MFP_IPRA & 0xb5) == 0 && (MFP_IPRB & 0xf0) == 0)
! 321: {
! 322: /* Should never get here, but if do just clear flag (see 'MFP_UpdateFlags') */
! 323: M68000_UnsetSpecial(SPCFLAG_MFP);
! 324: return;
! 325: }
1.1 root 326:
1.1.1.11! root 327: if (MFP_IPRA & MFP_TIMER_GPIP7_BIT) /* Check MFP GPIP7 interrupt (bit 7) */
! 328: MFP_InterruptRequest(MFP_EXCEPT_GPIP7, MFP_TIMER_GPIP7_BIT, &MFP_IPRA, MFP_IMRA, 0x80, 0x00, &MFP_ISRA);
1.1.1.9 root 329:
1.1.1.11! root 330: if (MFP_IPRA & MFP_TIMER_A_BIT) /* Check Timer A (bit 5) */
! 331: MFP_InterruptRequest(MFP_EXCEPT_TIMERA, MFP_TIMER_A_BIT, &MFP_IPRA, MFP_IMRA, 0xe0, 0x00, &MFP_ISRA);
1.1.1.2 root 332:
1.1.1.11! root 333: if (MFP_IPRA & MFP_RCVBUFFULL_BIT) /* Check Receive buffer full (bit 4) */
! 334: MFP_InterruptRequest(MFP_EXCEPT_RECBUFFULL, MFP_RCVBUFFULL_BIT, &MFP_IPRA, MFP_IMRA, 0xf0, 0x00, &MFP_ISRA);
1.1.1.7 root 335:
1.1.1.11! root 336: if (MFP_IPRA & MFP_TRNBUFEMPTY_BIT) /* Check transmit buffer empty (bit 2) */
! 337: MFP_InterruptRequest(MFP_EXCEPT_TRANSBUFFEMPTY, MFP_TRNBUFEMPTY_BIT, &MFP_IPRA, MFP_IMRA, 0xfb, 0x00, &MFP_ISRA);
1.1.1.7 root 338:
1.1.1.11! root 339: if (MFP_IPRA & MFP_TIMER_B_BIT) /* Check Timer B (bit 0) */
! 340: MFP_InterruptRequest(MFP_EXCEPT_TIMERB, MFP_TIMER_B_BIT, &MFP_IPRA, MFP_IMRA, 0xff, 0x00, &MFP_ISRA);
1.1.1.7 root 341:
1.1.1.11! root 342: if (MFP_IPRB & MFP_FDCHDC_BIT) /* Check FDC (bit 7) */
! 343: MFP_InterruptRequest(MFP_EXCEPT_GPIP5, MFP_FDCHDC_BIT, &MFP_IPRB, MFP_IMRB, 0xff, 0x80, &MFP_ISRB);
1.1.1.7 root 344:
1.1.1.11! root 345: if (MFP_IPRB & MFP_ACIA_BIT) /* Check ACIA (Keyboard or MIDI) (bit 6) */
! 346: MFP_InterruptRequest(MFP_EXCEPT_ACIA, MFP_ACIA_BIT, &MFP_IPRB, MFP_IMRB, 0xff, 0xc0, &MFP_ISRB);
1.1 root 347:
1.1.1.11! root 348: if (MFP_IPRB & MFP_TIMER_C_BIT) /* Check Timer C (bit 5) */
! 349: MFP_InterruptRequest(MFP_EXCEPT_TIMERC, MFP_TIMER_C_BIT, &MFP_IPRB, MFP_IMRB, 0xff, 0xe0, &MFP_ISRB);
1.1 root 350:
1.1.1.11! root 351: if (MFP_IPRB & MFP_TIMER_D_BIT) /* Check Timer D (bit 4) */
! 352: MFP_InterruptRequest(MFP_EXCEPT_TIMERD, MFP_TIMER_D_BIT, &MFP_IPRB, MFP_IMRB, 0xff, 0xf0, &MFP_ISRB);
1.1 root 353: }
354:
1.1.1.2 root 355:
356: /*-----------------------------------------------------------------------*/
1.1.1.11! root 357: /**
! 358: * Interrupt Channel is active, set pending bit so can be serviced
! 359: */
1.1.1.9 root 360: void MFP_InputOnChannel(Uint8 Bit, Uint8 EnableBit, Uint8 *pPendingReg)
1.1 root 361: {
1.1.1.11! root 362: /* Input has occurred on MFP channel, set interrupt pending to request interrupt when able */
! 363: if (EnableBit&Bit)
! 364: *pPendingReg |= Bit; /* Set bit */
! 365: else
! 366: *pPendingReg &= ~Bit; /* Clear bit */
! 367: MFP_UpdateFlags();
1.1 root 368: }
369:
1.1.1.2 root 370:
371: /*-----------------------------------------------------------------------*/
1.1.1.11! root 372: /**
! 373: * Generate Timer A Interrupt when in Event Count mode
! 374: */
1.1 root 375: void MFP_TimerA_EventCount_Interrupt(void)
376: {
1.1.1.11! root 377: if (MFP_TA_MAINCOUNTER == 1) /* Timer expired? If so, generate interrupt */
! 378: {
! 379: MFP_TA_MAINCOUNTER = MFP_TADR; /* Reload timer from data register */
1.1 root 380:
1.1.1.11! root 381: /* Acknowledge in MFP circuit, pass bit,enable,pending */
! 382: MFP_InputOnChannel(MFP_TIMER_A_BIT,MFP_IERA,&MFP_IPRA);
! 383: }
! 384: else
! 385: MFP_TA_MAINCOUNTER--; /* Subtract timer main counter */
1.1 root 386: }
387:
1.1.1.2 root 388:
389: /*-----------------------------------------------------------------------*/
1.1.1.11! root 390: /**
! 391: * Generate Timer B Interrupt when in Event Count mode
! 392: */
1.1 root 393: void MFP_TimerB_EventCount_Interrupt(void)
394: {
1.1.1.11! root 395: if (MFP_TB_MAINCOUNTER == 1) /* Timer expired? If so, generate interrupt */
! 396: {
! 397: MFP_TB_MAINCOUNTER = MFP_TBDR; /* Reload timer from data register */
1.1 root 398:
1.1.1.11! root 399: /* Acknowledge in MFP circuit, pass bit,enable,pending */
! 400: MFP_InputOnChannel(MFP_TIMER_B_BIT,MFP_IERA,&MFP_IPRA);
! 401: }
! 402: else
! 403: MFP_TB_MAINCOUNTER--; /* Subtract timer main counter */
1.1 root 404: }
405:
1.1.1.2 root 406:
407: /*-----------------------------------------------------------------------*/
1.1.1.11! root 408: /**
! 409: * Start Timer A or B - EventCount mode is done in HBL handler to time correctly
! 410: */
! 411: static int MFP_StartTimer_AB(Uint8 TimerControl, Uint16 TimerData, int Handler,
! 412: BOOL bFirstTimer, BOOL *pTimerCanResume)
1.1 root 413: {
1.1.1.11! root 414: int TimerClockCycles = 0;
! 415:
! 416: /* Is timer in delay mode (ctrl = 0-7) ? */
! 417: /* If we are in event-count mode (ctrl = 8) ignore this (done on HBL) */
! 418: if (TimerControl <= 7)
! 419: {
! 420: /* Find number of CPU cycles for when timer is due (include preset
! 421: * and counter). As timer occurs very often we multiply by counter
! 422: * to speed up emulator */
! 423: if (TimerData == 0) /* Data=0 is actually Data=256 */
! 424: TimerData = 256;
! 425: TimerClockCycles = MFP_REG_TO_CYCLES ( TimerData, TimerControl );
! 426:
! 427: if ( HATARI_TRACE_LEVEL ( HATARI_TRACE_MFP_START ) )
! 428: {
! 429: int nFrameCycles = Cycles_GetCounter(CYCLES_COUNTER_VIDEO);
! 430: int nLineCycles = nFrameCycles % nCyclesPerLine;
! 431: HATARI_TRACE_PRINT ( "mfp start AB handler=%d data=%d ctrl=%d timer_cyc=%d pending_cyc=%d video_cyc=%d %d@%d pc=%x instr_cyc=%d first=%s resume=%s\n" ,
! 432: Handler, TimerData, TimerControl, TimerClockCycles, PendingCyclesOver,
! 433: nFrameCycles, nLineCycles, nHBL, M68000_GetPC(), CurrentInstrCycles,
! 434: bFirstTimer?"true":"false" , *pTimerCanResume?"true":"false" );
! 435: }
! 436:
! 437: /* And add to our internal interrupt list, if timer cycles is zero
! 438: * then timer is stopped */
! 439: Int_RemovePendingInterrupt(Handler);
! 440: if (TimerClockCycles)
! 441: {
! 442: if ( ( *pTimerCanResume == TRUE ) && ( bFirstTimer == TRUE ) ) /* we can't resume if the timer is auto restarting after an interrupt */
! 443: {
! 444: Int_ResumeStoppedInterrupt ( Handler );
! 445: }
! 446: else
! 447: {
! 448: int AddCurCycles = INT_CONVERT_TO_INTERNAL ( CurrentInstrCycles + nWaitStateCycles - 4 , INT_CPU_CYCLE );
! 449:
! 450: /* Start timer from now? If not continue timer using PendingCycleOver */
! 451: if (bFirstTimer)
! 452: Int_AddRelativeInterrupt(TimerClockCycles, INT_MFP_CYCLE, Handler, AddCurCycles);
! 453: else
! 454: {
! 455: int TimerClockCyclesInternal = INT_CONVERT_TO_INTERNAL ( TimerClockCycles , INT_MFP_CYCLE );
! 456:
! 457: /* In case we miss more than one int, we must correct the delay for the next one */
! 458: if ( PendingCyclesOver > TimerClockCyclesInternal )
! 459: PendingCyclesOver = PendingCyclesOver % TimerClockCyclesInternal;
! 460:
! 461: Int_AddRelativeInterruptWithOffset(TimerClockCycles, INT_MFP_CYCLE, Handler, -PendingCyclesOver);
! 462: }
1.1 root 463:
1.1.1.11! root 464: *pTimerCanResume = TRUE; /* timer was set, resume is possible if stop/start it later */
! 465: }
! 466: }
! 467: }
! 468: else
! 469: {
! 470: /* Make sure no outstanding interrupts in list if channel is disabled */
! 471: Int_RemovePendingInterrupt(Handler);
! 472: }
1.1 root 473:
1.1.1.11! root 474: return TimerClockCycles;
1.1 root 475: }
476:
1.1.1.2 root 477:
478: /*-----------------------------------------------------------------------*/
1.1.1.11! root 479: /**
! 480: * Start Timer C or D
! 481: */
! 482: static int MFP_StartTimer_CD(Uint8 TimerControl, Uint16 TimerData, int Handler,
! 483: BOOL bFirstTimer, BOOL *pTimerCanResume)
1.1 root 484: {
1.1.1.11! root 485: int TimerClockCycles = 0;
1.1 root 486:
1.1.1.11! root 487: /* Is timer in delay mode ? */
! 488: if ((TimerControl&0x7) != 0)
! 489: {
! 490: /* Find number of cycles for when timer is due (include preset and
! 491: * counter). As timer occurs very often we multiply by counter to
! 492: * speed up emulator */
! 493: if (TimerData == 0) /* Data=0 is actually Data=256 */
! 494: TimerData = 256;
! 495: TimerClockCycles = MFP_REG_TO_CYCLES ( TimerData, TimerControl );
! 496:
! 497: if ( HATARI_TRACE_LEVEL ( HATARI_TRACE_MFP_START ) )
! 498: {
! 499: int nFrameCycles = Cycles_GetCounter(CYCLES_COUNTER_VIDEO);
! 500: int nLineCycles = nFrameCycles % nCyclesPerLine;
! 501: HATARI_TRACE_PRINT ( "mfp start CD handler=%d data=%d ctrl=%d timer_cyc=%d pending_cyc=%d video_cyc=%d %d@%d pc=%x instr_cyc=%d first=%s resume=%s\n" ,
! 502: Handler, TimerData, TimerControl, TimerClockCycles, PendingCyclesOver,
! 503: nFrameCycles, nLineCycles, nHBL, M68000_GetPC(), CurrentInstrCycles,
! 504: bFirstTimer?"true":"false" , *pTimerCanResume?"true":"false" );
! 505: }
! 506:
! 507: /* And add to our internal interrupt list, if timer cycles is zero
! 508: * then timer is stopped */
! 509: Int_RemovePendingInterrupt(Handler);
! 510: if (TimerClockCycles)
! 511: {
! 512: if ( ( *pTimerCanResume == TRUE ) && ( bFirstTimer == TRUE ) ) /* we can't resume if the timer is auto restarting after an interrupt */
! 513: {
! 514: Int_ResumeStoppedInterrupt ( Handler );
! 515: }
! 516: else
! 517: {
! 518: int AddCurCycles = INT_CONVERT_TO_INTERNAL ( CurrentInstrCycles + nWaitStateCycles - 4 , INT_CPU_CYCLE );
! 519:
! 520: /* Start timer from now? If not continue timer using PendingCycleOver */
! 521: if (bFirstTimer)
! 522: Int_AddRelativeInterrupt(TimerClockCycles, INT_MFP_CYCLE, Handler, AddCurCycles);
! 523: else
! 524: {
! 525: int TimerClockCyclesInternal = INT_CONVERT_TO_INTERNAL ( TimerClockCycles , INT_MFP_CYCLE );
! 526:
! 527: /* In case we miss more than one int, we must correct the delay for the next one */
! 528: if ( PendingCyclesOver > TimerClockCyclesInternal )
! 529: PendingCyclesOver = PendingCyclesOver % TimerClockCyclesInternal;
! 530:
! 531: Int_AddRelativeInterruptWithOffset(TimerClockCycles, INT_MFP_CYCLE, Handler, -PendingCyclesOver);
! 532: }
! 533:
! 534: *pTimerCanResume = TRUE; /* timer was set, resume is possible if stop/start it later */
! 535: }
! 536: }
! 537: }
! 538: else
! 539: {
! 540: /* Make sure no outstanding interrupts in list if channel is disabled */
! 541: Int_RemovePendingInterrupt(Handler);
! 542: }
1.1 root 543:
1.1.1.11! root 544: return TimerClockCycles;
1.1 root 545: }
546:
1.1.1.2 root 547:
548: /*-----------------------------------------------------------------------*/
1.1.1.11! root 549: /**
! 550: * Read Timer A or B - If in EventCount MainCounter already has correct value
! 551: */
1.1.1.9 root 552: static Uint8 MFP_ReadTimer_AB(Uint8 TimerControl, Uint8 MainCounter, int TimerCycles, int Handler)
1.1 root 553: {
1.1.1.11! root 554: int TimerCyclesPassed;
1.1 root 555:
1.1.1.11! root 556: /* Find TimerAB count, if no interrupt or not in delay mode assume
! 557: * in Event Count mode so already up-to-date as kept by HBL */
! 558: if (Int_InterruptActive(Handler) && (TimerControl > 0) && (TimerControl <= 7))
! 559: {
! 560: /* Find cycles passed since last interrupt */
! 561: TimerCyclesPassed = TimerCycles - Int_FindCyclesPassed ( Handler, INT_MFP_CYCLE );
! 562: MainCounter = MFP_CYCLE_TO_REG ( Int_FindCyclesPassed ( Handler, INT_MFP_CYCLE ), TimerControl );
! 563: //fprintf ( stderr , "mfp read AB passed %d count %d\n" , TimerCyclesPassed, MainCounter );
! 564: }
! 565:
! 566: if ( HATARI_TRACE_LEVEL ( HATARI_TRACE_MFP_READ ) )
! 567: {
! 568: int nFrameCycles = Cycles_GetCounter(CYCLES_COUNTER_VIDEO);
! 569: int nLineCycles = nFrameCycles % nCyclesPerLine;
! 570: HATARI_TRACE_PRINT ( "mfp read AB handler=%d data=%d ctrl=%d timer_cyc=%d video_cyc=%d %d@%d pc=%x instr_cyc=%d\n" ,
! 571: Handler, MainCounter, TimerControl, TimerCycles,
! 572: nFrameCycles, nLineCycles, nHBL, M68000_GetPC(), CurrentInstrCycles );
! 573: }
1.1.1.6 root 574:
1.1.1.11! root 575: return MainCounter;
1.1 root 576: }
577:
1.1.1.2 root 578:
579: /*-----------------------------------------------------------------------*/
1.1.1.11! root 580: /**
! 581: * Read Timer C or D
! 582: */
1.1.1.9 root 583: static Uint8 MFP_ReadTimerCD(Uint8 TimerControl, Uint8 TimerData, Uint8 MainCounter, int TimerCycles, int Handler)
1.1 root 584: {
1.1.1.11! root 585: int TimerCyclesPassed;
1.1 root 586:
1.1.1.11! root 587: /* Find TimerCD count. If timer is off, MainCounter already contains
! 588: * the latest value */
! 589: if (Int_InterruptActive(Handler))
! 590: {
! 591: /* Find cycles passed since last interrupt */
! 592: TimerCyclesPassed = TimerCycles - Int_FindCyclesPassed ( Handler, INT_MFP_CYCLE );
! 593: MainCounter = MFP_CYCLE_TO_REG ( Int_FindCyclesPassed ( Handler, INT_MFP_CYCLE ), TimerControl);
! 594: //fprintf ( stderr , "mfp read CD passed %d count %d\n" , TimerCyclesPassed, MainCounter );
! 595: }
! 596:
! 597: if ( HATARI_TRACE_LEVEL ( HATARI_TRACE_MFP_READ ) )
! 598: {
! 599: int nFrameCycles = Cycles_GetCounter(CYCLES_COUNTER_VIDEO);
! 600: int nLineCycles = nFrameCycles % nCyclesPerLine;
! 601: HATARI_TRACE_PRINT ( "mfp read CD handler=%d data=%d ctrl=%d timer_cyc=%d video_cyc=%d %d@%d pc=%x instr_cyc=%d\n" ,
! 602: Handler, MainCounter, TimerControl, TimerCycles,
! 603: nFrameCycles, nLineCycles, nHBL, M68000_GetPC(), CurrentInstrCycles );
! 604: }
1.1 root 605:
1.1.1.11! root 606: return MainCounter;
1.1 root 607: }
608:
1.1.1.2 root 609:
610: /*-----------------------------------------------------------------------*/
1.1.1.11! root 611: /**
! 612: * Start Timer A
! 613: */
1.1.1.10 root 614: static void MFP_StartTimerA(void)
1.1 root 615: {
1.1.1.11! root 616: TimerAClockCycles = MFP_StartTimer_AB(MFP_TACR, MFP_TA_MAINCOUNTER,
! 617: INTERRUPT_MFP_TIMERA, TRUE, &TimerACanResume);
1.1 root 618: }
619:
620:
1.1.1.2 root 621: /*-----------------------------------------------------------------------*/
1.1.1.11! root 622: /**
! 623: * Read Timer A
! 624: */
1.1.1.10 root 625: static void MFP_ReadTimerA(void)
1.1 root 626: {
1.1.1.11! root 627: MFP_TA_MAINCOUNTER = MFP_ReadTimer_AB(MFP_TACR, MFP_TA_MAINCOUNTER,
! 628: TimerAClockCycles, INTERRUPT_MFP_TIMERA);
1.1 root 629: }
630:
631:
1.1.1.2 root 632: /*-----------------------------------------------------------------------*/
1.1.1.11! root 633: /**
! 634: * Start Timer B
! 635: * (This does not start the EventCount mode time as this is taken care
! 636: * of by the HBL)
! 637: */
1.1.1.10 root 638: static void MFP_StartTimerB(void)
1.1 root 639: {
1.1.1.11! root 640: TimerBClockCycles = MFP_StartTimer_AB(MFP_TBCR, MFP_TB_MAINCOUNTER,
! 641: INTERRUPT_MFP_TIMERB, TRUE, &TimerBCanResume);
1.1 root 642: }
643:
644:
1.1.1.2 root 645: /*-----------------------------------------------------------------------*/
1.1.1.11! root 646: /**
! 647: * Read Timer B
! 648: */
1.1.1.10 root 649: static void MFP_ReadTimerB(void)
1.1 root 650: {
1.1.1.11! root 651: MFP_TB_MAINCOUNTER = MFP_ReadTimer_AB(MFP_TBCR, MFP_TB_MAINCOUNTER,
! 652: TimerBClockCycles, INTERRUPT_MFP_TIMERB);
1.1 root 653: }
654:
655:
1.1.1.2 root 656: /*-----------------------------------------------------------------------*/
1.1.1.11! root 657: /**
! 658: * Start Timer C
! 659: */
1.1.1.10 root 660: static void MFP_StartTimerC(void)
1.1 root 661: {
1.1.1.11! root 662: TimerCClockCycles = MFP_StartTimer_CD((MFP_TCDCR>>4)&7, MFP_TC_MAINCOUNTER,
! 663: INTERRUPT_MFP_TIMERC , TRUE, &TimerCCanResume);
1.1 root 664: }
665:
666:
1.1.1.2 root 667: /*-----------------------------------------------------------------------*/
1.1.1.11! root 668: /**
! 669: * Read Timer C
! 670: */
1.1.1.10 root 671: static void MFP_ReadTimerC(void)
1.1 root 672: {
1.1.1.11! root 673: MFP_TC_MAINCOUNTER = MFP_ReadTimerCD((MFP_TCDCR>>4)&7, MFP_TCDR, MFP_TC_MAINCOUNTER,
! 674: TimerCClockCycles, INTERRUPT_MFP_TIMERC);
1.1 root 675: }
676:
677:
1.1.1.2 root 678: /*-----------------------------------------------------------------------*/
1.1.1.11! root 679: /**
! 680: * Start Timer D
! 681: */
1.1.1.10 root 682: static void MFP_StartTimerD(void)
1.1 root 683: {
1.1.1.11! root 684: TimerDClockCycles = MFP_StartTimer_CD(MFP_TCDCR&7, MFP_TD_MAINCOUNTER,
! 685: INTERRUPT_MFP_TIMERD, TRUE, &TimerDCanResume);
1.1 root 686: }
687:
688:
1.1.1.2 root 689: /*-----------------------------------------------------------------------*/
1.1.1.11! root 690: /**
! 691: * Read Timer D
! 692: */
1.1.1.10 root 693: static void MFP_ReadTimerD(void)
1.1 root 694: {
1.1.1.11! root 695: MFP_TD_MAINCOUNTER = MFP_ReadTimerCD(MFP_TCDCR&7, MFP_TDDR, MFP_TD_MAINCOUNTER,
! 696: TimerDClockCycles, INTERRUPT_MFP_TIMERD);
1.1 root 697: }
698:
699:
1.1.1.2 root 700: /*-----------------------------------------------------------------------*/
1.1.1.11! root 701: /**
! 702: * Handle Timer A Interrupt
! 703: */
1.1 root 704: void MFP_InterruptHandler_TimerA(void)
705: {
1.1.1.11! root 706: /* Number of internal cycles we went over for this timer ( <= 0 ),
! 707: * used when timer expires and needs to be restarted */
! 708: PendingCyclesOver = -PendingInterruptCount; /* >= 0 */
! 709:
! 710: /* Remove this interrupt from list and re-order */
! 711: Int_AcknowledgeInterrupt();
1.1 root 712:
1.1.1.11! root 713: /* Acknowledge in MFP circuit, pass bit,enable,pending */
! 714: if ((MFP_TACR&0xf) != 0) /* Is timer OK? */
! 715: MFP_InputOnChannel(MFP_TIMER_A_BIT, MFP_IERA, &MFP_IPRA);
1.1 root 716:
1.1.1.11! root 717: /* Start next interrupt, if need one - from current cycle count */
! 718: TimerAClockCycles = MFP_StartTimer_AB(MFP_TACR, MFP_TADR, INTERRUPT_MFP_TIMERA, FALSE, &TimerACanResume);
1.1 root 719: }
720:
721:
1.1.1.2 root 722: /*-----------------------------------------------------------------------*/
1.1.1.11! root 723: /**
! 724: * Handle Timer B Interrupt
! 725: */
1.1 root 726: void MFP_InterruptHandler_TimerB(void)
727: {
1.1.1.11! root 728: /* Number of internal cycles we went over for this timer ( <= 0 ),
! 729: * used when timer expires and needs to be restarted */
! 730: PendingCyclesOver = -PendingInterruptCount; /* >= 0 */
! 731:
! 732: /* Remove this interrupt from list and re-order */
! 733: Int_AcknowledgeInterrupt();
1.1 root 734:
1.1.1.11! root 735: /* Acknowledge in MFP circuit, pass bit, enable, pending */
! 736: if ((MFP_TBCR&0xf) != 0) /* Is timer OK? */
! 737: MFP_InputOnChannel(MFP_TIMER_B_BIT, MFP_IERA, &MFP_IPRA);
1.1 root 738:
1.1.1.11! root 739: /* Start next interrupt, if need one - from current cycle count */
! 740: TimerBClockCycles = MFP_StartTimer_AB(MFP_TBCR, MFP_TBDR, INTERRUPT_MFP_TIMERB, FALSE, &TimerBCanResume);
1.1 root 741: }
742:
743:
1.1.1.2 root 744: /*-----------------------------------------------------------------------*/
1.1.1.11! root 745: /**
! 746: * Handle Timer C Interrupt
! 747: */
1.1 root 748: void MFP_InterruptHandler_TimerC(void)
749: {
1.1.1.11! root 750: /* Number of internal cycles we went over for this timer ( <= 0 ),
! 751: * used when timer expires and needs to be restarted */
! 752: PendingCyclesOver = -PendingInterruptCount; /* >= 0 */
1.1 root 753:
1.1.1.11! root 754: /* Remove this interrupt from list and re-order */
! 755: Int_AcknowledgeInterrupt();
1.1 root 756:
1.1.1.11! root 757: /* Acknowledge in MFP circuit, pass bit, enable, pending */
! 758: if ((MFP_TCDCR&0x70) != 0) /* Is timer OK? */
! 759: MFP_InputOnChannel(MFP_TIMER_C_BIT, MFP_IERB, &MFP_IPRB);
! 760:
! 761: /* Start next interrupt, if need one - from current cycle count */
! 762: TimerCClockCycles = MFP_StartTimer_CD((MFP_TCDCR>>4)&7, MFP_TCDR, INTERRUPT_MFP_TIMERC, FALSE, &TimerCCanResume);
1.1 root 763: }
764:
765:
1.1.1.2 root 766: /*-----------------------------------------------------------------------*/
1.1.1.11! root 767: /**
! 768: * Handle Timer D Interrupt
! 769: */
1.1 root 770: void MFP_InterruptHandler_TimerD(void)
771: {
1.1.1.11! root 772: /* Number of internal cycles we went over for this timer ( <= 0 ),
! 773: * used when timer expires and needs to be restarted */
! 774: PendingCyclesOver = -PendingInterruptCount; /* >= 0 */
! 775:
! 776: /* Remove this interrupt from list and re-order */
! 777: Int_AcknowledgeInterrupt();
! 778:
! 779: /* Acknowledge in MFP circuit, pass bit, enable, pending */
! 780: if ((MFP_TCDCR&0x07) != 0) /* Is timer OK? */
! 781: MFP_InputOnChannel(MFP_TIMER_D_BIT, MFP_IERB, &MFP_IPRB);
! 782:
! 783: /* Start next interrupt, if need one - from current cycle count */
! 784: TimerDClockCycles = MFP_StartTimer_CD(MFP_TCDCR&7, MFP_TDDR, INTERRUPT_MFP_TIMERD, FALSE, &TimerDCanResume);
1.1 root 785: }
786:
1.1.1.8 root 787:
788:
789: /*-----------------------------------------------------------------------*/
1.1.1.11! root 790: /**
! 791: * Handle read from GPIP pins register (0xfffa01).
! 792: *
! 793: * - Bit 0 is the BUSY signal of the printer port, it is SET if no printer
! 794: * is connected or on BUSY. Therefor we should assume it to be 0 in Hatari
! 795: * when a printer is emulated.
! 796: * - Bit 1 is used for RS232: DCD
! 797: * - Bit 2 is used for RS232: CTS
! 798: * - Bit 3 is used by the blitter for signalling when its done.
! 799: * - Bit 4 is used by the ACIAs.
! 800: * - Bit 5 is used by the floppy controller / ACSI DMA
! 801: * - Bit 6 is used for RS232: RI
! 802: * - Bit 7 is monochrome monitor detection signal. On STE it is also XORed with
! 803: * the DMA sound play bit.
! 804: */
1.1.1.8 root 805: void MFP_GPIP_ReadByte(void)
806: {
1.1.1.10 root 807: M68000_WaitState(4);
808:
1.1.1.8 root 809: if (!bUseHighRes)
1.1.1.11! root 810: MFP_GPIP |= 0x80; /* Color monitor -> set top bit */
1.1.1.9 root 811: else
812: MFP_GPIP &= ~0x80;
813: if (nDmaSoundControl & DMASNDCTRL_PLAY)
1.1.1.11! root 814: MFP_GPIP ^= 0x80; /* Top bit is XORed with DMA sound control play bit */
1.1.1.9 root 815:
816: if (ConfigureParams.Printer.bEnablePrinting)
817: {
818: /* Signal that printer is not busy */
819: MFP_GPIP &= ~1;
820: }
821: else
822: {
823: MFP_GPIP |= 1;
824:
825: /* Printer BUSY bit is also used by parallel port joystick adapters as fire button */
826: if (ConfigureParams.Joysticks.Joy[JOYID_PARPORT1].nJoystickMode != JOYSTICK_DISABLED)
827: {
828: /* Fire pressed? */
829: if (Joy_GetStickData(JOYID_PARPORT1) & 0x80)
830: MFP_GPIP &= ~1;
831: }
832: }
1.1.1.8 root 833:
1.1.1.10 root 834: FDC_GpipRead();
835:
1.1.1.9 root 836: IoMem[0xfffa01] = MFP_GPIP;
1.1.1.8 root 837: }
838:
839: /*-----------------------------------------------------------------------*/
1.1.1.11! root 840: /**
! 841: * Handle read from active edge register (0xfffa03).
! 842: */
1.1.1.8 root 843: void MFP_ActiveEdge_ReadByte(void)
844: {
1.1.1.10 root 845: M68000_WaitState(4);
846:
1.1.1.8 root 847: IoMem[0xfffa03] = MFP_AER;
848: }
849:
850: /*-----------------------------------------------------------------------*/
1.1.1.11! root 851: /**
! 852: * Handle read from data direction register (0xfffa05).
! 853: */
1.1.1.8 root 854: void MFP_DataDirection_ReadByte(void)
855: {
1.1.1.10 root 856: M68000_WaitState(4);
857:
1.1.1.8 root 858: IoMem[0xfffa05] = MFP_DDR;
859: }
860:
861: /*-----------------------------------------------------------------------*/
1.1.1.11! root 862: /**
! 863: * Handle read from interupt enable register A (0xfffa07).
! 864: */
1.1.1.8 root 865: void MFP_EnableA_ReadByte(void)
866: {
1.1.1.10 root 867: M68000_WaitState(4);
868:
1.1.1.8 root 869: IoMem[0xfffa07] = MFP_IERA;
870: }
871:
872: /*-----------------------------------------------------------------------*/
1.1.1.11! root 873: /**
! 874: * Handle read from interupt enable register B (0xfffa09).
! 875: */
1.1.1.8 root 876: void MFP_EnableB_ReadByte(void)
877: {
1.1.1.10 root 878: M68000_WaitState(4);
879:
1.1.1.8 root 880: IoMem[0xfffa09] = MFP_IERB;
881: }
882:
883: /*-----------------------------------------------------------------------*/
1.1.1.11! root 884: /**
! 885: * Handle read from interupt pending register A (0xfffa0b).
! 886: */
1.1.1.8 root 887: void MFP_PendingA_ReadByte(void)
888: {
1.1.1.10 root 889: M68000_WaitState(4);
890:
1.1.1.8 root 891: IoMem[0xfffa0b] = MFP_IPRA;
892: }
893:
894: /*-----------------------------------------------------------------------*/
1.1.1.11! root 895: /**
! 896: * Handle read from interupt pending register A (0xfffa0d).
! 897: */
1.1.1.8 root 898: void MFP_PendingB_ReadByte(void)
899: {
1.1.1.10 root 900: M68000_WaitState(4);
901:
1.1.1.8 root 902: IoMem[0xfffa0d] = MFP_IPRB;
903: }
904:
905: /*-----------------------------------------------------------------------*/
1.1.1.11! root 906: /**
! 907: * Handle read from interupt in service register A (0xfffa0f).
! 908: */
1.1.1.8 root 909: void MFP_InServiceA_ReadByte(void)
910: {
1.1.1.10 root 911: M68000_WaitState(4);
912:
1.1.1.8 root 913: IoMem[0xfffa0f] = MFP_ISRA;
914: }
915:
916: /*-----------------------------------------------------------------------*/
1.1.1.11! root 917: /**
! 918: * Handle read from interupt in service register B (0xfffa11).
! 919: */
1.1.1.8 root 920: void MFP_InServiceB_ReadByte(void)
921: {
1.1.1.10 root 922: M68000_WaitState(4);
923:
1.1.1.8 root 924: IoMem[0xfffa11] = MFP_ISRB;
925: }
926:
927: /*-----------------------------------------------------------------------*/
1.1.1.11! root 928: /**
! 929: * Handle read from interupt mask register A (0xfffa13).
! 930: */
1.1.1.8 root 931: void MFP_MaskA_ReadByte(void)
932: {
1.1.1.10 root 933: M68000_WaitState(4);
934:
1.1.1.8 root 935: IoMem[0xfffa13] = MFP_IMRA;
936: }
937:
938: /*-----------------------------------------------------------------------*/
1.1.1.11! root 939: /**
! 940: * Handle read from interupt mask register B (0xfffa15).
! 941: */
1.1.1.8 root 942: void MFP_MaskB_ReadByte(void)
943: {
1.1.1.10 root 944: M68000_WaitState(4);
945:
1.1.1.8 root 946: IoMem[0xfffa15] = MFP_IMRB;
947: }
948:
949: /*-----------------------------------------------------------------------*/
1.1.1.11! root 950: /**
! 951: * Handle read from MFP vector register (0xfffa17).
! 952: */
1.1.1.8 root 953: void MFP_VectorReg_ReadByte(void)
954: {
1.1.1.10 root 955: M68000_WaitState(4);
956:
1.1.1.8 root 957: IoMem[0xfffa17] = MFP_VR;
958: }
959:
960: /*-----------------------------------------------------------------------*/
1.1.1.11! root 961: /**
! 962: * Handle read from timer A control register (0xfffa19).
! 963: */
1.1.1.8 root 964: void MFP_TimerACtrl_ReadByte(void)
965: {
1.1.1.10 root 966: M68000_WaitState(4);
967:
1.1.1.8 root 968: IoMem[0xfffa19] = MFP_TACR;
969: }
970:
971: /*-----------------------------------------------------------------------*/
1.1.1.11! root 972: /**
! 973: * Handle read from timer B control register (0xfffa1b).
! 974: */
1.1.1.8 root 975: void MFP_TimerBCtrl_ReadByte(void)
976: {
1.1.1.10 root 977: M68000_WaitState(4);
978:
1.1.1.8 root 979: IoMem[0xfffa1b] = MFP_TBCR;
980: }
981:
982: /*-----------------------------------------------------------------------*/
1.1.1.11! root 983: /**
! 984: * Handle read from timer C/D control register (0xfffa1d).
! 985: */
1.1.1.8 root 986: void MFP_TimerCDCtrl_ReadByte(void)
987: {
1.1.1.10 root 988: M68000_WaitState(4);
989:
1.1.1.8 root 990: IoMem[0xfffa1d] = MFP_TCDCR;
991: }
992:
993: /*-----------------------------------------------------------------------*/
1.1.1.11! root 994: /**
! 995: * Handle read from timer A data register (0xfffa1f).
! 996: */
1.1.1.8 root 997: void MFP_TimerAData_ReadByte(void)
998: {
1.1.1.10 root 999: M68000_WaitState(4);
1000:
1.1.1.8 root 1001: if (MFP_TACR != 8) /* Is event count? Need to re-calculate counter */
1002: MFP_ReadTimerA(); /* Stores result in 'MFP_TA_MAINCOUNTER' */
1003:
1004: IoMem[0xfffa1f] = MFP_TA_MAINCOUNTER;
1005: }
1006:
1007: /*-----------------------------------------------------------------------*/
1.1.1.11! root 1008: /**
! 1009: * Handle read from timer B data register (0xfffa21).
! 1010: */
1.1.1.8 root 1011: void MFP_TimerBData_ReadByte(void)
1012: {
1.1.1.10 root 1013: M68000_WaitState(4);
1014:
1.1.1.8 root 1015: if (MFP_TBCR != 8) /* Is event count? Need to re-calculate counter */
1016: MFP_ReadTimerB(); /* Stores result in 'MFP_TB_MAINCOUNTER' */
1017:
1018: IoMem[0xfffa21] = MFP_TB_MAINCOUNTER;
1019: }
1020:
1021: /*-----------------------------------------------------------------------*/
1.1.1.11! root 1022: /**
! 1023: * Handle read from timer C data register (0xfffa23).
! 1024: */
1.1.1.8 root 1025: void MFP_TimerCData_ReadByte(void)
1026: {
1.1.1.10 root 1027: M68000_WaitState(4);
1028:
1.1.1.8 root 1029: MFP_ReadTimerC(); /* Stores result in 'MFP_TC_MAINCOUNTER' */
1030:
1031: IoMem[0xfffa23] = MFP_TC_MAINCOUNTER;
1032: }
1033:
1034: /*-----------------------------------------------------------------------*/
1.1.1.11! root 1035: /**
! 1036: * Handle read from timer D data register (0xfffa25).
! 1037: */
1.1.1.8 root 1038: void MFP_TimerDData_ReadByte(void)
1039: {
1.1.1.11! root 1040: Uint32 pc = M68000_GetPC();
1.1.1.8 root 1041:
1.1.1.10 root 1042: M68000_WaitState(4);
1043:
1.1.1.8 root 1044: if (ConfigureParams.System.bPatchTimerD && pc >= TosAddress && pc <= TosAddress + TosSize)
1045: {
1046: /* Trick the tos to believe it was changed: */
1047: IoMem[0xfffa25] = nTimerDFakeValue;
1048: }
1049: else
1050: {
1051: MFP_ReadTimerD(); /* Stores result in 'MFP_TD_MAINCOUNTER' */
1052: IoMem[0xfffa25] = MFP_TD_MAINCOUNTER;
1053: }
1054: }
1055:
1056:
1057: /*-----------------------------------------------------------------------*/
1.1.1.11! root 1058: /**
! 1059: * Handle write to GPIP register (0xfffa01).
! 1060: */
1.1.1.8 root 1061: void MFP_GPIP_WriteByte(void)
1062: {
1.1.1.10 root 1063: M68000_WaitState(4);
1064:
1.1.1.8 root 1065: /* Nothing... */
1066: /*fprintf(stderr, "Write to GPIP: %x\n", (int)IoMem[0xfffa01]);*/
1067: /*MFP_GPIP = IoMem[0xfffa01];*/ /* TODO: What are the GPIP pins good for? */
1068: }
1069:
1070: /*-----------------------------------------------------------------------*/
1.1.1.11! root 1071: /**
! 1072: * Handle write to AER (0xfffa03).
! 1073: */
1.1.1.8 root 1074: void MFP_ActiveEdge_WriteByte(void)
1075: {
1.1.1.10 root 1076: M68000_WaitState(4);
1077:
1.1.1.8 root 1078: MFP_AER = IoMem[0xfffa03];
1079: }
1080:
1081: /*-----------------------------------------------------------------------*/
1.1.1.11! root 1082: /**
! 1083: * Handle write to data direction register (0xfffa05).
! 1084: */
1.1.1.8 root 1085: void MFP_DataDirection_WriteByte(void)
1086: {
1.1.1.10 root 1087: M68000_WaitState(4);
1088:
1.1.1.8 root 1089: MFP_DDR = IoMem[0xfffa05];
1090: }
1091:
1092: /*-----------------------------------------------------------------------*/
1.1.1.11! root 1093: /**
! 1094: * Handle write to interrupt enable register A (0xfffa07).
! 1095: */
1.1.1.8 root 1096: void MFP_EnableA_WriteByte(void)
1097: {
1.1.1.10 root 1098: M68000_WaitState(4);
1099:
1.1.1.8 root 1100: MFP_IERA = IoMem[0xfffa07];
1101: MFP_IPRA &= MFP_IERA;
1102: MFP_UpdateFlags();
1103: /* We may have enabled Timer A or B, check */
1.1.1.11! root 1104: /* [NP] No check, restarting the timer is wrong */
! 1105: // MFP_StartTimerA();
! 1106: // MFP_StartTimerB();
1.1.1.8 root 1107: }
1108:
1109: /*-----------------------------------------------------------------------*/
1.1.1.11! root 1110: /**
! 1111: * Handle write to interrupt enable register B (0xfffa09).
! 1112: */
1.1.1.8 root 1113: void MFP_EnableB_WriteByte(void)
1114: {
1.1.1.10 root 1115: M68000_WaitState(4);
1116:
1.1.1.8 root 1117: MFP_IERB = IoMem[0xfffa09];
1118: MFP_IPRB &= MFP_IERB;
1119: MFP_UpdateFlags();
1120: /* We may have enabled Timer C or D, check */
1.1.1.11! root 1121: /* [NP] No check, restarting the timer is wrong */
! 1122: // MFP_StartTimerC();
! 1123: // MFP_StartTimerD();
1.1.1.8 root 1124: }
1125:
1126: /*-----------------------------------------------------------------------*/
1.1.1.11! root 1127: /**
! 1128: * Handle write to interrupt pending register A (0xfffa0b).
! 1129: */
1.1.1.8 root 1130: void MFP_PendingA_WriteByte(void)
1131: {
1.1.1.10 root 1132: M68000_WaitState(4);
1133:
1.1.1.8 root 1134: MFP_IPRA &= IoMem[0xfffa0b]; /* Cannot set pending bits - only clear via software */
1135: MFP_UpdateFlags(); /* Check if any interrupts pending */
1136: }
1137:
1138: /*-----------------------------------------------------------------------*/
1.1.1.11! root 1139: /**
! 1140: * Handle write to interrupt pending register B (0xfffa0d).
! 1141: */
1.1.1.8 root 1142: void MFP_PendingB_WriteByte(void)
1143: {
1.1.1.10 root 1144: M68000_WaitState(4);
1145:
1.1.1.8 root 1146: MFP_IPRB &= IoMem[0xfffa0d];
1147: MFP_UpdateFlags(); /* Check if any interrupts pending */
1148: }
1149:
1150: /*-----------------------------------------------------------------------*/
1.1.1.11! root 1151: /**
! 1152: * Handle write to interrupt in service register A (0xfffa0f).
! 1153: */
1.1.1.8 root 1154: void MFP_InServiceA_WriteByte(void)
1155: {
1.1.1.10 root 1156: M68000_WaitState(4);
1157:
1.1.1.8 root 1158: MFP_ISRA &= IoMem[0xfffa0f]; /* Cannot set in-service bits - only clear via software */
1159: }
1160:
1161: /*-----------------------------------------------------------------------*/
1.1.1.11! root 1162: /**
! 1163: * Handle write to interrupt in service register B (0xfffa11).
! 1164: */
1.1.1.8 root 1165: void MFP_InServiceB_WriteByte(void)
1166: {
1.1.1.10 root 1167: M68000_WaitState(4);
1168:
1.1.1.8 root 1169: MFP_ISRB &= IoMem[0xfffa11]; /* Cannot set in-service bits - only clear via software */
1170: }
1171:
1172: /*-----------------------------------------------------------------------*/
1.1.1.11! root 1173: /**
! 1174: * Handle write to interrupt mask register A (0xfffa13).
! 1175: */
1.1.1.8 root 1176: void MFP_MaskA_WriteByte(void)
1177: {
1.1.1.10 root 1178: M68000_WaitState(4);
1179:
1.1.1.8 root 1180: MFP_IMRA = IoMem[0xfffa13];
1181: }
1182:
1183: /*-----------------------------------------------------------------------*/
1.1.1.11! root 1184: /**
! 1185: * Handle write to interrupt mask register B (0xfffa15).
! 1186: */
1.1.1.8 root 1187: void MFP_MaskB_WriteByte(void)
1188: {
1.1.1.10 root 1189: M68000_WaitState(4);
1190:
1.1.1.8 root 1191: MFP_IMRB = IoMem[0xfffa15];
1192: }
1193:
1194: /*-----------------------------------------------------------------------*/
1.1.1.11! root 1195: /**
! 1196: * Handle write to MFP vector register (0xfffa17).
! 1197: */
1.1.1.8 root 1198: void MFP_VectorReg_WriteByte(void)
1199: {
1200: Uint8 old_vr;
1.1.1.10 root 1201:
1202: M68000_WaitState(4);
1203:
1.1.1.8 root 1204: old_vr = MFP_VR; /* Copy for checking if set mode */
1205: MFP_VR = IoMem[0xfffa17];
1.1.1.10 root 1206:
1.1.1.8 root 1207: if ((MFP_VR^old_vr) & 0x08) /* Test change in end-of-interrupt mode */
1208: {
1.1.1.10 root 1209: /* Mode did change but was it to automatic mode? (ie bit is a zero) */
1210: if (!(MFP_VR & 0x08))
1211: {
1212: /* We are now in automatic mode, so clear all in-service bits! */
1.1.1.8 root 1213: MFP_ISRA = 0;
1214: MFP_ISRB = 0;
1215: }
1216: }
1.1.1.11! root 1217:
! 1218: if ( HATARI_TRACE_LEVEL ( HATARI_TRACE_MFP_WRITE ) )
! 1219: {
! 1220: int nFrameCycles = Cycles_GetCounter(CYCLES_COUNTER_VIDEO);;
! 1221: int nLineCycles = nFrameCycles % nCyclesPerLine;
! 1222: HATARI_TRACE_PRINT ( "mfp write vector reg fa17=%x video_cyc=%d %d@%d pc=%x instr_cycle %d\n" ,
! 1223: MFP_VR, nFrameCycles, nLineCycles, nHBL, M68000_GetPC(), CurrentInstrCycles );
! 1224: }
! 1225:
1.1.1.8 root 1226: }
1227:
1228: /*-----------------------------------------------------------------------*/
1.1.1.11! root 1229: /**
! 1230: * Handle write to timer A control register (0xfffa19).
! 1231: */
1.1.1.8 root 1232: void MFP_TimerACtrl_WriteByte(void)
1233: {
1.1.1.11! root 1234: Uint8 new_tacr;
1.1.1.10 root 1235:
1236: M68000_WaitState(4);
1237:
1.1.1.11! root 1238: new_tacr = IoMem[0xfffa19] & 0x0f; /* FIXME : ignore bit 4 (reset) ? */
1.1.1.10 root 1239:
1.1.1.11! root 1240: if ( MFP_TACR != new_tacr ) /* Timer control changed */
! 1241: {
! 1242: /* If we stop a timer which was in delay mode, we need to store
! 1243: * the current value of the counter to be able to read it or to
! 1244: * continue from where we left if the timer is restarted later
! 1245: * without writing to the data register. */
! 1246: if ((new_tacr == 0) && (MFP_TACR >=1) && (MFP_TACR <= 7))
! 1247: MFP_ReadTimerA(); /* Store result in 'MFP_TA_MAINCOUNTER' */
! 1248:
! 1249: MFP_TACR = new_tacr; /* set to new value before calling MFP_StartTimer */
! 1250: MFP_StartTimerA(); /* start/stop timer depending on control reg */
! 1251: }
1.1.1.8 root 1252: }
1253:
1254: /*-----------------------------------------------------------------------*/
1.1.1.11! root 1255: /**
! 1256: * Handle write to timer B control register (0xfffa1b).
! 1257: */
1.1.1.8 root 1258: void MFP_TimerBCtrl_WriteByte(void)
1259: {
1.1.1.11! root 1260: Uint8 new_tbcr;
1.1.1.10 root 1261:
1262: M68000_WaitState(4);
1263:
1.1.1.11! root 1264: new_tbcr = IoMem[0xfffa1b] & 0x0f; /* FIXME : ignore bit 4 (reset) ? */
! 1265:
! 1266: if (MFP_TBCR != new_tbcr) /* Timer control changed */
! 1267: {
! 1268: /* If we stop a timer which was in delay mode, we need to store
! 1269: * the current value of the counter to be able to read it or to
! 1270: * continue from where we left if the timer is restarted later
! 1271: * without writing to the data register. */
! 1272: if ((new_tbcr == 0) && (MFP_TBCR >= 1) && (MFP_TBCR <= 7))
! 1273: MFP_ReadTimerB(); /* Store result in 'MFP_TB_MAINCOUNTER' */
1.1.1.10 root 1274:
1.1.1.11! root 1275: MFP_TBCR = new_tbcr; /* set to new value before calling MFP_StartTimer */
! 1276: MFP_StartTimerB(); /* start/stop timer depending on control reg */
! 1277: }
1.1.1.8 root 1278: }
1279:
1280: /*-----------------------------------------------------------------------*/
1.1.1.11! root 1281: /**
! 1282: * Handle write to timer C/D control register (0xfffa1d).
! 1283: */
1.1.1.8 root 1284: void MFP_TimerCDCtrl_WriteByte(void)
1285: {
1.1.1.11! root 1286: Uint8 new_tcdcr;
1.1.1.8 root 1287: Uint8 old_tcdcr;
1288:
1.1.1.10 root 1289: M68000_WaitState(4);
1290:
1.1.1.11! root 1291: new_tcdcr = IoMem[0xfffa1d];
! 1292: old_tcdcr = MFP_TCDCR;
1.1.1.8 root 1293:
1.1.1.11! root 1294: if ((old_tcdcr & 0x70) != (new_tcdcr & 0x70)) /* Timer control changed */
! 1295: {
! 1296: /* If we stop a timer which was in delay mode, we need to store
! 1297: * the current value of the counter to be able to read it or to
! 1298: * continue from where we left if the timer is restarted later
! 1299: * without writing to the data register. */
! 1300: if ((new_tcdcr & 0x70) == 0)
! 1301: MFP_ReadTimerC(); /* Store result in 'MFP_TC_MAINCOUNTER' */
! 1302:
! 1303: MFP_TCDCR = ( new_tcdcr & 0x70 ) | ( old_tcdcr & 0x07 ); /* we set TCCR and keep old TDDR */
! 1304: MFP_StartTimerC(); /* start/stop timer depending on control reg */
! 1305: }
1.1.1.8 root 1306:
1.1.1.11! root 1307: if ((old_tcdcr & 0x07) != (new_tcdcr & 0x07)) /* Timer control changed */
1.1.1.8 root 1308: {
1.1.1.11! root 1309: Uint32 pc = M68000_GetPC();
1.1.1.8 root 1310:
1311: /* Need to change baud rate of RS232 emulation? */
1312: if (ConfigureParams.RS232.bEnableRS232)
1313: {
1314: RS232_SetBaudRateFromTimerD();
1315: }
1316:
1317: if (ConfigureParams.System.bPatchTimerD && !bAppliedTimerDPatch
1.1.1.11! root 1318: && pc >= TosAddress && pc <= TosAddress + TosSize)
1.1.1.8 root 1319: {
1.1.1.11! root 1320: /* Slow down Timer-D if set from TOS for the first time to gain
! 1321: * more desktop performance.
! 1322: * Obviously, we need to emulate all timers correctly but TOS sets
! 1323: * up Timer-D at a very high rate (every couple of instructions).
! 1324: * The interrupt isn't enabled but the emulator still needs to
! 1325: * process the interrupt table and this HALVES our frame rate!!!
1.1.1.8 root 1326: * Some games actually reference this timer but don't set it up
1.1.1.11! root 1327: * (eg Paradroid, Speedball I) so we simply intercept the Timer-D
! 1328: * setup code in TOS and fix the numbers with more 'laid-back'
! 1329: * values. This still keeps 100% compatibility */
! 1330: // FIXME [NP] : this seems wrong, this can set TDCR to 7 even if it was 0 !
! 1331: new_tcdcr = IoMem[0xfffa1d] = (IoMem[0xfffa1d] & 0xf0) | 7;
1.1.1.8 root 1332: bAppliedTimerDPatch = TRUE;
1333: }
1.1.1.11! root 1334:
! 1335: /* If we stop a timer which was in delay mode, we need to store the current value */
! 1336: /* of the counter to be able to read it or to continue from where we left if the timer is */
! 1337: /* restarted later without writing to the data register. */
! 1338: if ((new_tcdcr & 0x07) == 0)
! 1339: MFP_ReadTimerD(); /* Stores result in 'MFP_TD_MAINCOUNTER' */
! 1340:
! 1341: MFP_TCDCR = new_tcdcr; /* set to new value before calling MFP_StartTimer */
! 1342: MFP_StartTimerD(); /* start/stop timer depending on control reg */
1.1.1.8 root 1343: }
1344: }
1345:
1346: /*-----------------------------------------------------------------------*/
1.1.1.11! root 1347: /**
! 1348: * Handle write to timer A data register (0xfffa1f).
! 1349: */
1.1.1.8 root 1350: void MFP_TimerAData_WriteByte(void)
1351: {
1.1.1.10 root 1352: M68000_WaitState(4);
1353:
1.1.1.8 root 1354: MFP_TADR = IoMem[0xfffa1f]; /* Store into data register */
1.1.1.10 root 1355:
1.1.1.8 root 1356: if (MFP_TACR == 0) /* Now check if timer is running - if so do not set */
1357: {
1358: MFP_TA_MAINCOUNTER = MFP_TADR; /* Timer is off, store to main counter */
1.1.1.11! root 1359: TimerACanResume = FALSE; /* we need to set a new int when timer start */
1.1.1.8 root 1360: }
1361: }
1362:
1363: /*-----------------------------------------------------------------------*/
1.1.1.11! root 1364: /**
! 1365: * Handle write to timer B data register (0xfffa21).
! 1366: */
1.1.1.8 root 1367: void MFP_TimerBData_WriteByte(void)
1368: {
1.1.1.10 root 1369: M68000_WaitState(4);
1370:
1.1.1.8 root 1371: MFP_TBDR = IoMem[0xfffa21]; /* Store into data register */
1.1.1.10 root 1372:
1.1.1.8 root 1373: if (MFP_TBCR == 0) /* Now check if timer is running - if so do not set */
1374: {
1375: MFP_TB_MAINCOUNTER = MFP_TBDR; /* Timer is off, store to main counter */
1.1.1.11! root 1376: TimerBCanResume = FALSE; /* we need to set a new int when timer start */
1.1.1.8 root 1377: }
1378: }
1379:
1380: /*-----------------------------------------------------------------------*/
1.1.1.11! root 1381: /**
! 1382: * Handle write to timer C data register (0xfffa23).
! 1383: */
1.1.1.8 root 1384: void MFP_TimerCData_WriteByte(void)
1385: {
1.1.1.10 root 1386: M68000_WaitState(4);
1387:
1.1.1.8 root 1388: MFP_TCDR = IoMem[0xfffa23]; /* Store into data register */
1.1.1.10 root 1389:
1.1.1.8 root 1390: if ((MFP_TCDCR&0x70) == 0) /* Now check if timer is running - if so do not set */
1391: {
1.1.1.11! root 1392: MFP_TC_MAINCOUNTER = MFP_TCDR; /* Timer is off, store to main counter */
! 1393: TimerCCanResume = FALSE; /* we need to set a new int when timer start */
1.1.1.8 root 1394: }
1395: }
1396:
1397: /*-----------------------------------------------------------------------*/
1.1.1.11! root 1398: /**
! 1399: * Handle write to timer D data register (0xfffa25).
! 1400: */
1.1.1.8 root 1401: void MFP_TimerDData_WriteByte(void)
1402: {
1.1.1.11! root 1403: Uint32 pc = M68000_GetPC();
1.1.1.8 root 1404:
1.1.1.10 root 1405: M68000_WaitState(4);
1406:
1.1.1.8 root 1407: /* Need to change baud rate of RS232 emulation? */
1408: if (ConfigureParams.RS232.bEnableRS232 && (IoMem[0xfffa1d] & 0x07))
1409: {
1410: RS232_SetBaudRateFromTimerD();
1411: }
1412:
1413: /* Patch Timer-D for better performance? */
1414: if (ConfigureParams.System.bPatchTimerD && pc >= TosAddress && pc <= TosAddress + TosSize)
1415: {
1416: nTimerDFakeValue = IoMem[0xfffa25];
1417: IoMem[0xfffa25] = 0x64; /* Slow down the useless Timer-D setup from the bios */
1418: }
1419:
1420: MFP_TDDR = IoMem[0xfffa25]; /* Store into data register */
1421: if ((MFP_TCDCR&0x07) == 0) /* Now check if timer is running - if so do not set */
1422: {
1.1.1.11! root 1423: MFP_TD_MAINCOUNTER = MFP_TDDR; /* Timer is off, store to main counter */
! 1424: TimerDCanResume = FALSE; /* we need to set a new int when timer start */
1.1.1.8 root 1425: }
1426: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.