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

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

unix.superglobalmegacorp.com

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