|
|
1.1 root 1: /* 1.1.1.5 root 2: Hatari - mfp.c 1.1 root 3: 1.1.1.18! root 4: This file is distributed under the GNU General Public License, version 2 ! 5: or at your option any later version. Read the file gpl.txt for details. 1.1.1.5 root 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 */ 1.1.1.12 root 26: /* changes since start, instead of the remaining counter value). */ 1.1.1.11 root 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(). */ 1.1.1.12 root 60: /* 2008/04/17 [NP] Handle the case where Timer B is in event count mode and the */ 61: /* content of $fffa21 is updated by the end of line signal while a */ 62: /* read instruction at addr $fffa21 occurs at the same time (before*/ 63: /* calling MFP_TimerB_EventCount_Interrupt). */ 64: /* In that case, we need to return MFP_TB_MAINCOUNTER - 1. */ 65: /* (fix B.I.G. Demo Screen 1). */ 66: /* FIXME : this should be handled by Cycles_GetCounterOnReadAccess */ 67: /* but it's not correctly implemented at the moment. */ 68: /* 2008/04/20 [NP] In the TRACE call in 'MFP_Exception', replace 'get_long' by */ 69: /* 'STMemory_ReadLong' because 'get_long' produced a bus error */ 70: /* if we were not already in supervisor mode when the mfp exception*/ 1.1.1.18! root 71: /* occurred. This could cause bus error when restoring snapshot */ 1.1.1.12 root 72: /* of a gemdos program for example if trace mode was activated. */ 73: /* 2008/07/12 [NP] When stopping an active timer just when the internal data */ 74: /* counter is going from 1 to 0, the internal data counter will be */ 75: /* set to 0 (=256) instead of being reloaded with the original */ 76: /* data value. In case no new value is written to the data reg, */ 77: /* this means a write > 0 to the control reg will restart the timer*/ 78: /* with a counter of 256 ! (fix timer saving routine used by */ 79: /* ST Cnx in the Punish Your Machine and the Froggies Over The */ 80: /* Fence (although this routine is in fact buggy)). */ 81: /* 2008/09/13 [NP] Add some traces when stopping a timer and changing data reg. */ 82: /* Don't apply timer D patch if timer D ctrl reg is 0. */ 83: /* 2008/10/04 [NP] In MFP_TimerBData_ReadByte, test for overlap only when nHBL */ 84: /* is between nStartHBL and nEndHBL (fix Wolfenstein 3D intro). */ 85: /* In event count mode for timer A and B, set data reg to 255 when */ 86: /* data reg was 0 (which in fact means 256). */ 87: /* 2008/10/16 [NP] No need to set data reg to 255 when decrementing a data reg that*/ 88: /* was 0, this is already what is implicitly done, because data */ 89: /* reg for timer A/B is Uint8 (revert 2008/10/04 changes). */ 1.1.1.14 root 90: /* 2008/12/11 [NP] In MFP_CheckPendingInterrupts(), returns true or false instead */ 1.1.1.13 root 91: /* of void, depending on whether at least one MFP interrupt was */ 92: /* allowed or not. */ 1.1.1.14 root 93: /* 2009/03/28 [NP] Handle bit 3 of AER for timer B (fix Seven Gates Of Jambala). */ 1.1.1.16 root 94: /* 2010/07/26 [NP] In MFP_StartTimer_AB, when ctrl reg is in pulse width mode, */ 95: /* clear bit 3 to emulate it as in delay mode. This is not */ 1.1.1.18! root 96: /* completely correct as we should also emulate GPIO 3/4, but it */ 1.1.1.16 root 97: /* helps running some programs (fix the game Erik). */ 1.1.1.18! root 98: /* 2013/02/24 [NP] - In MFP_CheckPendingInterrupts, don't check all the MFP ints, */ ! 99: /* stop as soon as the highest interrupt is found (simultaneous */ ! 100: /* interrupts could be processed during the same cycle and were */ ! 101: /* stacked/executed in the reverse order, from lowest to highest */ ! 102: /* priority, which was wrong). */ ! 103: /* - Use MFP_ProcessIRQ to separate the MFP's IRQ signal handling */ ! 104: /* and the exception processing at the CPU level. */ ! 105: /* 2013/03/01 [NP] When MFP_IRQ goes from 0 to 1, the resulting signal is visible */ ! 106: /* to the CPU only 4 cycles later (fix Audio Artistic Demo by */ ! 107: /* Big Alec and the games Super Hang On, Super Monaco GP, Bolo). */ ! 108: /* 2013/03/10 [NP] Improve the MFP_IRQ 4 cycle delay by taking into account the */ ! 109: /* time at which the timer expired during the CPU instruction */ ! 110: /* (fix Reset part in Decade Demo, High Fidelity Dreams by Aura). */ ! 111: /* 2013/03/14 [NP] When writing to the MFP's registers, take the write cycles into */ ! 112: /* account when updating MFP_IRQ_Time (properly fix Super Hang On).*/ ! 113: /* 2013/04/11 [NP] Handle the IACK cycles, interrupts can change during the first */ ! 114: /* 12 cycles of an MFP exception (fix Anomaly Demo Menu by MJJ Prod*/ ! 115: /* and sample intro in the game The Final Conflict). */ ! 116: /* 2013/04/21 [NP] Handle the case where several MFP interrupts happen during the */ ! 117: /* same CPU instruction but at different sub-cycles. We must take */ ! 118: /* into account only the oldest interrupts to choose the highest */ ! 119: /* one (fix Fuzion CD Menus 77, 78, 84). */ 1.1.1.11 root 120: 1.1.1.12 root 121: 1.1.1.13 root 122: const char MFP_fileid[] = "Hatari mfp.c : " __DATE__ " " __TIME__; 1.1 root 123: 124: #include "main.h" 1.1.1.8 root 125: #include "configuration.h" 1.1.1.9 root 126: #include "dmaSnd.h" 1.1.1.15 root 127: #include "crossbar.h" 1.1 root 128: #include "fdc.h" 129: #include "ikbd.h" 1.1.1.15 root 130: #include "cycInt.h" 1.1.1.8 root 131: #include "ioMem.h" 1.1.1.9 root 132: #include "joy.h" 1.1 root 133: #include "m68000.h" 134: #include "memorySnapShot.h" 135: #include "mfp.h" 136: #include "psg.h" 1.1.1.8 root 137: #include "rs232.h" 1.1 root 138: #include "sound.h" 1.1.1.12 root 139: #include "stMemory.h" 1.1.1.8 root 140: #include "tos.h" 1.1.1.13 root 141: #include "vdi.h" 1.1.1.16 root 142: #include "screen.h" 1.1 root 143: #include "video.h" 1.1.1.3 root 144: 1.1 root 145: 146: /* 147: MFP interrupt channel circuit:- 148: 149: EdgeRegister EnableRegister MaskRegister SBit 150: | | | | 151: | | | | ------------------------ 152: | | ------------------------ ---\ |---\ | | 153: | o--\ | | AND---o----------------AND---| S InterruptInService | 154: ---\ | AND---| S InterruptPending O |-------/ | |---/ | | 155: XOR----------)--/ | R | | | ------------------------ 156: Input -----/ | ------------------------ | | 157: | | InterruptRequest | 158: NOT OR | 159: | | | | 160: -------------------- --------------------------------------o--- PassVector 161: */ 162: 1.1.1.7 root 163: 1.1.1.18! root 164: /* ! 165: Emulation Note : ! 166: - MFP emulation doesn't run in parallel with the CPU emulation as it would take too much resources. ! 167: Instead, MFP emulation is called each time a CPU instruction is completely processed. ! 168: The drawback is that several MFP interrupts can happen during a single CPU instruction (especially ! 169: for long ones like MOVEM or DIV). In that case, we should not choose the highest priority interrupt ! 170: among all the interrupts, but we should keep only the interrupts that chronologically happened first ! 171: during this CPU instruction (and ignore the other interrupts' requests for this CPU instruction). ! 172: - When the MFP's main IRQ signal goes from 0 to 1, the signal is not immediatly visible to the CPU, but only ! 173: 4 cycles later. This 4 cycle delay should be taken into account, depending at what time the signal ! 174: went to 1 in the corresponding CPU instruction (the 4 cycle delay can be "included" in the CPU instruction ! 175: in some cases) ! 176: - When an interrupt happens in the MFP, an exception will be started in the CPU. Then after 12 cycles an IACK ! 177: sequence will be started by the CPU to request the interrupt vector from the MFP. During those 12 cycles, ! 178: it is possible that a new higher priority MFP interrupt happens and in that case we must replace the MFP ! 179: vector number that was initially computed at the start of the exception with the new one. ! 180: This is also after the IACK sequence that in service / pending bits must be handled for this MFP's interrupt. ! 181: */ ! 182: 1.1.1.7 root 183: /*-----------------------------------------------------------------------*/ 1.1 root 184: 1.1.1.2 root 185: /* MFP Registers */ 1.1.1.9 root 186: Uint8 MFP_GPIP; /* General Purpose Pins */ 1.1.1.11 root 187: Uint8 MFP_VR; /* Vector Register 0xfffa17 */ 1.1.1.9 root 188: Uint8 MFP_IERA,MFP_IERB; /* Interrupt Enable Registers A,B 0xfffa07,0xfffa09 */ 189: Uint8 MFP_IPRA,MFP_IPRB; /* Interrupt Pending Registers A,B 0xfffa0b,0xfffa0d */ 1.1.1.11 root 190: Uint8 MFP_TACR,MFP_TBCR; /* Timer A,B Control Registers */ 1.1.1.10 root 191: 1.1.1.11 root 192: static Uint8 MFP_TCDCR; /* C+D Control Registers */ 1.1.1.10 root 193: static Uint8 MFP_AER,MFP_DDR; /* Active Edge Register, Data Direction Register */ 194: static Uint8 MFP_ISRA,MFP_ISRB; /* Interrupt In-Service Registers A,B 0xfffa0f,0xfffa11 */ 195: static Uint8 MFP_IMRA,MFP_IMRB; /* Interrupt Mask Registers A,B 0xfffa13,0xfffa15 */ 196: static Uint8 MFP_TADR,MFP_TBDR; /* Timer A,B Data Registers */ 197: static Uint8 MFP_TCDR,MFP_TDDR; /* Timer C,D Data Registers */ 198: static Uint8 MFP_TA_MAINCOUNTER; /* Timer A Main Counter (internal to MFP) */ 199: static Uint8 MFP_TB_MAINCOUNTER; /* Timer B Main Counter */ 200: static Uint8 MFP_TC_MAINCOUNTER; /* Timer C Main Counter (these are temp's, set when read as) */ 201: static Uint8 MFP_TD_MAINCOUNTER; /* Timer D Main Counter (as done via interrupts) */ 1.1 root 202: 203: /* CPU clock cycle counts for each timer */ 1.1.1.7 root 204: static int TimerAClockCycles=0; 205: static int TimerBClockCycles=0; 206: static int TimerCClockCycles=0; 207: static int TimerDClockCycles=0; 208: 1.1.1.11 root 209: /* If a timer is stopped then restarted later without writing to the data register, */ 210: /* we must resume the timer from where we left in the interrupts table, instead of */ 211: /* computing a new number of clock cycles to restart the interrupt. */ 1.1.1.14 root 212: static bool TimerACanResume = false; 213: static bool TimerBCanResume = false; 214: static bool TimerCCanResume = false; 215: static bool TimerDCanResume = false; 1.1.1.11 root 216: 1.1.1.14 root 217: bool bAppliedTimerDPatch; /* true if the Timer-D patch has been applied */ 1.1.1.9 root 218: static int nTimerDFakeValue; /* Faked Timer-D data register for the Timer-D patch */ 1.1.1.8 root 219: 1.1.1.11 root 220: static int PendingCyclesOver = 0; /* >= 0 value, used to "loop" a timer when data counter reaches 0 */ 1.1 root 221: 1.1.1.18! root 222: ! 223: #define MFP_IRQ_DELAY_TO_CPU 4 /* When MFP_IRQ is set, it takes 4 CPU cycles before it's visible to the CPU */ ! 224: ! 225: static int MFP_Current_Interrupt = -1; ! 226: static Uint8 MFP_IRQ = 0; ! 227: static Uint64 MFP_IRQ_Time = 0; ! 228: bool MFP_UpdateNeeded = false; /* When set to true, main CPU loop should call MFP_UpdateIRQ() */ ! 229: static Uint64 MFP_Pending_Time_Min; /* Clock value of the oldest pending int since last MFP_UpdateIRQ() */ ! 230: static Uint64 MFP_Pending_Time[ MFP_INT_MAX+1 ]; /* Clock value when pending is set to 1 for each non-masked int */ ! 231: 1.1.1.11 root 232: static const Uint16 MFPDiv[] = 233: { 234: 0, 235: 4, 236: 10, 237: 16, 238: 50, 239: 64, 240: 100, 241: 200 1.1 root 242: }; 243: 1.1.1.11 root 244: /* Convert data/ctrl register to a number of mfp cycles */ 245: #define MFP_REG_TO_CYCLES(data,ctrl) ( data * MFPDiv[ ctrl&0x7 ] ) 246: /* Determine the data register corresponding to a number of mfp cycles/ctrl register */ 247: /* (we round to the closest higher integer) */ 248: #define MFP_CYCLE_TO_REG(cyc,ctrl) ( ( cyc + MFPDiv[ ctrl&0x7 ] - 1 ) / MFPDiv[ ctrl&0x7 ] ) 249: //#define MFP_CYCLE_TO_REG(cyc,ctrl) ( cyc / MFPDiv[ ctrl&0x7 ] ) 250: 1.1 root 251: 1.1.1.18! root 252: ! 253: ! 254: /*--------------------------------------------------------------*/ ! 255: /* Local functions prototypes */ ! 256: /*--------------------------------------------------------------*/ ! 257: ! 258: static Uint8 MFP_ConvertIntNumber ( int Interrupt , Uint8 **pMFP_IER , Uint8 **pMFP_IPR , Uint8 **pMFP_ISR , Uint8 **pMFP_IMR ); ! 259: static void MFP_Exception ( int Interrupt ); ! 260: static bool MFP_InterruptRequest ( int Int , Uint8 Bit , Uint8 IPRx , Uint8 IMRx , Uint8 PriorityMaskA , Uint8 PriorityMaskB ); ! 261: static int MFP_CheckPendingInterrupts ( void ); ! 262: ! 263: ! 264: 1.1.1.2 root 265: /*-----------------------------------------------------------------------*/ 1.1.1.11 root 266: /** 267: * Reset all MFP variables and start interrupts on their way! 268: */ 1.1 root 269: void MFP_Reset(void) 270: { 1.1.1.18! root 271: int i; ! 272: 1.1.1.11 root 273: /* Reset MFP internal variables */ 1.1.1.7 root 274: 1.1.1.14 root 275: bAppliedTimerDPatch = false; 1.1.1.7 root 276: 1.1.1.11 root 277: MFP_GPIP = 0xff; 278: MFP_AER = MFP_DDR = 0; 279: MFP_IERA = MFP_IERB = 0; 280: MFP_IPRA = MFP_IPRB = 0; 281: MFP_ISRA = MFP_ISRB = 0; 282: MFP_IMRA = MFP_IMRB = 0; 283: MFP_VR = 0; 284: MFP_TACR = MFP_TBCR = MFP_TCDCR = 0; 285: MFP_TADR = MFP_TBDR = 0; 286: MFP_TCDR = MFP_TDDR = 0; 287: MFP_TA_MAINCOUNTER = MFP_TB_MAINCOUNTER = 0; 288: MFP_TC_MAINCOUNTER = MFP_TD_MAINCOUNTER = 0; 1.1 root 289: 1.1.1.11 root 290: /* Clear counters */ 291: TimerAClockCycles = TimerBClockCycles = 0; 292: TimerCClockCycles = TimerDClockCycles = 0; 1.1.1.18! root 293: ! 294: /* Clear IRQ */ ! 295: MFP_Current_Interrupt = -1; ! 296: MFP_IRQ = 0; ! 297: MFP_IRQ_Time = 0; ! 298: MFP_UpdateNeeded = false; ! 299: MFP_Pending_Time_Min = UINT64_MAX; ! 300: for ( i=0 ; i<=MFP_INT_MAX ; i++ ) ! 301: MFP_Pending_Time[ i ] = UINT64_MAX; 1.1 root 302: } 303: 1.1.1.2 root 304: 305: /*-----------------------------------------------------------------------*/ 1.1.1.11 root 306: /** 307: * Save/Restore snapshot of local variables('MemorySnapShot_Store' handles type) 308: */ 1.1.1.12 root 309: void MFP_MemorySnapShot_Capture(bool bSave) 1.1 root 310: { 1.1.1.11 root 311: /* Save/Restore details */ 312: MemorySnapShot_Store(&MFP_GPIP, sizeof(MFP_GPIP)); 313: MemorySnapShot_Store(&MFP_AER, sizeof(MFP_AER)); 314: MemorySnapShot_Store(&MFP_DDR, sizeof(MFP_DDR)); 315: MemorySnapShot_Store(&MFP_IERA, sizeof(MFP_IERA)); 316: MemorySnapShot_Store(&MFP_IERB, sizeof(MFP_IERB)); 317: MemorySnapShot_Store(&MFP_IPRA, sizeof(MFP_IPRA)); 318: MemorySnapShot_Store(&MFP_IPRB, sizeof(MFP_IPRB)); 319: MemorySnapShot_Store(&MFP_ISRA, sizeof(MFP_ISRA)); 320: MemorySnapShot_Store(&MFP_ISRB, sizeof(MFP_ISRB)); 321: MemorySnapShot_Store(&MFP_IMRA, sizeof(MFP_IMRA)); 322: MemorySnapShot_Store(&MFP_IMRB, sizeof(MFP_IMRB)); 323: MemorySnapShot_Store(&MFP_VR, sizeof(MFP_VR)); 324: MemorySnapShot_Store(&MFP_TACR, sizeof(MFP_TACR)); 325: MemorySnapShot_Store(&MFP_TBCR, sizeof(MFP_TBCR)); 326: MemorySnapShot_Store(&MFP_TCDCR, sizeof(MFP_TCDCR)); 327: MemorySnapShot_Store(&MFP_TADR, sizeof(MFP_TADR)); 328: MemorySnapShot_Store(&MFP_TBDR, sizeof(MFP_TBDR)); 329: MemorySnapShot_Store(&MFP_TCDR, sizeof(MFP_TCDR)); 330: MemorySnapShot_Store(&MFP_TDDR, sizeof(MFP_TDDR)); 331: MemorySnapShot_Store(&MFP_TA_MAINCOUNTER, sizeof(MFP_TA_MAINCOUNTER)); 332: MemorySnapShot_Store(&MFP_TB_MAINCOUNTER, sizeof(MFP_TB_MAINCOUNTER)); 333: MemorySnapShot_Store(&MFP_TC_MAINCOUNTER, sizeof(MFP_TC_MAINCOUNTER)); 334: MemorySnapShot_Store(&MFP_TD_MAINCOUNTER, sizeof(MFP_TD_MAINCOUNTER)); 335: MemorySnapShot_Store(&TimerAClockCycles, sizeof(TimerAClockCycles)); 336: MemorySnapShot_Store(&TimerBClockCycles, sizeof(TimerBClockCycles)); 337: MemorySnapShot_Store(&TimerCClockCycles, sizeof(TimerCClockCycles)); 338: MemorySnapShot_Store(&TimerDClockCycles, sizeof(TimerDClockCycles)); 339: MemorySnapShot_Store(&TimerACanResume, sizeof(TimerACanResume)); 340: MemorySnapShot_Store(&TimerBCanResume, sizeof(TimerBCanResume)); 341: MemorySnapShot_Store(&TimerCCanResume, sizeof(TimerCCanResume)); 342: MemorySnapShot_Store(&TimerDCanResume, sizeof(TimerDCanResume)); 1.1.1.18! root 343: MemorySnapShot_Store(&MFP_Current_Interrupt, sizeof(MFP_Current_Interrupt)); ! 344: MemorySnapShot_Store(&MFP_IRQ, sizeof(MFP_IRQ)); ! 345: MemorySnapShot_Store(&MFP_IRQ_Time, sizeof(MFP_IRQ_Time)); ! 346: MemorySnapShot_Store(&MFP_UpdateNeeded, sizeof(MFP_UpdateNeeded)); ! 347: MemorySnapShot_Store(&MFP_Pending_Time_Min, sizeof(MFP_Pending_Time_Min)); ! 348: MemorySnapShot_Store(&MFP_Pending_Time, sizeof(MFP_Pending_Time)); ! 349: } ! 350: ! 351: ! 352: ! 353: /*-----------------------------------------------------------------------*/ ! 354: /** ! 355: * Given an MFP interrupt number, return a pointer to the corresponding ! 356: * registers handling this interrupt, as well as the binary value ! 357: * to set/clear these registers. ! 358: * If an input pointer is NULL, we don't return the corresponding register. ! 359: */ ! 360: static Uint8 MFP_ConvertIntNumber ( int Interrupt , Uint8 **pMFP_IER , Uint8 **pMFP_IPR , Uint8 **pMFP_ISR , Uint8 **pMFP_IMR ) ! 361: { ! 362: Uint8 Bit; ! 363: ! 364: if ( Interrupt > 7 ) ! 365: { ! 366: Bit = 1 << ( Interrupt - 8 ); ! 367: if ( pMFP_IER ) *pMFP_IER = &MFP_IERA; ! 368: if ( pMFP_IPR ) *pMFP_IPR = &MFP_IPRA; ! 369: if ( pMFP_ISR ) *pMFP_ISR = &MFP_ISRA; ! 370: if ( pMFP_IMR ) *pMFP_IMR = &MFP_IMRA; ! 371: } ! 372: else ! 373: { ! 374: Bit = 1 << Interrupt; ! 375: if ( pMFP_IER ) *pMFP_IER = &MFP_IERB; ! 376: if ( pMFP_IPR ) *pMFP_IPR = &MFP_IPRB; ! 377: if ( pMFP_ISR ) *pMFP_ISR = &MFP_ISRB; ! 378: if ( pMFP_IMR ) *pMFP_IMR = &MFP_IMRB; ! 379: } ! 380: ! 381: return Bit; 1.1 root 382: } 383: 1.1.1.2 root 384: 385: /*-----------------------------------------------------------------------*/ 1.1.1.11 root 386: /** 1.1.1.18! root 387: * Call the MFP exception associated to the current MFP interrupt 0-15. ! 388: * When the MFP sets its IRQ signal, it will put the interrupt vector number ! 389: * on the data bus ; the 68000 will read it during the IACK cycle ! 390: * and multiply it by 4 to get the address of the exception handler. ! 391: * The upper 4 bits of the vector number are stored in the VR register 0xfffa17 ! 392: * (default value is 0x40, which gives exceptions' handlers located at 0x100 in RAM) 1.1.1.11 root 393: */ 1.1.1.18! root 394: static void MFP_Exception ( int Interrupt ) 1.1 root 395: { 1.1.1.18! root 396: unsigned int VecNr; 1.1 root 397: 1.1.1.18! root 398: VecNr = ( MFP_VR & 0xf0 ) + Interrupt; 1.1.1.11 root 399: 1.1.1.14 root 400: if (LOG_TRACE_LEVEL(TRACE_MFP_EXCEPTION)) 1.1.1.11 root 401: { 1.1.1.14 root 402: int FrameCycles, HblCounterVideo, LineCycles; 403: Video_GetPosition ( &FrameCycles , &HblCounterVideo , &LineCycles ); 404: LOG_TRACE_PRINT("mfp excep int=%d vec=0x%x new_pc=0x%x video_cyc=%d %d@%d\n" , 1.1.1.18! root 405: Interrupt, VecNr * 4, STMemory_ReadLong ( VecNr * 4 ), FrameCycles, LineCycles, HblCounterVideo ); 1.1.1.11 root 406: } 407: 1.1.1.18! root 408: M68000_Exception(VecNr * 4, M68000_EXC_SRC_INT_MFP); 1.1 root 409: } 410: 1.1.1.2 root 411: 1.1.1.18! root 412: ! 413: 1.1.1.2 root 414: /*-----------------------------------------------------------------------*/ 1.1.1.11 root 415: /** 1.1.1.18! root 416: * Return the vector number associated to the current MFP interrupt. ! 417: * MFP_ProcessIACK is called 12 cycles after the start of the 68000 exception. ! 418: * We must call MFP_UpdateIRQ just before the IACK cycles to update ! 419: * MFP_Current_Interrupt in case a higher MFP interrupt happened ! 420: * or pending bit was set twice for the same interrupt during those 12 cycles (rare case) 1.1.1.11 root 421: */ 1.1.1.18! root 422: int MFP_ProcessIACK ( int OldVecNr ) 1.1.1.10 root 423: { 1.1.1.18! root 424: Uint8 *pPendingReg; ! 425: Uint8 *pInServiceReg; ! 426: Uint8 Bit; ! 427: int NewVecNr; ! 428: ! 429: ! 430: /* Check if MFP interrupt vector number changed before IACK */ ! 431: MFP_UpdateIRQ ( CyclesGlobalClockCounter ); ! 432: ! 433: NewVecNr = ( MFP_VR & 0xf0 ) + MFP_Current_Interrupt; ! 434: ! 435: /* Print traces if VecNr changed just before IACK */ ! 436: if ( LOG_TRACE_LEVEL(TRACE_MFP_EXCEPTION) && ( OldVecNr != NewVecNr ) ) 1.1.1.11 root 437: { 1.1.1.18! root 438: int FrameCycles, HblCounterVideo, LineCycles; ! 439: Video_GetPosition ( &FrameCycles , &HblCounterVideo , &LineCycles ); ! 440: LOG_TRACE_PRINT("mfp iack change old_vec=0x%x new_vec=0x%x new_pc=0x%x video_cyc=%d %d@%d\n" , ! 441: OldVecNr * 4, NewVecNr * 4, STMemory_ReadLong ( NewVecNr * 4 ) , FrameCycles, LineCycles, HblCounterVideo ); 1.1.1.11 root 442: } 1.1.1.18! root 443: ! 444: Bit = MFP_ConvertIntNumber ( MFP_Current_Interrupt , NULL , &pPendingReg , &pInServiceReg , NULL ); ! 445: ! 446: *pPendingReg &= ~Bit; /* Clear pending bit */ ! 447: ! 448: /* Are we in 'auto' interrupt or 'manual' ? */ ! 449: if ( MFP_VR & 0x08 ) /* Software End-of-Interrupt (SEI) */ ! 450: *pInServiceReg |= Bit; /* Set interrupt in service register */ 1.1.1.11 root 451: else 1.1.1.18! root 452: *pInServiceReg &= ~Bit; /* Clear interrupt in service register */ ! 453: ! 454: MFP_UpdateIRQ ( CyclesGlobalClockCounter ); ! 455: ! 456: return NewVecNr; /* Vector number */ 1.1.1.10 root 457: } 458: 459: 1.1.1.18! root 460: ! 461: 1.1.1.10 root 462: /*-----------------------------------------------------------------------*/ 1.1.1.11 root 463: /** 1.1.1.18! root 464: * This function is called from the CPU emulation part when SPCFLAG_MFP is set. ! 465: * If the MFP's IRQ signal is set, we check that SR allows a level 6 interrupt, ! 466: * and if so, we call MFP_Exception. ! 467: * If SR doesn't allow an MFP interrupt, MFP's pending requests will be ! 468: * processed later when SR allows it. ! 469: * ! 470: * Important timing note : when the MFP's IRQ signal is set, it's visible to ! 471: * the CPU only 4 cycles later. Depending if the signal happens during a CPU ! 472: * instruction or just before processing a new instruction, this delay will ! 473: * not always be necessary. ! 474: * ! 475: * Instead of using CycInt_AddRelativeInterrupt to simulate this 4 cycles delay, ! 476: * we use MFP_IRQ_Time to delay the exception processing until 4 cycles have ! 477: * passed. 1.1.1.11 root 478: */ 1.1.1.18! root 479: bool MFP_ProcessIRQ ( void ) 1.1 root 480: { 1.1.1.18! root 481: //fprintf ( stderr , "process irq %d %lld %lld - ipr %x %x imr %x %x isr %x %x\n" , MFP_IRQ , CyclesGlobalClockCounter , MFP_IRQ_Time , MFP_IPRA , MFP_IPRB , MFP_IMRA , MFP_IMRB , MFP_ISRA , MFP_ISRB ); ! 482: ! 483: if ( MFP_IRQ == 1 ) 1.1.1.11 root 484: { 1.1.1.18! root 485: if ( CyclesGlobalClockCounter - MFP_IRQ_Time < MFP_IRQ_DELAY_TO_CPU ) /* Is it time to trigger the exception ? */ 1.1.1.11 root 486: { 1.1.1.18! root 487: return false; /* For now, return without calling an exception (and try again later) */ ! 488: } 1.1.1.11 root 489: 1.1.1.18! root 490: if (regs.intmask < 6) ! 491: { ! 492: /* The exception is possible ; pending / in service bits will be handled in MFP_ProcessIACK() */ ! 493: MFP_Exception ( MFP_Current_Interrupt ); ! 494: return true; 1.1.1.11 root 495: } 496: } 1.1 root 497: 1.1.1.14 root 498: return false; 1.1 root 499: } 500: 1.1.1.2 root 501: 1.1.1.18! root 502: 1.1.1.2 root 503: /*-----------------------------------------------------------------------*/ 1.1.1.11 root 504: /** 1.1.1.18! root 505: * Update the MFP IRQ signal when IERx, IPRx, ISRx or IMRx are modified. ! 506: * We set the special flag SPCFLAG_MFP accordingly (to say if an MFP interrupt ! 507: * is to be processed) so we only have one compare to call MFP_ProcessIRQ ! 508: * during the CPU's decode instruction loop. ! 509: * If MFP_IRQ goes from 0 to 1, we update MFP_IRQ_Time to correctly emulate ! 510: * the 4 cycle delay before MFP_IRQ is visible to the CPU. ! 511: * ! 512: * When MFP_UpdateIRQ() is called after writing to an MFP's register, Event_Time ! 513: * will be the time of the write cycle. ! 514: * When MFP_UpdateIRQ is called from the main CPU loop after processing the ! 515: * internal timers, Event_Time will be 0 and we must use MFP_Pending_Time[ NewInt ]. ! 516: * This way, MFP_IRQ_Time should always be correct to check the delay in MFP_ProcessIRQ(). 1.1.1.11 root 517: */ 1.1.1.18! root 518: void MFP_UpdateIRQ ( Uint64 Event_Time ) 1.1 root 519: { 1.1.1.18! root 520: int NewInt; ! 521: ! 522: //fprintf ( stderr , "updirq0 %d - ipr %x %x imr %x %x isr %x %x\n" , MFP_IRQ , MFP_IPRA , MFP_IPRB , MFP_IMRA , MFP_IMRB , MFP_ISRA , MFP_ISRB ); ! 523: ! 524: if ( ( MFP_IPRA & MFP_IMRA ) | ( MFP_IPRB & MFP_IMRB ) ) ! 525: { ! 526: NewInt = MFP_CheckPendingInterrupts (); ! 527: ! 528: if ( NewInt >= 0 ) ! 529: { ! 530: if ( MFP_IRQ == 0 ) /* MFP IRQ goes from 0 to 1 */ ! 531: { ! 532: if ( Event_Time != 0 ) ! 533: MFP_IRQ_Time = Event_Time; ! 534: else ! 535: MFP_IRQ_Time = MFP_Pending_Time[ NewInt ]; ! 536: } 1.1.1.13 root 537: 1.1.1.18! root 538: MFP_IRQ = 1; ! 539: MFP_Current_Interrupt = NewInt; ! 540: } ! 541: else ! 542: MFP_IRQ = 0; /* Pending interrupts are blocked by in-service interrupts */ ! 543: } ! 544: else 1.1.1.15 root 545: { 1.1.1.18! root 546: MFP_IRQ = 0; 1.1.1.15 root 547: } 1.1.1.13 root 548: 1.1.1.18! root 549: //fprintf ( stderr , "updirq1 %d - ipr %x %x imr %x %x isr %x %x\n" , MFP_IRQ , MFP_IPRA , MFP_IPRB , MFP_IMRA , MFP_IMRB , MFP_ISRA , MFP_ISRB ); ! 550: if ( MFP_IRQ == 1 ) 1.1.1.11 root 551: { 1.1.1.18! root 552: M68000_SetSpecial(SPCFLAG_MFP); 1.1.1.11 root 553: } 1.1.1.18! root 554: else ! 555: M68000_UnsetSpecial(SPCFLAG_MFP); 1.1 root 556: 1.1.1.18! root 557: /* Update IRQ is done, reset Time_Min and UpdateNeeded */ ! 558: MFP_Pending_Time_Min = UINT64_MAX; ! 559: MFP_UpdateNeeded = false; ! 560: } 1.1.1.12 root 561: 1.1.1.13 root 562: 1.1.1.18! root 563: /*-----------------------------------------------------------------------*/ ! 564: /** ! 565: * Test if interrupt 'Bit' is set in pending and mask register. ! 566: * Also check that no higher priority interrupt is in service. ! 567: * Depending on the interrupt, we check either IPRA/IMRA or IPRB/IMRB ! 568: * @return true if the MFP interrupt request is allowed ! 569: */ ! 570: static bool MFP_InterruptRequest ( int Int , Uint8 Bit , Uint8 IPRx , Uint8 IMRx , Uint8 PriorityMaskA , Uint8 PriorityMaskB ) ! 571: { ! 572: //fprintf ( stderr , "mfp int req %d %x %x %X %x %x\n" , Int , Bit , IPRx , IMRx , PriorityMaskA , PriorityMaskB ); 1.1.1.9 root 573: 1.1.1.18! root 574: if ( ( IPRx & IMRx & Bit ) /* Interrupt is pending and not masked */ ! 575: && ( MFP_Pending_Time[ Int ] <= MFP_Pending_Time_Min ) ) /* Process pending requests in chronological time */ ! 576: { ! 577: /* Are any higher priority interrupts in service ? */ ! 578: if ( ( ( MFP_ISRA & PriorityMaskA ) == 0 ) && ( ( MFP_ISRB & PriorityMaskB ) == 0 ) ) ! 579: return true; /* No higher int in service */ ! 580: } 1.1.1.2 root 581: 1.1.1.18! root 582: return false; ! 583: } 1.1.1.7 root 584: 585: 1.1.1.18! root 586: /*-----------------------------------------------------------------------*/ ! 587: /** ! 588: * Check if any MFP interrupts can be serviced. ! 589: * @return MFP interrupt number for the highest interrupt allowed, else return -1. ! 590: */ ! 591: static int MFP_CheckPendingInterrupts ( void ) ! 592: { ! 593: if ( MFP_InterruptRequest ( MFP_INT_GPIP7 , MFP_GPIP7_BIT, MFP_IPRA, MFP_IMRA, 0x80, 0x00 ) ) /* Check MFP GPIP7 interrupt (bit 7) */ ! 594: return MFP_INT_GPIP7; ! 595: ! 596: if ( MFP_InterruptRequest ( MFP_INT_TIMER_A , MFP_TIMER_A_BIT, MFP_IPRA, MFP_IMRA, 0xe0, 0x00 ) ) /* Check Timer A (bit 5) */ ! 597: return MFP_INT_TIMER_A; ! 598: ! 599: if ( MFP_InterruptRequest ( MFP_INT_RCV_BUF_FULL , MFP_RCV_BUF_FULL_BIT, MFP_IPRA, MFP_IMRA, 0xf0, 0x00 ) ) /* Check Receive buffer full (bit 4) */ ! 600: return MFP_INT_RCV_BUF_FULL; 1.1.1.7 root 601: 1.1.1.18! root 602: if ( MFP_InterruptRequest ( MFP_INT_TRN_BUF_EMPTY , MFP_TRN_BUF_EMPTY_BIT, MFP_IPRA, MFP_IMRA, 0xfc, 0x00 ) ) /* Check transmit buffer empty (bit 2) */ ! 603: return MFP_INT_TRN_BUF_EMPTY; 1.1.1.12 root 604: 1.1.1.18! root 605: if ( MFP_InterruptRequest ( MFP_INT_TIMER_B , MFP_TIMER_B_BIT, MFP_IPRA, MFP_IMRA, 0xff, 0x00 ) ) /* Check Timer B (bit 0) */ ! 606: return MFP_INT_TIMER_B; 1.1.1.7 root 607: 1.1.1.18! root 608: if ( MFP_InterruptRequest ( MFP_INT_GPIP5 , MFP_FDCHDC_BIT, MFP_IPRB, MFP_IMRB, 0xff, 0x80 ) ) /* Check FDC (bit 7) */ ! 609: return MFP_INT_GPIP5; 1.1 root 610: 1.1.1.18! root 611: if ( MFP_InterruptRequest ( MFP_INT_ACIA , MFP_ACIA_BIT, MFP_IPRB, MFP_IMRB, 0xff, 0xc0 ) ) /* Check ACIA (Keyboard or MIDI) (bit 6) */ ! 612: return MFP_INT_ACIA; 1.1 root 613: 1.1.1.18! root 614: if ( MFP_InterruptRequest ( MFP_INT_TIMER_C , MFP_TIMER_C_BIT, MFP_IPRB, MFP_IMRB, 0xff, 0xe0 ) ) /* Check Timer C (bit 5) */ ! 615: return MFP_INT_TIMER_C; 1.1.1.12 root 616: 1.1.1.18! root 617: if ( MFP_InterruptRequest ( MFP_INT_TIMER_D , MFP_TIMER_D_BIT, MFP_IPRB, MFP_IMRB, 0xff, 0xf0 ) ) /* Check Timer D (bit 4) */ ! 618: return MFP_INT_TIMER_D; 1.1.1.12 root 619: 1.1.1.18! root 620: if ( MFP_InterruptRequest ( MFP_INT_GPU_DONE , MFP_GPU_DONE_BIT, MFP_IPRB, MFP_IMRB, 0xff, 0xf8 ) ) /* Check GPU done (bit 3) */ ! 621: return MFP_INT_GPU_DONE; 1.1.1.12 root 622: 1.1.1.18! root 623: if ( MFP_InterruptRequest ( MFP_INT_GPIP1 , MFP_GPIP1_BIT, MFP_IPRB, MFP_IMRB, 0xff, 0xfe ) ) /* Check (Falcon) Centronics ACK / (ST) RS232 DCD (bit 1) */ ! 624: return MFP_INT_GPIP1; 1.1.1.12 root 625: 1.1.1.18! root 626: if ( MFP_InterruptRequest ( MFP_INT_GPIP0 , MFP_GPIP0_BIT, MFP_IPRB, MFP_IMRB, 0xff, 0xff ) ) /* Check Centronics BUSY (bit 0) */ ! 627: return MFP_INT_GPIP0; ! 628: ! 629: return -1; /* No pending interrupt */ 1.1 root 630: } 631: 1.1.1.2 root 632: 633: /*-----------------------------------------------------------------------*/ 1.1.1.11 root 634: /** 1.1.1.18! root 635: * If interrupt channel is active, set pending bit so it can be serviced ! 636: * later. ! 637: * As internal timers are processed after the current CPU instruction was ! 638: * emulated, we use Interrupt_Delayed_Cycles to compute the precise time ! 639: * at which the timer expired (it could be during the previous instruction). ! 640: * This allows to correctly handle the 4 cycle MFP_IRQ delay in MFP_ProcessIRQ(). ! 641: * ! 642: * As we can have several inputs during one CPU instruction, not necessarily ! 643: * sorted by Interrupt_Delayed_Cycles, we must call MFP_UpdateIRQ() only later ! 644: * in the main CPU loop, when all inputs were received, to choose the oldest ! 645: * input's event time. ! 646: */ ! 647: void MFP_InputOnChannel ( int Interrupt , int Interrupt_Delayed_Cycles ) ! 648: { ! 649: Uint8 *pEnableReg; ! 650: Uint8 *pPendingReg; ! 651: Uint8 *pMaskReg; ! 652: Uint8 Bit; ! 653: ! 654: //fprintf ( stderr , "mfp input %d delay %d clock %lld\n" , Interrupt , Interrupt_Delayed_Cycles , CyclesGlobalClockCounter ); ! 655: Bit = MFP_ConvertIntNumber ( Interrupt , &pEnableReg , &pPendingReg , NULL , &pMaskReg ); ! 656: ! 657: /* Input has occurred on MFP channel, set interrupt pending to request service when able */ ! 658: if ( *pEnableReg & Bit ) ! 659: { ! 660: /* Print traces if pending bits changed just before IACK */ ! 661: if ( LOG_TRACE_LEVEL(TRACE_MFP_EXCEPTION) && ( CPU_IACK == true ) ) ! 662: { ! 663: int FrameCycles, HblCounterVideo, LineCycles; ! 664: Video_GetPosition ( &FrameCycles , &HblCounterVideo , &LineCycles ); ! 665: if ( *pPendingReg & Bit ) ! 666: LOG_TRACE_PRINT("mfp input, pending set again during iack for int=%d, skip one interrupt video_cyc=%d %d@%d\n" , ! 667: Interrupt , FrameCycles, LineCycles, HblCounterVideo ); ! 668: else ! 669: LOG_TRACE_PRINT("mfp input, new pending set during iack for int=%d video_cyc=%d %d@%d\n" , ! 670: Interrupt , FrameCycles, LineCycles, HblCounterVideo ); ! 671: } ! 672: ! 673: /* Set pending bit and event's time */ ! 674: *pPendingReg |= Bit; ! 675: MFP_Pending_Time[ Interrupt ] = CyclesGlobalClockCounter - Interrupt_Delayed_Cycles; ! 676: ! 677: /* Store the time of the most ancient non-masked pending=1 event */ ! 678: if ( ( *pMaskReg & Bit ) && ( MFP_Pending_Time[ Interrupt ] < MFP_Pending_Time_Min ) ) ! 679: MFP_Pending_Time_Min = MFP_Pending_Time[ Interrupt ]; ! 680: } 1.1.1.11 root 681: else 1.1.1.18! root 682: *pPendingReg &= ~Bit; /* Clear bit */ ! 683: ! 684: MFP_UpdateNeeded = true; /* Tell main CPU loop to call MFP_UpdateIRQ() */ 1.1 root 685: } 686: 1.1.1.2 root 687: 688: /*-----------------------------------------------------------------------*/ 1.1.1.11 root 689: /** 690: * Generate Timer A Interrupt when in Event Count mode 691: */ 1.1 root 692: void MFP_TimerA_EventCount_Interrupt(void) 693: { 1.1.1.12 root 694: if (MFP_TA_MAINCOUNTER == 1) /* Timer expired? If so, generate interrupt */ 1.1.1.11 root 695: { 1.1.1.12 root 696: MFP_TA_MAINCOUNTER = MFP_TADR; /* Reload timer from data register */ 1.1 root 697: 1.1.1.11 root 698: /* Acknowledge in MFP circuit, pass bit,enable,pending */ 1.1.1.18! root 699: MFP_InputOnChannel ( MFP_INT_TIMER_A , 0 ); 1.1.1.11 root 700: } 701: else 1.1.1.12 root 702: { 703: MFP_TA_MAINCOUNTER--; /* Decrement timer main counter */ 704: /* As MFP_TA_MAINCOUNTER is Uint8, when we decrement MFP_TA_MAINCOUNTER=0 */ 705: /* we go to MFP_TA_MAINCOUNTER=255, which is the wanted behaviour because */ 706: /* data reg = 0 means 256 in fact. So, the next 2 lines are redundant. */ 707: /* if ( MFP_TA_MAINCOUNTER < 0 ) 708: MFP_TA_MAINCOUNTER = 255; 709: */ 710: } 1.1 root 711: } 712: 1.1.1.2 root 713: 714: /*-----------------------------------------------------------------------*/ 1.1.1.11 root 715: /** 716: * Generate Timer B Interrupt when in Event Count mode 717: */ 1.1.1.18! root 718: void MFP_TimerB_EventCount_Interrupt ( int Delayed_Cycles ) 1.1 root 719: { 1.1.1.18! root 720: LOG_TRACE(TRACE_VIDEO_HBL , "mfp/video timer B new event count %d, delay=%d\n" , MFP_TB_MAINCOUNTER-1 , Delayed_Cycles ); 1.1.1.14 root 721: 1.1.1.12 root 722: if (MFP_TB_MAINCOUNTER == 1) /* Timer expired? If so, generate interrupt */ 1.1.1.11 root 723: { 1.1.1.12 root 724: MFP_TB_MAINCOUNTER = MFP_TBDR; /* Reload timer from data register */ 1.1 root 725: 1.1.1.11 root 726: /* Acknowledge in MFP circuit, pass bit,enable,pending */ 1.1.1.18! root 727: MFP_InputOnChannel ( MFP_INT_TIMER_B , Delayed_Cycles ); 1.1.1.11 root 728: } 729: else 1.1.1.12 root 730: { 731: MFP_TB_MAINCOUNTER--; /* Decrement timer main counter */ 732: /* As MFP_TB_MAINCOUNTER is Uint8, when we decrement MFP_TB_MAINCOUNTER=0 */ 733: /* we go to MFP_TB_MAINCOUNTER=255, which is the wanted behaviour because */ 734: /* data reg = 0 means 256 in fact. So, the next 2 lines are redundant. */ 735: /* if ( MFP_TB_MAINCOUNTER < 0 ) 736: MFP_TB_MAINCOUNTER = 255; 737: */ 738: } 1.1 root 739: } 740: 1.1.1.2 root 741: 742: /*-----------------------------------------------------------------------*/ 1.1.1.11 root 743: /** 744: * Start Timer A or B - EventCount mode is done in HBL handler to time correctly 745: */ 1.1.1.14 root 746: static int MFP_StartTimer_AB(Uint8 TimerControl, Uint16 TimerData, interrupt_id Handler, 1.1.1.12 root 747: bool bFirstTimer, bool *pTimerCanResume) 1.1 root 748: { 1.1.1.11 root 749: int TimerClockCycles = 0; 750: 1.1.1.16 root 751: 752: /* When in pulse width mode, handle as in delay mode */ 1.1.1.18! root 753: /* (this is not completely correct, as we should also handle GPIO 3/4 in pulse mode) */ 1.1.1.16 root 754: if ( TimerControl > 8 ) 755: { 756: if (LOG_TRACE_LEVEL(TRACE_MFP_START)) 757: { 758: int FrameCycles, HblCounterVideo, LineCycles; 759: Video_GetPosition ( &FrameCycles , &HblCounterVideo , &LineCycles ); 760: LOG_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 pulse mode->delay mode\n", 761: Handler, TimerData, TimerControl, TimerClockCycles, PendingCyclesOver, 762: FrameCycles, LineCycles, HblCounterVideo, M68000_GetPC(), CurrentInstrCycles); 763: } 764: 765: TimerControl &= 0x07; /* clear bit 3, pulse width mode -> delay mode */ 766: } 767: 768: 1.1.1.11 root 769: /* Is timer in delay mode (ctrl = 0-7) ? */ 770: /* If we are in event-count mode (ctrl = 8) ignore this (done on HBL) */ 771: if (TimerControl <= 7) 772: { 773: /* Find number of CPU cycles for when timer is due (include preset 774: * and counter). As timer occurs very often we multiply by counter 775: * to speed up emulator */ 776: if (TimerData == 0) /* Data=0 is actually Data=256 */ 777: TimerData = 256; 778: TimerClockCycles = MFP_REG_TO_CYCLES ( TimerData, TimerControl ); 779: 1.1.1.14 root 780: if (LOG_TRACE_LEVEL(TRACE_MFP_START)) 1.1.1.11 root 781: { 1.1.1.14 root 782: int FrameCycles, HblCounterVideo, LineCycles; 783: Video_GetPosition ( &FrameCycles , &HblCounterVideo , &LineCycles ); 784: LOG_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", 785: Handler, TimerData, TimerControl, TimerClockCycles, PendingCyclesOver, 786: FrameCycles, LineCycles, HblCounterVideo, M68000_GetPC(), CurrentInstrCycles, 787: bFirstTimer?"true":"false", *pTimerCanResume?"true":"false"); 1.1.1.11 root 788: } 789: 790: /* And add to our internal interrupt list, if timer cycles is zero 791: * then timer is stopped */ 1.1.1.15 root 792: CycInt_RemovePendingInterrupt(Handler); 1.1.1.11 root 793: if (TimerClockCycles) 794: { 1.1.1.14 root 795: if ((*pTimerCanResume == true) && (bFirstTimer == true)) /* we can't resume if the timer is auto restarting after an interrupt */ 1.1.1.11 root 796: { 1.1.1.15 root 797: CycInt_ResumeStoppedInterrupt ( Handler ); 1.1.1.11 root 798: } 799: else 800: { 801: int AddCurCycles = INT_CONVERT_TO_INTERNAL ( CurrentInstrCycles + nWaitStateCycles - 4 , INT_CPU_CYCLE ); 802: 803: /* Start timer from now? If not continue timer using PendingCycleOver */ 804: if (bFirstTimer) 1.1.1.15 root 805: CycInt_AddRelativeInterruptWithOffset(TimerClockCycles, INT_MFP_CYCLE, Handler, AddCurCycles); 1.1.1.11 root 806: else 807: { 808: int TimerClockCyclesInternal = INT_CONVERT_TO_INTERNAL ( TimerClockCycles , INT_MFP_CYCLE ); 809: 810: /* In case we miss more than one int, we must correct the delay for the next one */ 811: if ( PendingCyclesOver > TimerClockCyclesInternal ) 812: PendingCyclesOver = PendingCyclesOver % TimerClockCyclesInternal; 813: 1.1.1.15 root 814: CycInt_AddRelativeInterruptWithOffset(TimerClockCycles, INT_MFP_CYCLE, Handler, -PendingCyclesOver); 1.1.1.11 root 815: } 1.1 root 816: 1.1.1.14 root 817: *pTimerCanResume = true; /* timer was set, resume is possible if stop/start it later */ 1.1.1.11 root 818: } 819: } 1.1.1.12 root 820: 821: else /* Ctrl was 0 -> timer is stopped */ 822: { 823: /* do nothing, only print some traces */ 1.1.1.14 root 824: if (LOG_TRACE_LEVEL(TRACE_MFP_START)) 1.1.1.12 root 825: { 1.1.1.14 root 826: int FrameCycles, HblCounterVideo, LineCycles; 827: Video_GetPosition ( &FrameCycles , &HblCounterVideo , &LineCycles ); 828: LOG_TRACE_PRINT("mfp stop 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", 829: Handler, TimerData, TimerControl, TimerClockCycles, PendingCyclesOver, 830: FrameCycles, LineCycles, HblCounterVideo, M68000_GetPC(), CurrentInstrCycles, 831: bFirstTimer?"true":"false", *pTimerCanResume?"true":"false"); 1.1.1.12 root 832: } 833: } 1.1.1.11 root 834: } 1.1.1.12 root 835: 1.1.1.16 root 836: 837: else if (TimerControl == 8 ) /* event count mode */ 1.1.1.11 root 838: { 839: /* Make sure no outstanding interrupts in list if channel is disabled */ 1.1.1.15 root 840: CycInt_RemovePendingInterrupt(Handler); 1.1 root 841: 1.1.1.14 root 842: if ( Handler == INTERRUPT_MFP_TIMERB ) /* we're starting timer B event count mode */ 843: { 844: /* Store start cycle for handling interrupt in video.c */ 845: TimerBEventCountCycleStart = Cycles_GetCounterOnWriteAccess(CYCLES_COUNTER_VIDEO); 846: } 1.1.1.12 root 847: 1.1.1.14 root 848: if (LOG_TRACE_LEVEL(TRACE_MFP_START)) 1.1.1.12 root 849: { 1.1.1.14 root 850: int FrameCycles, HblCounterVideo, LineCycles; 851: Video_GetPosition ( &FrameCycles , &HblCounterVideo , &LineCycles ); 852: LOG_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", 853: Handler, TimerData, TimerControl, TimerClockCycles, PendingCyclesOver, 854: FrameCycles, LineCycles, HblCounterVideo, M68000_GetPC(), CurrentInstrCycles, 855: bFirstTimer?"true":"false", *pTimerCanResume?"true":"false"); 1.1.1.12 root 856: } 857: } 858: 1.1.1.11 root 859: return TimerClockCycles; 1.1 root 860: } 861: 1.1.1.2 root 862: 863: /*-----------------------------------------------------------------------*/ 1.1.1.11 root 864: /** 865: * Start Timer C or D 866: */ 1.1.1.14 root 867: static int MFP_StartTimer_CD(Uint8 TimerControl, Uint16 TimerData, interrupt_id Handler, 1.1.1.12 root 868: bool bFirstTimer, bool *pTimerCanResume) 1.1 root 869: { 1.1.1.11 root 870: int TimerClockCycles = 0; 1.1 root 871: 1.1.1.11 root 872: /* Is timer in delay mode ? */ 873: if ((TimerControl&0x7) != 0) 874: { 875: /* Find number of cycles for when timer is due (include preset and 876: * counter). As timer occurs very often we multiply by counter to 877: * speed up emulator */ 878: if (TimerData == 0) /* Data=0 is actually Data=256 */ 879: TimerData = 256; 880: TimerClockCycles = MFP_REG_TO_CYCLES ( TimerData, TimerControl ); 881: 1.1.1.14 root 882: if ( LOG_TRACE_LEVEL( TRACE_MFP_START ) ) 1.1.1.11 root 883: { 1.1.1.14 root 884: int FrameCycles, HblCounterVideo, LineCycles; 885: Video_GetPosition ( &FrameCycles , &HblCounterVideo , &LineCycles ); 886: LOG_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" , 1.1.1.11 root 887: Handler, TimerData, TimerControl, TimerClockCycles, PendingCyclesOver, 1.1.1.14 root 888: FrameCycles, LineCycles, HblCounterVideo, M68000_GetPC(), CurrentInstrCycles, 1.1.1.11 root 889: bFirstTimer?"true":"false" , *pTimerCanResume?"true":"false" ); 890: } 891: 892: /* And add to our internal interrupt list, if timer cycles is zero 893: * then timer is stopped */ 1.1.1.15 root 894: CycInt_RemovePendingInterrupt(Handler); 1.1.1.11 root 895: if (TimerClockCycles) 896: { 1.1.1.14 root 897: if ((*pTimerCanResume == true) && (bFirstTimer == true)) /* we can't resume if the timer is auto restarting after an interrupt */ 1.1.1.11 root 898: { 1.1.1.15 root 899: CycInt_ResumeStoppedInterrupt ( Handler ); 1.1.1.11 root 900: } 901: else 902: { 903: int AddCurCycles = INT_CONVERT_TO_INTERNAL ( CurrentInstrCycles + nWaitStateCycles - 4 , INT_CPU_CYCLE ); 904: 905: /* Start timer from now? If not continue timer using PendingCycleOver */ 906: if (bFirstTimer) 1.1.1.15 root 907: CycInt_AddRelativeInterruptWithOffset(TimerClockCycles, INT_MFP_CYCLE, Handler, AddCurCycles); 1.1.1.11 root 908: else 909: { 910: int TimerClockCyclesInternal = INT_CONVERT_TO_INTERNAL ( TimerClockCycles , INT_MFP_CYCLE ); 911: 912: /* In case we miss more than one int, we must correct the delay for the next one */ 913: if ( PendingCyclesOver > TimerClockCyclesInternal ) 914: PendingCyclesOver = PendingCyclesOver % TimerClockCyclesInternal; 915: 1.1.1.15 root 916: CycInt_AddRelativeInterruptWithOffset(TimerClockCycles, INT_MFP_CYCLE, Handler, -PendingCyclesOver); 1.1.1.11 root 917: } 918: 1.1.1.14 root 919: *pTimerCanResume = true; /* timer was set, resume is possible if stop/start it later */ 1.1.1.11 root 920: } 921: } 922: } 1.1.1.12 root 923: 924: else /* timer control is 0 */ 1.1.1.11 root 925: { 1.1.1.14 root 926: if ( LOG_TRACE_LEVEL( TRACE_MFP_START ) ) 1.1.1.12 root 927: { 1.1.1.14 root 928: int FrameCycles, HblCounterVideo, LineCycles; 929: Video_GetPosition ( &FrameCycles , &HblCounterVideo , &LineCycles ); 930: LOG_TRACE_PRINT("mfp stop 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" , 1.1.1.12 root 931: Handler, TimerData, TimerControl, TimerClockCycles, PendingCyclesOver, 1.1.1.14 root 932: FrameCycles, LineCycles, HblCounterVideo, M68000_GetPC(), CurrentInstrCycles, 1.1.1.12 root 933: bFirstTimer?"true":"false" , *pTimerCanResume?"true":"false" ); 934: } 935: 1.1.1.11 root 936: /* Make sure no outstanding interrupts in list if channel is disabled */ 1.1.1.15 root 937: CycInt_RemovePendingInterrupt(Handler); 1.1.1.11 root 938: } 1.1 root 939: 1.1.1.11 root 940: return TimerClockCycles; 1.1 root 941: } 942: 1.1.1.2 root 943: 944: /*-----------------------------------------------------------------------*/ 1.1.1.11 root 945: /** 946: * Read Timer A or B - If in EventCount MainCounter already has correct value 947: */ 1.1.1.14 root 948: static Uint8 MFP_ReadTimer_AB(Uint8 TimerControl, Uint8 MainCounter, int TimerCycles, interrupt_id Handler, bool TimerIsStopping) 1.1 root 949: { 1.1.1.12 root 950: // int TimerCyclesPassed; 1.1 root 951: 1.1.1.11 root 952: /* Find TimerAB count, if no interrupt or not in delay mode assume 953: * in Event Count mode so already up-to-date as kept by HBL */ 1.1.1.15 root 954: if (CycInt_InterruptActive(Handler) && (TimerControl > 0) && (TimerControl <= 7)) 1.1.1.11 root 955: { 956: /* Find cycles passed since last interrupt */ 1.1.1.15 root 957: //TimerCyclesPassed = TimerCycles - CycInt_FindCyclesPassed ( Handler, INT_MFP_CYCLE ); 958: MainCounter = MFP_CYCLE_TO_REG ( CycInt_FindCyclesPassed ( Handler, INT_MFP_CYCLE ), TimerControl ); 1.1.1.11 root 959: //fprintf ( stderr , "mfp read AB passed %d count %d\n" , TimerCyclesPassed, MainCounter ); 960: } 961: 1.1.1.12 root 962: /* If the timer is stopped when the internal mfp data reg is already < 1 */ 963: /* then the data reg will be 0 (=256) next time the timer will be restarted */ 964: /* if no write is made to the data reg before */ 965: if ( TimerIsStopping ) 966: { 1.1.1.15 root 967: if ( CycInt_FindCyclesPassed ( Handler, INT_MFP_CYCLE ) < MFP_REG_TO_CYCLES ( 1 , TimerControl ) ) 1.1.1.12 root 968: { 969: MainCounter = 0; /* internal mfp counter becomes 0 (=256) */ 1.1.1.14 root 970: LOG_TRACE(TRACE_MFP_READ , "mfp read AB handler=%d stopping timer while data reg between 1 and 0 : forcing data to 256\n" , 1.1.1.12 root 971: Handler ); 972: } 973: } 974: 1.1.1.14 root 975: if ( LOG_TRACE_LEVEL( TRACE_MFP_READ ) ) 1.1.1.11 root 976: { 1.1.1.14 root 977: int FrameCycles, HblCounterVideo, LineCycles; 978: Video_GetPosition ( &FrameCycles , &HblCounterVideo , &LineCycles ); 979: LOG_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" , 1.1.1.11 root 980: Handler, MainCounter, TimerControl, TimerCycles, 1.1.1.14 root 981: FrameCycles, LineCycles, HblCounterVideo, M68000_GetPC(), CurrentInstrCycles ); 1.1.1.11 root 982: } 1.1.1.6 root 983: 1.1.1.11 root 984: return MainCounter; 1.1 root 985: } 986: 1.1.1.2 root 987: 988: /*-----------------------------------------------------------------------*/ 1.1.1.11 root 989: /** 990: * Read Timer C or D 991: */ 1.1.1.14 root 992: static Uint8 MFP_ReadTimerCD(Uint8 TimerControl, Uint8 TimerData, Uint8 MainCounter, int TimerCycles, interrupt_id Handler, bool TimerIsStopping) 1.1 root 993: { 1.1.1.12 root 994: // int TimerCyclesPassed; 1.1 root 995: 1.1.1.11 root 996: /* Find TimerCD count. If timer is off, MainCounter already contains 997: * the latest value */ 1.1.1.15 root 998: if (CycInt_InterruptActive(Handler)) 1.1.1.11 root 999: { 1000: /* Find cycles passed since last interrupt */ 1.1.1.15 root 1001: //TimerCyclesPassed = TimerCycles - CycInt_FindCyclesPassed ( Handler, INT_MFP_CYCLE ); 1002: MainCounter = MFP_CYCLE_TO_REG ( CycInt_FindCyclesPassed ( Handler, INT_MFP_CYCLE ), TimerControl); 1.1.1.11 root 1003: //fprintf ( stderr , "mfp read CD passed %d count %d\n" , TimerCyclesPassed, MainCounter ); 1004: } 1005: 1.1.1.12 root 1006: /* If the timer is stopped when the internal mfp data reg is already < 1 */ 1007: /* then the data reg will be 0 (=256) next time the timer will be restarted */ 1008: /* if no write is made to the data reg before */ 1009: if ( TimerIsStopping ) 1010: { 1.1.1.15 root 1011: if ( CycInt_FindCyclesPassed ( Handler, INT_MFP_CYCLE ) < MFP_REG_TO_CYCLES ( 1 , TimerControl ) ) 1.1.1.12 root 1012: { 1013: MainCounter = 0; /* internal mfp counter becomes 0 (=256) */ 1.1.1.14 root 1014: LOG_TRACE(TRACE_MFP_READ , "mfp read CD handler=%d stopping timer while data reg between 1 and 0 : forcing data to 256\n" , 1.1.1.12 root 1015: Handler ); 1016: } 1017: } 1018: 1.1.1.14 root 1019: if ( LOG_TRACE_LEVEL( TRACE_MFP_READ ) ) 1.1.1.11 root 1020: { 1.1.1.14 root 1021: int FrameCycles, HblCounterVideo, LineCycles; 1022: Video_GetPosition ( &FrameCycles , &HblCounterVideo , &LineCycles ); 1023: LOG_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" , 1.1.1.11 root 1024: Handler, MainCounter, TimerControl, TimerCycles, 1.1.1.14 root 1025: FrameCycles, LineCycles, HblCounterVideo, M68000_GetPC(), CurrentInstrCycles ); 1.1.1.11 root 1026: } 1.1 root 1027: 1.1.1.11 root 1028: return MainCounter; 1.1 root 1029: } 1030: 1.1.1.2 root 1031: 1032: /*-----------------------------------------------------------------------*/ 1.1.1.11 root 1033: /** 1034: * Start Timer A 1035: */ 1.1.1.10 root 1036: static void MFP_StartTimerA(void) 1.1 root 1037: { 1.1.1.11 root 1038: TimerAClockCycles = MFP_StartTimer_AB(MFP_TACR, MFP_TA_MAINCOUNTER, 1.1.1.14 root 1039: INTERRUPT_MFP_TIMERA, true, &TimerACanResume); 1.1 root 1040: } 1041: 1042: 1.1.1.2 root 1043: /*-----------------------------------------------------------------------*/ 1.1.1.11 root 1044: /** 1045: * Read Timer A 1046: */ 1.1.1.12 root 1047: static void MFP_ReadTimerA(bool TimerIsStopping) 1.1 root 1048: { 1.1.1.11 root 1049: MFP_TA_MAINCOUNTER = MFP_ReadTimer_AB(MFP_TACR, MFP_TA_MAINCOUNTER, 1.1.1.12 root 1050: TimerAClockCycles, INTERRUPT_MFP_TIMERA, TimerIsStopping); 1.1 root 1051: } 1052: 1053: 1.1.1.2 root 1054: /*-----------------------------------------------------------------------*/ 1.1.1.11 root 1055: /** 1056: * Start Timer B 1057: * (This does not start the EventCount mode time as this is taken care 1058: * of by the HBL) 1059: */ 1.1.1.10 root 1060: static void MFP_StartTimerB(void) 1.1 root 1061: { 1.1.1.11 root 1062: TimerBClockCycles = MFP_StartTimer_AB(MFP_TBCR, MFP_TB_MAINCOUNTER, 1.1.1.14 root 1063: INTERRUPT_MFP_TIMERB, true, &TimerBCanResume); 1.1 root 1064: } 1065: 1066: 1.1.1.2 root 1067: /*-----------------------------------------------------------------------*/ 1.1.1.11 root 1068: /** 1069: * Read Timer B 1070: */ 1.1.1.12 root 1071: static void MFP_ReadTimerB(bool TimerIsStopping) 1.1 root 1072: { 1.1.1.11 root 1073: MFP_TB_MAINCOUNTER = MFP_ReadTimer_AB(MFP_TBCR, MFP_TB_MAINCOUNTER, 1.1.1.12 root 1074: TimerBClockCycles, INTERRUPT_MFP_TIMERB, TimerIsStopping); 1.1 root 1075: } 1076: 1077: 1.1.1.2 root 1078: /*-----------------------------------------------------------------------*/ 1.1.1.11 root 1079: /** 1080: * Start Timer C 1081: */ 1.1.1.10 root 1082: static void MFP_StartTimerC(void) 1.1 root 1083: { 1.1.1.11 root 1084: TimerCClockCycles = MFP_StartTimer_CD((MFP_TCDCR>>4)&7, MFP_TC_MAINCOUNTER, 1.1.1.14 root 1085: INTERRUPT_MFP_TIMERC , true, &TimerCCanResume); 1.1 root 1086: } 1087: 1088: 1.1.1.2 root 1089: /*-----------------------------------------------------------------------*/ 1.1.1.11 root 1090: /** 1091: * Read Timer C 1092: */ 1.1.1.12 root 1093: static void MFP_ReadTimerC(bool TimerIsStopping) 1.1 root 1094: { 1.1.1.11 root 1095: MFP_TC_MAINCOUNTER = MFP_ReadTimerCD((MFP_TCDCR>>4)&7, MFP_TCDR, MFP_TC_MAINCOUNTER, 1.1.1.12 root 1096: TimerCClockCycles, INTERRUPT_MFP_TIMERC, TimerIsStopping); 1.1 root 1097: } 1098: 1099: 1.1.1.2 root 1100: /*-----------------------------------------------------------------------*/ 1.1.1.11 root 1101: /** 1102: * Start Timer D 1103: */ 1.1.1.10 root 1104: static void MFP_StartTimerD(void) 1.1 root 1105: { 1.1.1.11 root 1106: TimerDClockCycles = MFP_StartTimer_CD(MFP_TCDCR&7, MFP_TD_MAINCOUNTER, 1.1.1.14 root 1107: INTERRUPT_MFP_TIMERD, true, &TimerDCanResume); 1.1 root 1108: } 1109: 1110: 1.1.1.2 root 1111: /*-----------------------------------------------------------------------*/ 1.1.1.11 root 1112: /** 1113: * Read Timer D 1114: */ 1.1.1.12 root 1115: static void MFP_ReadTimerD(bool TimerIsStopping) 1.1 root 1116: { 1.1.1.11 root 1117: MFP_TD_MAINCOUNTER = MFP_ReadTimerCD(MFP_TCDCR&7, MFP_TDDR, MFP_TD_MAINCOUNTER, 1.1.1.12 root 1118: TimerDClockCycles, INTERRUPT_MFP_TIMERD, TimerIsStopping); 1.1 root 1119: } 1120: 1121: 1.1.1.2 root 1122: /*-----------------------------------------------------------------------*/ 1.1.1.11 root 1123: /** 1124: * Handle Timer A Interrupt 1125: */ 1.1 root 1126: void MFP_InterruptHandler_TimerA(void) 1127: { 1.1.1.11 root 1128: /* Number of internal cycles we went over for this timer ( <= 0 ), 1129: * used when timer expires and needs to be restarted */ 1130: PendingCyclesOver = -PendingInterruptCount; /* >= 0 */ 1131: 1132: /* Remove this interrupt from list and re-order */ 1.1.1.15 root 1133: CycInt_AcknowledgeInterrupt(); 1.1 root 1134: 1.1.1.11 root 1135: /* Acknowledge in MFP circuit, pass bit,enable,pending */ 1136: if ((MFP_TACR&0xf) != 0) /* Is timer OK? */ 1.1.1.18! root 1137: MFP_InputOnChannel ( MFP_INT_TIMER_A , 0 ); 1.1 root 1138: 1.1.1.11 root 1139: /* Start next interrupt, if need one - from current cycle count */ 1.1.1.14 root 1140: TimerAClockCycles = MFP_StartTimer_AB(MFP_TACR, MFP_TADR, INTERRUPT_MFP_TIMERA, false, &TimerACanResume); 1.1 root 1141: } 1142: 1143: 1.1.1.2 root 1144: /*-----------------------------------------------------------------------*/ 1.1.1.11 root 1145: /** 1146: * Handle Timer B Interrupt 1147: */ 1.1 root 1148: void MFP_InterruptHandler_TimerB(void) 1149: { 1.1.1.11 root 1150: /* Number of internal cycles we went over for this timer ( <= 0 ), 1151: * used when timer expires and needs to be restarted */ 1152: PendingCyclesOver = -PendingInterruptCount; /* >= 0 */ 1153: 1154: /* Remove this interrupt from list and re-order */ 1.1.1.15 root 1155: CycInt_AcknowledgeInterrupt(); 1.1 root 1156: 1.1.1.11 root 1157: /* Acknowledge in MFP circuit, pass bit, enable, pending */ 1158: if ((MFP_TBCR&0xf) != 0) /* Is timer OK? */ 1.1.1.18! root 1159: MFP_InputOnChannel ( MFP_INT_TIMER_B , 0 ); 1.1 root 1160: 1.1.1.11 root 1161: /* Start next interrupt, if need one - from current cycle count */ 1.1.1.14 root 1162: TimerBClockCycles = MFP_StartTimer_AB(MFP_TBCR, MFP_TBDR, INTERRUPT_MFP_TIMERB, false, &TimerBCanResume); 1.1 root 1163: } 1164: 1165: 1.1.1.2 root 1166: /*-----------------------------------------------------------------------*/ 1.1.1.11 root 1167: /** 1168: * Handle Timer C Interrupt 1169: */ 1.1 root 1170: void MFP_InterruptHandler_TimerC(void) 1171: { 1.1.1.11 root 1172: /* Number of internal cycles we went over for this timer ( <= 0 ), 1173: * used when timer expires and needs to be restarted */ 1174: PendingCyclesOver = -PendingInterruptCount; /* >= 0 */ 1.1 root 1175: 1.1.1.11 root 1176: /* Remove this interrupt from list and re-order */ 1.1.1.15 root 1177: CycInt_AcknowledgeInterrupt(); 1.1 root 1178: 1.1.1.11 root 1179: /* Acknowledge in MFP circuit, pass bit, enable, pending */ 1180: if ((MFP_TCDCR&0x70) != 0) /* Is timer OK? */ 1.1.1.18! root 1181: MFP_InputOnChannel ( MFP_INT_TIMER_C , 0 ); 1.1.1.11 root 1182: 1183: /* Start next interrupt, if need one - from current cycle count */ 1.1.1.14 root 1184: TimerCClockCycles = MFP_StartTimer_CD((MFP_TCDCR>>4)&7, MFP_TCDR, INTERRUPT_MFP_TIMERC, false, &TimerCCanResume); 1.1 root 1185: } 1186: 1187: 1.1.1.2 root 1188: /*-----------------------------------------------------------------------*/ 1.1.1.11 root 1189: /** 1190: * Handle Timer D Interrupt 1191: */ 1.1 root 1192: void MFP_InterruptHandler_TimerD(void) 1193: { 1.1.1.11 root 1194: /* Number of internal cycles we went over for this timer ( <= 0 ), 1195: * used when timer expires and needs to be restarted */ 1196: PendingCyclesOver = -PendingInterruptCount; /* >= 0 */ 1197: 1198: /* Remove this interrupt from list and re-order */ 1.1.1.15 root 1199: CycInt_AcknowledgeInterrupt(); 1.1.1.11 root 1200: 1201: /* Acknowledge in MFP circuit, pass bit, enable, pending */ 1202: if ((MFP_TCDCR&0x07) != 0) /* Is timer OK? */ 1.1.1.18! root 1203: MFP_InputOnChannel ( MFP_INT_TIMER_D , 0 ); 1.1.1.11 root 1204: 1205: /* Start next interrupt, if need one - from current cycle count */ 1.1.1.14 root 1206: TimerDClockCycles = MFP_StartTimer_CD(MFP_TCDCR&7, MFP_TDDR, INTERRUPT_MFP_TIMERD, false, &TimerDCanResume); 1.1 root 1207: } 1208: 1.1.1.8 root 1209: 1210: 1211: /*-----------------------------------------------------------------------*/ 1.1.1.11 root 1212: /** 1213: * Handle read from GPIP pins register (0xfffa01). 1214: * 1215: * - Bit 0 is the BUSY signal of the printer port, it is SET if no printer 1216: * is connected or on BUSY. Therefor we should assume it to be 0 in Hatari 1217: * when a printer is emulated. 1218: * - Bit 1 is used for RS232: DCD 1219: * - Bit 2 is used for RS232: CTS 1220: * - Bit 3 is used by the blitter for signalling when its done. 1221: * - Bit 4 is used by the ACIAs. 1222: * - Bit 5 is used by the floppy controller / ACSI DMA 1223: * - Bit 6 is used for RS232: RI 1224: * - Bit 7 is monochrome monitor detection signal. On STE it is also XORed with 1225: * the DMA sound play bit. 1226: */ 1.1.1.8 root 1227: void MFP_GPIP_ReadByte(void) 1228: { 1.1.1.10 root 1229: M68000_WaitState(4); 1230: 1.1.1.8 root 1231: if (!bUseHighRes) 1.1.1.11 root 1232: MFP_GPIP |= 0x80; /* Color monitor -> set top bit */ 1.1.1.9 root 1233: else 1234: MFP_GPIP &= ~0x80; 1.1.1.15 root 1235: 1.1.1.9 root 1236: if (nDmaSoundControl & DMASNDCTRL_PLAY) 1.1.1.15 root 1237: MFP_GPIP ^= 0x80; /* Top bit is XORed with DMA sound control play bit (Ste/TT emulation mode)*/ 1238: if (nCbar_DmaSoundControl & CROSSBAR_SNDCTRL_PLAY || nCbar_DmaSoundControl & CROSSBAR_SNDCTRL_RECORD) 1239: MFP_GPIP ^= 0x80; /* Top bit is XORed with Falcon crossbar DMA sound control play bit (Falcon emulation mode) */ 1.1.1.9 root 1240: 1241: if (ConfigureParams.Printer.bEnablePrinting) 1242: { 1243: /* Signal that printer is not busy */ 1244: MFP_GPIP &= ~1; 1245: } 1246: else 1247: { 1248: MFP_GPIP |= 1; 1249: 1250: /* Printer BUSY bit is also used by parallel port joystick adapters as fire button */ 1251: if (ConfigureParams.Joysticks.Joy[JOYID_PARPORT1].nJoystickMode != JOYSTICK_DISABLED) 1252: { 1253: /* Fire pressed? */ 1254: if (Joy_GetStickData(JOYID_PARPORT1) & 0x80) 1255: MFP_GPIP &= ~1; 1256: } 1257: } 1.1.1.8 root 1258: 1.1.1.9 root 1259: IoMem[0xfffa01] = MFP_GPIP; 1.1.1.13 root 1260: 1.1.1.14 root 1261: if ( LOG_TRACE_LEVEL( TRACE_MFP_READ ) ) 1.1.1.13 root 1262: { 1.1.1.14 root 1263: int FrameCycles, HblCounterVideo, LineCycles; 1264: Video_GetPosition ( &FrameCycles , &HblCounterVideo , &LineCycles ); 1265: LOG_TRACE_PRINT("mfp read gpip fa01=0x%x video_cyc=%d %d@%d pc=%x instr_cycle %d\n" , 1266: MFP_GPIP, FrameCycles, LineCycles, HblCounterVideo, M68000_GetPC(), CurrentInstrCycles ); 1.1.1.13 root 1267: } 1.1.1.8 root 1268: } 1269: 1270: /*-----------------------------------------------------------------------*/ 1.1.1.11 root 1271: /** 1272: * Handle read from active edge register (0xfffa03). 1273: */ 1.1.1.8 root 1274: void MFP_ActiveEdge_ReadByte(void) 1275: { 1.1.1.10 root 1276: M68000_WaitState(4); 1277: 1.1.1.8 root 1278: IoMem[0xfffa03] = MFP_AER; 1279: } 1280: 1281: /*-----------------------------------------------------------------------*/ 1.1.1.11 root 1282: /** 1283: * Handle read from data direction register (0xfffa05). 1284: */ 1.1.1.8 root 1285: void MFP_DataDirection_ReadByte(void) 1286: { 1.1.1.10 root 1287: M68000_WaitState(4); 1288: 1.1.1.8 root 1289: IoMem[0xfffa05] = MFP_DDR; 1290: } 1291: 1292: /*-----------------------------------------------------------------------*/ 1.1.1.11 root 1293: /** 1.1.1.18! root 1294: * Handle read from interrupt enable register A (0xfffa07). 1.1.1.11 root 1295: */ 1.1.1.8 root 1296: void MFP_EnableA_ReadByte(void) 1297: { 1.1.1.10 root 1298: M68000_WaitState(4); 1299: 1.1.1.8 root 1300: IoMem[0xfffa07] = MFP_IERA; 1301: } 1302: 1303: /*-----------------------------------------------------------------------*/ 1.1.1.11 root 1304: /** 1.1.1.18! root 1305: * Handle read from interrupt enable register B (0xfffa09). 1.1.1.11 root 1306: */ 1.1.1.8 root 1307: void MFP_EnableB_ReadByte(void) 1308: { 1.1.1.10 root 1309: M68000_WaitState(4); 1310: 1.1.1.8 root 1311: IoMem[0xfffa09] = MFP_IERB; 1312: } 1313: 1314: /*-----------------------------------------------------------------------*/ 1.1.1.11 root 1315: /** 1.1.1.18! root 1316: * Handle read from interrupt pending register A (0xfffa0b). 1.1.1.11 root 1317: */ 1.1.1.8 root 1318: void MFP_PendingA_ReadByte(void) 1319: { 1.1.1.10 root 1320: M68000_WaitState(4); 1321: 1.1.1.8 root 1322: IoMem[0xfffa0b] = MFP_IPRA; 1323: } 1324: 1325: /*-----------------------------------------------------------------------*/ 1.1.1.11 root 1326: /** 1.1.1.18! root 1327: * Handle read from interrupt pending register A (0xfffa0d). 1.1.1.11 root 1328: */ 1.1.1.8 root 1329: void MFP_PendingB_ReadByte(void) 1330: { 1.1.1.10 root 1331: M68000_WaitState(4); 1332: 1.1.1.8 root 1333: IoMem[0xfffa0d] = MFP_IPRB; 1334: } 1335: 1336: /*-----------------------------------------------------------------------*/ 1.1.1.11 root 1337: /** 1.1.1.18! root 1338: * Handle read from interrupt in service register A (0xfffa0f). 1.1.1.11 root 1339: */ 1.1.1.8 root 1340: void MFP_InServiceA_ReadByte(void) 1341: { 1.1.1.10 root 1342: M68000_WaitState(4); 1343: 1.1.1.8 root 1344: IoMem[0xfffa0f] = MFP_ISRA; 1345: } 1346: 1347: /*-----------------------------------------------------------------------*/ 1.1.1.11 root 1348: /** 1.1.1.18! root 1349: * Handle read from interrupt in service register B (0xfffa11). 1.1.1.11 root 1350: */ 1.1.1.8 root 1351: void MFP_InServiceB_ReadByte(void) 1352: { 1.1.1.10 root 1353: M68000_WaitState(4); 1354: 1.1.1.8 root 1355: IoMem[0xfffa11] = MFP_ISRB; 1356: } 1357: 1358: /*-----------------------------------------------------------------------*/ 1.1.1.11 root 1359: /** 1.1.1.18! root 1360: * Handle read from interrupt mask register A (0xfffa13). 1.1.1.11 root 1361: */ 1.1.1.8 root 1362: void MFP_MaskA_ReadByte(void) 1363: { 1.1.1.10 root 1364: M68000_WaitState(4); 1365: 1.1.1.8 root 1366: IoMem[0xfffa13] = MFP_IMRA; 1367: } 1368: 1369: /*-----------------------------------------------------------------------*/ 1.1.1.11 root 1370: /** 1.1.1.18! root 1371: * Handle read from interrupt mask register B (0xfffa15). 1.1.1.11 root 1372: */ 1.1.1.8 root 1373: void MFP_MaskB_ReadByte(void) 1374: { 1.1.1.10 root 1375: M68000_WaitState(4); 1376: 1.1.1.8 root 1377: IoMem[0xfffa15] = MFP_IMRB; 1378: } 1379: 1380: /*-----------------------------------------------------------------------*/ 1.1.1.11 root 1381: /** 1382: * Handle read from MFP vector register (0xfffa17). 1383: */ 1.1.1.8 root 1384: void MFP_VectorReg_ReadByte(void) 1385: { 1.1.1.10 root 1386: M68000_WaitState(4); 1387: 1.1.1.8 root 1388: IoMem[0xfffa17] = MFP_VR; 1389: } 1390: 1391: /*-----------------------------------------------------------------------*/ 1.1.1.11 root 1392: /** 1393: * Handle read from timer A control register (0xfffa19). 1394: */ 1.1.1.8 root 1395: void MFP_TimerACtrl_ReadByte(void) 1396: { 1.1.1.10 root 1397: M68000_WaitState(4); 1398: 1.1.1.8 root 1399: IoMem[0xfffa19] = MFP_TACR; 1400: } 1401: 1402: /*-----------------------------------------------------------------------*/ 1.1.1.11 root 1403: /** 1404: * Handle read from timer B control register (0xfffa1b). 1405: */ 1.1.1.8 root 1406: void MFP_TimerBCtrl_ReadByte(void) 1407: { 1.1.1.10 root 1408: M68000_WaitState(4); 1409: 1.1.1.8 root 1410: IoMem[0xfffa1b] = MFP_TBCR; 1411: } 1412: 1413: /*-----------------------------------------------------------------------*/ 1.1.1.11 root 1414: /** 1415: * Handle read from timer C/D control register (0xfffa1d). 1416: */ 1.1.1.8 root 1417: void MFP_TimerCDCtrl_ReadByte(void) 1418: { 1.1.1.10 root 1419: M68000_WaitState(4); 1420: 1.1.1.8 root 1421: IoMem[0xfffa1d] = MFP_TCDCR; 1422: } 1423: 1424: /*-----------------------------------------------------------------------*/ 1.1.1.11 root 1425: /** 1426: * Handle read from timer A data register (0xfffa1f). 1427: */ 1.1.1.8 root 1428: void MFP_TimerAData_ReadByte(void) 1429: { 1.1.1.10 root 1430: M68000_WaitState(4); 1431: 1.1.1.12 root 1432: if (MFP_TACR != 8) /* Is event count? Need to re-calculate counter */ 1.1.1.14 root 1433: MFP_ReadTimerA(false); /* Stores result in 'MFP_TA_MAINCOUNTER' */ 1.1.1.8 root 1434: 1435: IoMem[0xfffa1f] = MFP_TA_MAINCOUNTER; 1436: } 1437: 1438: /*-----------------------------------------------------------------------*/ 1.1.1.11 root 1439: /** 1440: * Handle read from timer B data register (0xfffa21). 1441: */ 1.1.1.8 root 1442: void MFP_TimerBData_ReadByte(void) 1443: { 1.1.1.12 root 1444: Uint8 TB_count; 1445: 1.1.1.10 root 1446: M68000_WaitState(4); 1447: 1.1.1.13 root 1448: /* Is it event count mode or not? */ 1449: if (MFP_TBCR != 8) 1450: { 1451: /* Not event count mode, so handle as normal timer 1452: * and store result in 'MFP_TB_MAINCOUNTER' */ 1.1.1.14 root 1453: MFP_ReadTimerB(false); 1.1.1.13 root 1454: } 1455: else if (bUseVDIRes) 1456: { 1457: /* HBLs are disabled in VDI mode, but TOS expects to read a 1. */ 1458: MFP_TB_MAINCOUNTER = 1; 1459: } 1.1.1.12 root 1460: /* Special case when reading $fffa21, we need to test if the current read instruction */ 1461: /* overlaps the horizontal video position where $fffa21 is changed */ 1462: else 1463: { 1.1.1.14 root 1464: int FrameCycles, HblCounterVideo; 1.1.1.12 root 1465: int pos_start , pos_read; 1466: 1467: /* Cycle position of the start of the current instruction */ 1.1.1.14 root 1468: //pos_start = nFrameCycles % nCyclesPerLine; 1469: Video_GetPosition ( &FrameCycles , &HblCounterVideo , &pos_start ); 1.1.1.12 root 1470: /* Cycle position of the read for the current instruction (approximatively, we consider */ 1471: /* the read happens after 4 cycles (due to MFP wait states in that case)) */ 1472: /* This is quite a hack, but hard to do without proper 68000 read cycle emulation */ 1473: if ( CurrentInstrCycles <= 8 ) /* move.b (a0),d0 / cmp.b (a0),d0 ... */ 1474: pos_read = pos_start + 4; /* wait state */ 1475: else /* cmp.b $fa21.w,d0 (BIG Demo) ... */ 1476: pos_read = pos_start + 8; /* more time needed to compute the effective address */ 1477: 1478: TB_count = MFP_TB_MAINCOUNTER; /* default value */ 1479: 1480: /* If Timer B's change happens before the read cycle of the current instruction, we must return */ 1481: /* the current value - 1 (because MFP_TimerB_EventCount_Interrupt was not called yet) */ 1482: if ( (nHBL >= nStartHBL ) && ( nHBL < nEndHBL ) /* ensure display is ON and timer B can happen */ 1483: && ( LineTimerBCycle > pos_start ) && ( LineTimerBCycle < pos_read ) ) 1484: { 1.1.1.14 root 1485: LOG_TRACE(TRACE_MFP_READ , "mfp read TB overlaps pos_start=%d TB_pos=%d pos_read=%d nHBL=%d \n", 1486: pos_start, LineTimerBCycle, pos_read , HblCounterVideo ); 1.1.1.12 root 1487: 1488: TB_count--; 1489: if ( TB_count == 0 ) /* going from 1 to 0 : timer restart, reload data reg */ 1490: TB_count = MFP_TBDR; 1491: /* Going from 0 to -1 : data reg is in fact going from 256 to 255. As TB_count is Uint8, */ 1492: /* this is already what we get when we decrement TB_count=0. So, the next 2 lines are redundant. */ 1493: /* else if ( TB_count < 0 ) 1494: TB_count = 255; 1495: */ 1496: } 1497: 1.1.1.14 root 1498: LOG_TRACE(TRACE_MFP_READ , "mfp read TB data=%d video_cyc=%d %d@%d pc=%x instr_cyc=%d\n" , 1499: TB_count, FrameCycles, pos_start, HblCounterVideo, M68000_GetPC(), CurrentInstrCycles ); 1.1.1.12 root 1500: IoMem[0xfffa21] = TB_count; 1501: return; 1502: } 1.1.1.8 root 1503: 1504: IoMem[0xfffa21] = MFP_TB_MAINCOUNTER; 1505: } 1506: 1507: /*-----------------------------------------------------------------------*/ 1.1.1.11 root 1508: /** 1509: * Handle read from timer C data register (0xfffa23). 1510: */ 1.1.1.8 root 1511: void MFP_TimerCData_ReadByte(void) 1512: { 1.1.1.10 root 1513: M68000_WaitState(4); 1514: 1.1.1.14 root 1515: MFP_ReadTimerC(false); /* Stores result in 'MFP_TC_MAINCOUNTER' */ 1.1.1.8 root 1516: 1517: IoMem[0xfffa23] = MFP_TC_MAINCOUNTER; 1518: } 1519: 1520: /*-----------------------------------------------------------------------*/ 1.1.1.11 root 1521: /** 1522: * Handle read from timer D data register (0xfffa25). 1523: */ 1.1.1.8 root 1524: void MFP_TimerDData_ReadByte(void) 1525: { 1.1.1.11 root 1526: Uint32 pc = M68000_GetPC(); 1.1.1.8 root 1527: 1.1.1.10 root 1528: M68000_WaitState(4); 1529: 1.1.1.8 root 1530: if (ConfigureParams.System.bPatchTimerD && pc >= TosAddress && pc <= TosAddress + TosSize) 1531: { 1532: /* Trick the tos to believe it was changed: */ 1533: IoMem[0xfffa25] = nTimerDFakeValue; 1534: } 1535: else 1536: { 1.1.1.14 root 1537: MFP_ReadTimerD(false); /* Stores result in 'MFP_TD_MAINCOUNTER' */ 1.1.1.8 root 1538: IoMem[0xfffa25] = MFP_TD_MAINCOUNTER; 1539: } 1540: } 1541: 1542: 1543: /*-----------------------------------------------------------------------*/ 1.1.1.11 root 1544: /** 1545: * Handle write to GPIP register (0xfffa01). 1546: */ 1.1.1.8 root 1547: void MFP_GPIP_WriteByte(void) 1548: { 1.1.1.10 root 1549: M68000_WaitState(4); 1550: 1.1.1.8 root 1551: /* Nothing... */ 1552: /*fprintf(stderr, "Write to GPIP: %x\n", (int)IoMem[0xfffa01]);*/ 1553: /*MFP_GPIP = IoMem[0xfffa01];*/ /* TODO: What are the GPIP pins good for? */ 1554: } 1555: 1556: /*-----------------------------------------------------------------------*/ 1.1.1.11 root 1557: /** 1.1.1.14 root 1558: * Handle write to AER (0xfffa03) 1559: * Bit 3 of AER is linked to timer B in event count mode. 1560: * If bit 3=0, timer B triggers on end of line when display goes off. 1561: * If bit 3=1, timer B triggers on start of line when display goes on. 1.1.1.11 root 1562: */ 1.1.1.8 root 1563: void MFP_ActiveEdge_WriteByte(void) 1564: { 1.1.1.14 root 1565: int FrameCycles, HblCounterVideo, LineCycles; 1566: int LineTimerBCycle_old = LineTimerBCycle; 1567: 1568: Video_GetPosition ( &FrameCycles , &HblCounterVideo , &LineCycles ); 1569: 1.1.1.10 root 1570: M68000_WaitState(4); 1571: 1.1.1.14 root 1572: /* 0 -> 1, timer B is now counting start of line events (cycle 56+28) */ 1573: if ( ( ( MFP_AER & ( 1 << 3 ) ) == 0 ) && ( ( IoMem[0xfffa03] & ( 1 << 3 ) ) != 1 ) ) 1574: { 1575: LineTimerBCycle = Video_TimerB_GetPos ( HblCounterVideo ); 1576: 1577: LOG_TRACE((TRACE_VIDEO_HBL | TRACE_MFP_WRITE), 1578: "mfp/video AER bit 3 0->1, timer B triggers on start of line," 1579: " old_pos=%d new_pos=%d video_cyc=%d %d@%d pc=%x instr_cyc=%d\n", 1580: LineTimerBCycle_old, LineTimerBCycle, 1581: FrameCycles, LineCycles, nHBL, M68000_GetPC(), CurrentInstrCycles); 1582: } 1583: 1584: /* 1 -> 0, timer B is now counting end of line events (cycle 376+28) */ 1585: else if ( ( ( MFP_AER & ( 1 << 3 ) ) != 0 ) && ( ( IoMem[0xfffa03] & ( 1 << 3 ) ) == 0 ) ) 1586: { 1587: LineTimerBCycle = Video_TimerB_GetPos ( HblCounterVideo ); 1588: 1589: LOG_TRACE((TRACE_VIDEO_HBL | TRACE_MFP_WRITE), 1590: "mfp/video AER bit 3 1->0, timer B triggers on end of line," 1591: " old_pos=%d new_pos=%d video_cyc=%d %d@%d pc=%x instr_cyc=%d\n", 1592: LineTimerBCycle_old, LineTimerBCycle, 1593: FrameCycles, LineCycles, nHBL, M68000_GetPC(), CurrentInstrCycles); 1594: } 1595: 1596: /* Timer B position changed, update the next interrupt */ 1597: if ( LineTimerBCycle_old != LineTimerBCycle ) 1598: Video_AddInterruptTimerB ( LineTimerBCycle ); 1599: 1.1.1.8 root 1600: MFP_AER = IoMem[0xfffa03]; 1601: } 1602: 1603: /*-----------------------------------------------------------------------*/ 1.1.1.11 root 1604: /** 1605: * Handle write to data direction register (0xfffa05). 1606: */ 1.1.1.8 root 1607: void MFP_DataDirection_WriteByte(void) 1608: { 1.1.1.10 root 1609: M68000_WaitState(4); 1610: 1.1.1.8 root 1611: MFP_DDR = IoMem[0xfffa05]; 1612: } 1613: 1614: /*-----------------------------------------------------------------------*/ 1.1.1.11 root 1615: /** 1616: * Handle write to interrupt enable register A (0xfffa07). 1617: */ 1.1.1.8 root 1618: void MFP_EnableA_WriteByte(void) 1619: { 1.1.1.10 root 1620: M68000_WaitState(4); 1621: 1.1.1.8 root 1622: MFP_IERA = IoMem[0xfffa07]; 1623: MFP_IPRA &= MFP_IERA; 1.1.1.18! root 1624: MFP_UpdateIRQ ( Cycles_GetClockCounterOnWriteAccess() ); 1.1.1.8 root 1625: } 1626: 1627: /*-----------------------------------------------------------------------*/ 1.1.1.11 root 1628: /** 1629: * Handle write to interrupt enable register B (0xfffa09). 1630: */ 1.1.1.8 root 1631: void MFP_EnableB_WriteByte(void) 1632: { 1.1.1.10 root 1633: M68000_WaitState(4); 1634: 1.1.1.8 root 1635: MFP_IERB = IoMem[0xfffa09]; 1636: MFP_IPRB &= MFP_IERB; 1.1.1.18! root 1637: MFP_UpdateIRQ ( Cycles_GetClockCounterOnWriteAccess() ); 1.1.1.8 root 1638: } 1639: 1640: /*-----------------------------------------------------------------------*/ 1.1.1.11 root 1641: /** 1642: * Handle write to interrupt pending register A (0xfffa0b). 1643: */ 1.1.1.8 root 1644: void MFP_PendingA_WriteByte(void) 1645: { 1.1.1.10 root 1646: M68000_WaitState(4); 1647: 1.1.1.18! root 1648: MFP_IPRA &= IoMem[0xfffa0b]; /* Cannot set pending bits - only clear via software */ ! 1649: MFP_UpdateIRQ ( Cycles_GetClockCounterOnWriteAccess() ); 1.1.1.8 root 1650: } 1651: 1652: /*-----------------------------------------------------------------------*/ 1.1.1.11 root 1653: /** 1654: * Handle write to interrupt pending register B (0xfffa0d). 1655: */ 1.1.1.8 root 1656: void MFP_PendingB_WriteByte(void) 1657: { 1.1.1.10 root 1658: M68000_WaitState(4); 1659: 1.1.1.18! root 1660: MFP_IPRB &= IoMem[0xfffa0d]; /* Cannot set pending bits - only clear via software */ ! 1661: MFP_UpdateIRQ ( Cycles_GetClockCounterOnWriteAccess() ); 1.1.1.8 root 1662: } 1663: 1664: /*-----------------------------------------------------------------------*/ 1.1.1.11 root 1665: /** 1666: * Handle write to interrupt in service register A (0xfffa0f). 1667: */ 1.1.1.8 root 1668: void MFP_InServiceA_WriteByte(void) 1669: { 1.1.1.10 root 1670: M68000_WaitState(4); 1671: 1.1.1.18! root 1672: MFP_ISRA &= IoMem[0xfffa0f]; /* Cannot set in-service bits - only clear via software */ ! 1673: MFP_UpdateIRQ ( Cycles_GetClockCounterOnWriteAccess() ); 1.1.1.8 root 1674: } 1675: 1676: /*-----------------------------------------------------------------------*/ 1.1.1.11 root 1677: /** 1678: * Handle write to interrupt in service register B (0xfffa11). 1679: */ 1.1.1.8 root 1680: void MFP_InServiceB_WriteByte(void) 1681: { 1.1.1.10 root 1682: M68000_WaitState(4); 1683: 1.1.1.18! root 1684: MFP_ISRB &= IoMem[0xfffa11]; /* Cannot set in-service bits - only clear via software */ ! 1685: MFP_UpdateIRQ ( Cycles_GetClockCounterOnWriteAccess() ); 1.1.1.8 root 1686: } 1687: 1688: /*-----------------------------------------------------------------------*/ 1.1.1.11 root 1689: /** 1690: * Handle write to interrupt mask register A (0xfffa13). 1691: */ 1.1.1.8 root 1692: void MFP_MaskA_WriteByte(void) 1693: { 1.1.1.10 root 1694: M68000_WaitState(4); 1695: 1.1.1.8 root 1696: MFP_IMRA = IoMem[0xfffa13]; 1.1.1.18! root 1697: MFP_UpdateIRQ ( Cycles_GetClockCounterOnWriteAccess() ); 1.1.1.8 root 1698: } 1699: 1700: /*-----------------------------------------------------------------------*/ 1.1.1.11 root 1701: /** 1702: * Handle write to interrupt mask register B (0xfffa15). 1703: */ 1.1.1.8 root 1704: void MFP_MaskB_WriteByte(void) 1705: { 1.1.1.10 root 1706: M68000_WaitState(4); 1707: 1.1.1.8 root 1708: MFP_IMRB = IoMem[0xfffa15]; 1.1.1.18! root 1709: MFP_UpdateIRQ ( Cycles_GetClockCounterOnWriteAccess() ); 1.1.1.8 root 1710: } 1711: 1712: /*-----------------------------------------------------------------------*/ 1.1.1.11 root 1713: /** 1714: * Handle write to MFP vector register (0xfffa17). 1715: */ 1.1.1.8 root 1716: void MFP_VectorReg_WriteByte(void) 1717: { 1718: Uint8 old_vr; 1.1.1.10 root 1719: 1720: M68000_WaitState(4); 1721: 1.1.1.8 root 1722: old_vr = MFP_VR; /* Copy for checking if set mode */ 1723: MFP_VR = IoMem[0xfffa17]; 1.1.1.10 root 1724: 1.1.1.8 root 1725: if ((MFP_VR^old_vr) & 0x08) /* Test change in end-of-interrupt mode */ 1726: { 1.1.1.10 root 1727: /* Mode did change but was it to automatic mode? (ie bit is a zero) */ 1728: if (!(MFP_VR & 0x08)) 1729: { 1730: /* We are now in automatic mode, so clear all in-service bits! */ 1.1.1.8 root 1731: MFP_ISRA = 0; 1732: MFP_ISRB = 0; 1.1.1.18! root 1733: MFP_UpdateIRQ ( Cycles_GetClockCounterOnWriteAccess() ); 1.1.1.8 root 1734: } 1735: } 1.1.1.11 root 1736: 1.1.1.14 root 1737: if ( LOG_TRACE_LEVEL( TRACE_MFP_WRITE ) ) 1.1.1.11 root 1738: { 1.1.1.14 root 1739: int FrameCycles, HblCounterVideo, LineCycles; 1740: Video_GetPosition ( &FrameCycles , &HblCounterVideo , &LineCycles ); 1741: LOG_TRACE_PRINT("mfp write vector reg fa17=0x%x video_cyc=%d %d@%d pc=%x instr_cycle %d\n" , 1742: MFP_VR, FrameCycles, LineCycles, HblCounterVideo, M68000_GetPC(), CurrentInstrCycles ); 1.1.1.11 root 1743: } 1744: 1.1.1.8 root 1745: } 1746: 1747: /*-----------------------------------------------------------------------*/ 1.1.1.11 root 1748: /** 1749: * Handle write to timer A control register (0xfffa19). 1750: */ 1.1.1.8 root 1751: void MFP_TimerACtrl_WriteByte(void) 1752: { 1.1.1.11 root 1753: Uint8 new_tacr; 1.1.1.10 root 1754: 1755: M68000_WaitState(4); 1756: 1.1.1.11 root 1757: new_tacr = IoMem[0xfffa19] & 0x0f; /* FIXME : ignore bit 4 (reset) ? */ 1.1.1.10 root 1758: 1.1.1.11 root 1759: if ( MFP_TACR != new_tacr ) /* Timer control changed */ 1760: { 1761: /* If we stop a timer which was in delay mode, we need to store 1762: * the current value of the counter to be able to read it or to 1763: * continue from where we left if the timer is restarted later 1764: * without writing to the data register. */ 1765: if ((new_tacr == 0) && (MFP_TACR >=1) && (MFP_TACR <= 7)) 1.1.1.14 root 1766: MFP_ReadTimerA(true); /* Store result in 'MFP_TA_MAINCOUNTER' */ 1.1.1.11 root 1767: 1768: MFP_TACR = new_tacr; /* set to new value before calling MFP_StartTimer */ 1769: MFP_StartTimerA(); /* start/stop timer depending on control reg */ 1770: } 1.1.1.8 root 1771: } 1772: 1773: /*-----------------------------------------------------------------------*/ 1.1.1.11 root 1774: /** 1775: * Handle write to timer B control register (0xfffa1b). 1776: */ 1.1.1.8 root 1777: void MFP_TimerBCtrl_WriteByte(void) 1778: { 1.1.1.11 root 1779: Uint8 new_tbcr; 1.1.1.10 root 1780: 1781: M68000_WaitState(4); 1782: 1.1.1.11 root 1783: new_tbcr = IoMem[0xfffa1b] & 0x0f; /* FIXME : ignore bit 4 (reset) ? */ 1784: 1785: if (MFP_TBCR != new_tbcr) /* Timer control changed */ 1786: { 1787: /* If we stop a timer which was in delay mode, we need to store 1788: * the current value of the counter to be able to read it or to 1789: * continue from where we left if the timer is restarted later 1790: * without writing to the data register. */ 1791: if ((new_tbcr == 0) && (MFP_TBCR >= 1) && (MFP_TBCR <= 7)) 1.1.1.14 root 1792: MFP_ReadTimerB(true); /* Store result in 'MFP_TB_MAINCOUNTER' */ 1.1.1.10 root 1793: 1.1.1.11 root 1794: MFP_TBCR = new_tbcr; /* set to new value before calling MFP_StartTimer */ 1795: MFP_StartTimerB(); /* start/stop timer depending on control reg */ 1796: } 1.1.1.8 root 1797: } 1798: 1799: /*-----------------------------------------------------------------------*/ 1.1.1.11 root 1800: /** 1801: * Handle write to timer C/D control register (0xfffa1d). 1802: */ 1.1.1.8 root 1803: void MFP_TimerCDCtrl_WriteByte(void) 1804: { 1.1.1.11 root 1805: Uint8 new_tcdcr; 1.1.1.8 root 1806: Uint8 old_tcdcr; 1807: 1.1.1.10 root 1808: M68000_WaitState(4); 1809: 1.1.1.11 root 1810: new_tcdcr = IoMem[0xfffa1d]; 1811: old_tcdcr = MFP_TCDCR; 1.1.1.12 root 1812: //fprintf ( stderr , "write fa1d new %x old %x\n" , IoMem[0xfffa1d] , MFP_TCDCR ); 1.1.1.8 root 1813: 1.1.1.12 root 1814: if ((old_tcdcr & 0x70) != (new_tcdcr & 0x70)) /* Timer C control changed */ 1.1.1.11 root 1815: { 1816: /* If we stop a timer which was in delay mode, we need to store 1817: * the current value of the counter to be able to read it or to 1818: * continue from where we left if the timer is restarted later 1819: * without writing to the data register. */ 1820: if ((new_tcdcr & 0x70) == 0) 1.1.1.14 root 1821: MFP_ReadTimerC(true); /* Store result in 'MFP_TC_MAINCOUNTER' */ 1.1.1.11 root 1822: 1.1.1.12 root 1823: MFP_TCDCR = ( new_tcdcr & 0x70 ) | ( old_tcdcr & 0x07 ); /* we set TCCR and keep old TDDR in case we need to read it below */ 1.1.1.11 root 1824: MFP_StartTimerC(); /* start/stop timer depending on control reg */ 1825: } 1.1.1.8 root 1826: 1.1.1.12 root 1827: if ((old_tcdcr & 0x07) != (new_tcdcr & 0x07)) /* Timer D control changed */ 1.1.1.8 root 1828: { 1.1.1.11 root 1829: Uint32 pc = M68000_GetPC(); 1.1.1.8 root 1830: 1831: /* Need to change baud rate of RS232 emulation? */ 1832: if (ConfigureParams.RS232.bEnableRS232) 1833: { 1834: RS232_SetBaudRateFromTimerD(); 1835: } 1836: 1837: if (ConfigureParams.System.bPatchTimerD && !bAppliedTimerDPatch 1.1.1.11 root 1838: && pc >= TosAddress && pc <= TosAddress + TosSize) 1.1.1.8 root 1839: { 1.1.1.11 root 1840: /* Slow down Timer-D if set from TOS for the first time to gain 1841: * more desktop performance. 1842: * Obviously, we need to emulate all timers correctly but TOS sets 1843: * up Timer-D at a very high rate (every couple of instructions). 1844: * The interrupt isn't enabled but the emulator still needs to 1845: * process the interrupt table and this HALVES our frame rate!!! 1.1.1.8 root 1846: * Some games actually reference this timer but don't set it up 1.1.1.11 root 1847: * (eg Paradroid, Speedball I) so we simply intercept the Timer-D 1848: * setup code in TOS and fix the numbers with more 'laid-back' 1849: * values. This still keeps 100% compatibility */ 1.1.1.12 root 1850: if ( new_tcdcr & 0x07 ) /* apply patch only if timer D is being started */ 1851: { 1852: new_tcdcr = IoMem[0xfffa1d] = (IoMem[0xfffa1d] & 0xf0) | 7; 1.1.1.14 root 1853: bAppliedTimerDPatch = true; 1.1.1.12 root 1854: } 1.1.1.8 root 1855: } 1.1.1.11 root 1856: 1857: /* If we stop a timer which was in delay mode, we need to store the current value */ 1858: /* of the counter to be able to read it or to continue from where we left if the timer is */ 1859: /* restarted later without writing to the data register. */ 1860: if ((new_tcdcr & 0x07) == 0) 1.1.1.14 root 1861: MFP_ReadTimerD(true); /* Stores result in 'MFP_TD_MAINCOUNTER' */ 1.1.1.11 root 1862: 1863: MFP_TCDCR = new_tcdcr; /* set to new value before calling MFP_StartTimer */ 1.1.1.12 root 1864: MFP_StartTimerD(); /* start/stop timer depending on control reg */ 1.1.1.8 root 1865: } 1866: } 1867: 1868: /*-----------------------------------------------------------------------*/ 1.1.1.11 root 1869: /** 1870: * Handle write to timer A data register (0xfffa1f). 1871: */ 1.1.1.8 root 1872: void MFP_TimerAData_WriteByte(void) 1873: { 1.1.1.10 root 1874: M68000_WaitState(4); 1875: 1.1.1.8 root 1876: MFP_TADR = IoMem[0xfffa1f]; /* Store into data register */ 1.1.1.10 root 1877: 1.1.1.8 root 1878: if (MFP_TACR == 0) /* Now check if timer is running - if so do not set */ 1879: { 1880: MFP_TA_MAINCOUNTER = MFP_TADR; /* Timer is off, store to main counter */ 1.1.1.14 root 1881: TimerACanResume = false; /* we need to set a new int when timer start */ 1.1.1.8 root 1882: } 1.1.1.12 root 1883: 1.1.1.14 root 1884: if ( LOG_TRACE_LEVEL( TRACE_MFP_WRITE ) ) 1.1.1.12 root 1885: { 1.1.1.14 root 1886: int FrameCycles, HblCounterVideo, LineCycles; 1887: Video_GetPosition ( &FrameCycles , &HblCounterVideo , &LineCycles ); 1888: LOG_TRACE_PRINT("mfp write data reg A fa1f=0x%x new counter=0x%x video_cyc=%d %d@%d pc=%x instr_cycle %d\n" , 1889: MFP_TADR, MFP_TA_MAINCOUNTER, FrameCycles, LineCycles, HblCounterVideo, M68000_GetPC(), CurrentInstrCycles ); 1.1.1.12 root 1890: } 1.1.1.8 root 1891: } 1892: 1893: /*-----------------------------------------------------------------------*/ 1.1.1.11 root 1894: /** 1895: * Handle write to timer B data register (0xfffa21). 1896: */ 1.1.1.8 root 1897: void MFP_TimerBData_WriteByte(void) 1898: { 1.1.1.10 root 1899: M68000_WaitState(4); 1900: 1.1.1.8 root 1901: MFP_TBDR = IoMem[0xfffa21]; /* Store into data register */ 1.1.1.10 root 1902: 1.1.1.8 root 1903: if (MFP_TBCR == 0) /* Now check if timer is running - if so do not set */ 1904: { 1905: MFP_TB_MAINCOUNTER = MFP_TBDR; /* Timer is off, store to main counter */ 1.1.1.14 root 1906: TimerBCanResume = false; /* we need to set a new int when timer start */ 1.1.1.8 root 1907: } 1.1.1.12 root 1908: 1.1.1.14 root 1909: if ( LOG_TRACE_LEVEL( TRACE_MFP_WRITE ) ) 1.1.1.12 root 1910: { 1.1.1.14 root 1911: int FrameCycles, HblCounterVideo, LineCycles; 1912: Video_GetPosition ( &FrameCycles , &HblCounterVideo , &LineCycles ); 1913: LOG_TRACE_PRINT("mfp write data reg B fa21=0x%x new counter=0x%x video_cyc=%d %d@%d pc=%x instr_cycle %d\n" , 1914: MFP_TBDR, MFP_TB_MAINCOUNTER, FrameCycles, LineCycles, HblCounterVideo, M68000_GetPC(), CurrentInstrCycles ); 1.1.1.12 root 1915: } 1.1.1.8 root 1916: } 1917: 1918: /*-----------------------------------------------------------------------*/ 1.1.1.11 root 1919: /** 1920: * Handle write to timer C data register (0xfffa23). 1921: */ 1.1.1.8 root 1922: void MFP_TimerCData_WriteByte(void) 1923: { 1.1.1.10 root 1924: M68000_WaitState(4); 1925: 1.1.1.8 root 1926: MFP_TCDR = IoMem[0xfffa23]; /* Store into data register */ 1.1.1.10 root 1927: 1.1.1.8 root 1928: if ((MFP_TCDCR&0x70) == 0) /* Now check if timer is running - if so do not set */ 1929: { 1.1.1.11 root 1930: MFP_TC_MAINCOUNTER = MFP_TCDR; /* Timer is off, store to main counter */ 1.1.1.14 root 1931: TimerCCanResume = false; /* we need to set a new int when timer start */ 1.1.1.8 root 1932: } 1.1.1.12 root 1933: 1.1.1.14 root 1934: if ( LOG_TRACE_LEVEL( TRACE_MFP_WRITE ) ) 1.1.1.12 root 1935: { 1.1.1.14 root 1936: int FrameCycles, HblCounterVideo, LineCycles; 1937: Video_GetPosition ( &FrameCycles , &HblCounterVideo , &LineCycles ); 1938: LOG_TRACE_PRINT("mfp write data reg C fa23=0x%x new counter=0x%x video_cyc=%d %d@%d pc=%x instr_cycle %d\n" , 1939: MFP_TCDR, MFP_TC_MAINCOUNTER, FrameCycles, LineCycles, HblCounterVideo, M68000_GetPC(), CurrentInstrCycles ); 1.1.1.12 root 1940: } 1.1.1.8 root 1941: } 1942: 1943: /*-----------------------------------------------------------------------*/ 1.1.1.11 root 1944: /** 1945: * Handle write to timer D data register (0xfffa25). 1946: */ 1.1.1.8 root 1947: void MFP_TimerDData_WriteByte(void) 1948: { 1.1.1.11 root 1949: Uint32 pc = M68000_GetPC(); 1.1.1.8 root 1950: 1.1.1.10 root 1951: M68000_WaitState(4); 1952: 1.1.1.8 root 1953: /* Need to change baud rate of RS232 emulation? */ 1954: if (ConfigureParams.RS232.bEnableRS232 && (IoMem[0xfffa1d] & 0x07)) 1955: { 1956: RS232_SetBaudRateFromTimerD(); 1957: } 1958: 1959: /* Patch Timer-D for better performance? */ 1960: if (ConfigureParams.System.bPatchTimerD && pc >= TosAddress && pc <= TosAddress + TosSize) 1961: { 1962: nTimerDFakeValue = IoMem[0xfffa25]; 1963: IoMem[0xfffa25] = 0x64; /* Slow down the useless Timer-D setup from the bios */ 1964: } 1965: 1966: MFP_TDDR = IoMem[0xfffa25]; /* Store into data register */ 1967: if ((MFP_TCDCR&0x07) == 0) /* Now check if timer is running - if so do not set */ 1968: { 1.1.1.11 root 1969: MFP_TD_MAINCOUNTER = MFP_TDDR; /* Timer is off, store to main counter */ 1.1.1.14 root 1970: TimerDCanResume = false; /* we need to set a new int when timer start */ 1.1.1.8 root 1971: } 1.1.1.12 root 1972: 1.1.1.14 root 1973: if ( LOG_TRACE_LEVEL( TRACE_MFP_WRITE ) ) 1.1.1.12 root 1974: { 1.1.1.14 root 1975: int FrameCycles, HblCounterVideo, LineCycles; 1976: Video_GetPosition ( &FrameCycles , &HblCounterVideo , &LineCycles ); 1977: LOG_TRACE_PRINT("mfp write data reg D fa25=0x%x new counter=0x%x video_cyc=%d %d@%d pc=%x instr_cycle %d\n" , 1978: MFP_TDDR, MFP_TD_MAINCOUNTER, FrameCycles, LineCycles, HblCounterVideo, M68000_GetPC(), CurrentInstrCycles ); 1.1.1.12 root 1979: } 1.1.1.8 root 1980: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.