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

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

unix.superglobalmegacorp.com

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