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

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

unix.superglobalmegacorp.com

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