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

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

unix.superglobalmegacorp.com

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