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

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

unix.superglobalmegacorp.com

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