Annotation of hatari/src/mfp.c, revision 1.1.1.21

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

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.