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

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

unix.superglobalmegacorp.com

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