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

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

unix.superglobalmegacorp.com

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