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

1.1       root        1: /*
1.1.1.3   root        2:   Hatari - int.c
                      3: 
                      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.
1.1       root        6: 
1.1.1.8   root        7:   This code handles our interrupt table. So we do not need to test for every
                      8:   possible interrupt we add any pending interrupts into a table. We then scan
                      9:   the list if used entries in the table and copy the one with the least cycle
                     10:   count into the global 'PendingInterruptCount' variable. This is then
                     11:   decremented by the execution loop - rather than decrement each and every
                     12:   entry (as the others cannot occur before this one).
                     13:   We have two methods of adding interrupts; Absolute and Relative.
                     14:   Absolute will set values from the time of the previous interrupt (e.g., add
                     15:   HBL every 512 cycles), and Relative will add from the current cycle time.
                     16:   Note that interrupt may occur 'late'. I.e., if an interrupt is due in 4
                     17:   cycles time but the current instruction takes 20 cycles we will be 16 cycles
                     18:   late - this is handled in the adjust functions.
                     19: 
                     20: 
                     21:   In order to handle both CPU and MFP interrupts, we don't convert MFP cyles to CPU cycles,
                     22:   because it requires some floating points approximation and accumulates some errors that
                     23:   could lead to bad results.
                     24:   Instead, CPU and MFP cycles are converted to 'internal' cycles with the following rule :
                     25:        - 1 CPU cycle gives  9600 internal cycles
                     26:        - 1 MFP cycle gives 31333 internal cycle
                     27: 
                     28:   All interrupts are then handled in the 'internal' units and are converted back to cpu or mfp
                     29:   units when needed. This allows very good synchronisation between CPU and MFP, without the
                     30:   rounding errors of floating points math.
                     31: 
                     32:   Thanks to Arnaud Carre (Leonard / Oxygene) for sharing this method used in Saint (and also
                     33:   used in sc68).
                     34: 
                     35:   Conversions are based on these values :
                     36:        real MFP frequency is 2457600 Hz
                     37:        real CPU frequency is 8021247 Hz (PAL european STF), which we round to 8021248.
                     38: 
                     39:   Then :
                     40:        8021248 = ( 2^8 * 31333 )
                     41:        2457600 = ( 2^15 * 3 * 5^2 )
                     42: 
                     43:   So, the ratio 8021248 / 2457600 can be expressed as 31333 / 9600
                     44: 
1.1       root       45: */
1.1.1.8   root       46: 
                     47: 
                     48: /* 2007/05/08  [NP]    Call Int_UpdateInterrupt in Int_AddRelativeInterrupt, because           */
                     49: /*                     Int_SetNewInterrupt can change the active int / PendingInterruptCount   */
                     50: /* 2007/09/29   [NP]    New method to handle interrupt. Instead of using cpu cycles to store   */
                     51: /*                     video int and MFP int (which looses precision because MFP cycles need   */
                     52: /*                     to be rounded to cpu cycles), we're using an 'internal' unit to store   */
                     53: /*                     both cpu cycles and mfp cycles. This removes floating point operations  */
                     54: /*                     and greatly improve the precision for MFP int with a very small divisor */
                     55: /*                     (thanks to Leonard / Oxygene for the idea, also used in 'sc68').        */
                     56: /* 2007/10/21  [NP]    Function 'Int_AddRelativeInterruptWithOffset' to restart an MFP timer   */
                     57: /*                     just after it expired (ULM DSOTS and Overscan Demos).                   */
                     58: /* 2007/10/28  [NP]    Function 'Int_ResumeStoppedInterrupt' to continue an interrupt from     */
                     59: /*                     where it was stopped, without updating 'cycles'.                        */
                     60: /* 2007/12/27  [NP]    Parameter 'AddInternalCycle' in Int_AddRelativeInterrupt, used in mfp.c */
                     61: /*                     to precisely start a timer after the current inst.                      */
1.1.1.9 ! root       62: /* 2008/03/30  [NP]    ActiveInterrupt was not saved in the memory snapshot, which could cause */
        !            63: /*                     errors when restoring it. We call Int_SetNewInterrupt() after restoring */
        !            64: /*                     the snapshot to set ActiveInterrupt to the correct value.               */
1.1.1.8   root       65: 
                     66: 
                     67: 
1.1.1.9 ! root       68: const char Int_rcsid[] = "Hatari $Id: int.c,v 1.31 2008/11/15 14:17:29 thothy Exp $";
1.1       root       69: 
1.1.1.9 ! root       70: #include <stdint.h>
1.1       root       71: #include "main.h"
1.1.1.9 ! root       72: #include "blitter.h"
1.1.1.6   root       73: #include "dmaSnd.h"
1.1.1.8   root       74: #include "fdc.h"
1.1       root       75: #include "ikbd.h"
                     76: #include "int.h"
                     77: #include "m68000.h"
                     78: #include "memorySnapShot.h"
                     79: #include "mfp.h"
                     80: #include "sound.h"
                     81: #include "video.h"
                     82: 
1.1.1.3   root       83: 
1.1.1.8   root       84: void (*PendingInterruptFunction)(void);
                     85: int PendingInterruptCount;
1.1.1.7   root       86: 
1.1.1.8   root       87: static int nCyclesOver;
1.1.1.7   root       88: 
1.1.1.8   root       89: /* List of possible interrupt handlers to be store in 'PendingInterruptTable',
                     90:  * used for 'MemorySnapShot' */
                     91: static void (* const pIntHandlerFunctions[MAX_INTERRUPTS])(void) =
                     92: {
                     93:        NULL,
                     94:        Video_InterruptHandler_VBL,
                     95:        Video_InterruptHandler_HBL,
                     96:        Video_InterruptHandler_EndLine,
                     97:        MFP_InterruptHandler_TimerA,
                     98:        MFP_InterruptHandler_TimerB,
                     99:        MFP_InterruptHandler_TimerC,
                    100:        MFP_InterruptHandler_TimerD,
                    101:        IKBD_InterruptHandler_ResetTimer,
                    102:        IKBD_InterruptHandler_ACIA,
1.1.1.9 ! root      103:        IKBD_InterruptHandler_MFP,
1.1.1.8   root      104:        DmaSnd_InterruptHandler,
1.1.1.9 ! root      105:        DmaSnd_InterruptHandler_Microwire,
        !           106:        FDC_InterruptHandler_Update,
        !           107:        Blitter_InterruptHandler
1.1       root      108: };
                    109: 
1.1.1.8   root      110: /* Event timer structure - keeps next timer to occur in structure so don't need
                    111:  * to check all entries */
1.1.1.7   root      112: typedef struct
                    113: {
1.1.1.9 ! root      114:        bool bUsed;                   /* Is interrupt active? */
        !           115:        Sint64 Cycles;
1.1.1.8   root      116:        void (*pFunction)(void);
1.1.1.7   root      117: } INTERRUPTHANDLER;
                    118: 
                    119: static INTERRUPTHANDLER InterruptHandlers[MAX_INTERRUPTS];
                    120: static int ActiveInterrupt=0;
1.1       root      121: 
1.1.1.9 ! root      122: static void Int_SetNewInterrupt(void);
1.1.1.2   root      123: 
                    124: /*-----------------------------------------------------------------------*/
1.1.1.8   root      125: /**
                    126:  * Reset interrupts, handlers
                    127:  */
1.1       root      128: void Int_Reset(void)
                    129: {
1.1.1.8   root      130:        int i;
1.1       root      131: 
1.1.1.8   root      132:        /* Reset counts */
                    133:        PendingInterruptCount = 0;
                    134:        ActiveInterrupt = 0;
                    135:        nCyclesOver = 0;
1.1       root      136: 
1.1.1.8   root      137:        /* Reset interrupt table */
                    138:        for (i=0; i<MAX_INTERRUPTS; i++)
                    139:        {
                    140:                InterruptHandlers[i].bUsed = FALSE;
1.1.1.9 ! root      141:                InterruptHandlers[i].Cycles = INT_MAX;
1.1.1.8   root      142:                InterruptHandlers[i].pFunction = pIntHandlerFunctions[i];
                    143:        }
1.1       root      144: }
                    145: 
1.1.1.2   root      146: 
                    147: /*-----------------------------------------------------------------------*/
1.1.1.8   root      148: /**
                    149:  * Convert interrupt handler function pointer to ID, used for saving
                    150:  */
                    151: static int Int_HandlerFunctionToID(void (*pHandlerFunction)(void))
1.1       root      152: {
1.1.1.8   root      153:        int i;
1.1       root      154: 
1.1.1.8   root      155:        /* Scan for function match */
                    156:        for (i=0; i<MAX_INTERRUPTS; i++)
                    157:        {
                    158:                if (pIntHandlerFunctions[i]==pHandlerFunction)
                    159:                        return i;
                    160:        }
                    161: 
                    162:        /* Didn't find one! Oops */
                    163:        fprintf(stderr, "\nError: didn't find interrupt function matching 0x%p\n",
                    164:                pHandlerFunction);
                    165:        return 0;
1.1       root      166: }
                    167: 
1.1.1.2   root      168: 
                    169: /*-----------------------------------------------------------------------*/
1.1.1.8   root      170: /**
                    171:  * Convert ID back into interrupt handler function, used for restoring
                    172:  */
                    173: static void *Int_IDToHandlerFunction(int ID)
1.1       root      174: {
1.1.1.8   root      175:        /* Get function pointer */
                    176:        return pIntHandlerFunctions[ID];
1.1       root      177: }
                    178: 
1.1.1.2   root      179: 
                    180: /*-----------------------------------------------------------------------*/
1.1.1.8   root      181: /**
                    182:  * Save/Restore snapshot of local variables('MemorySnapShot_Store' handles type)
                    183:  */
1.1.1.9 ! root      184: void Int_MemorySnapShot_Capture(bool bSave)
1.1       root      185: {
1.1.1.8   root      186:        int i,ID;
                    187: 
                    188:        /* Save/Restore details */
                    189:        for (i=0; i<MAX_INTERRUPTS; i++)
                    190:        {
                    191:                MemorySnapShot_Store(&InterruptHandlers[i].bUsed, sizeof(InterruptHandlers[i].bUsed));
                    192:                MemorySnapShot_Store(&InterruptHandlers[i].Cycles, sizeof(InterruptHandlers[i].Cycles));
                    193:                if (bSave)
                    194:                {
                    195:                        /* Convert function to ID */
                    196:                        ID = Int_HandlerFunctionToID(InterruptHandlers[i].pFunction);
                    197:                        MemorySnapShot_Store(&ID, sizeof(int));
                    198:                }
                    199:                else
                    200:                {
                    201:                        /* Convert ID to function */
                    202:                        MemorySnapShot_Store(&ID, sizeof(int));
                    203:                        InterruptHandlers[i].pFunction = Int_IDToHandlerFunction(ID);
                    204:                }
                    205:        }
                    206:        MemorySnapShot_Store(&nCyclesOver, sizeof(nCyclesOver));
                    207:        MemorySnapShot_Store(&PendingInterruptCount, sizeof(PendingInterruptCount));
                    208:        if (bSave)
                    209:        {
                    210:                /* Convert function to ID */
                    211:                ID = Int_HandlerFunctionToID(PendingInterruptFunction);
                    212:                MemorySnapShot_Store(&ID, sizeof(int));
                    213:        }
                    214:        else
                    215:        {
                    216:                /* Convert ID to function */
                    217:                MemorySnapShot_Store(&ID, sizeof(int));
                    218:                PendingInterruptFunction = Int_IDToHandlerFunction(ID);
                    219:        }
1.1.1.9 ! root      220: 
        !           221: 
        !           222:        if (!bSave)
        !           223:                Int_SetNewInterrupt();                  /* when restoring snapshot, compute current state after */
1.1       root      224: }
                    225: 
1.1.1.2   root      226: 
                    227: /*-----------------------------------------------------------------------*/
1.1.1.8   root      228: /**
1.1.1.9 ! root      229:  * Find next interrupt to occur, and store to global variables for decrement
        !           230:  * in instruction decode loop.
        !           231:  * Note: Although InterruptHandlers.Cycles and LowestCycleCount are 64 bit
        !           232:  * variables to get all the cycle counters right (e.g. the DMA sound counter
        !           233:  * can get very high), PendingInterruptCount is still a 32 bit variable for
        !           234:  * performance reasons (it's decremented after each CPU instruction).
        !           235:  * So we have to initialize LowestCycleCount with INT_MAX, not with INT64_MAX!
        !           236:  * Since there is always a VBL or HBL counter pending which fits fine into the
        !           237:  * 32 bit variable, we can be sure that we don't run into problems here.
1.1.1.8   root      238:  */
1.1.1.7   root      239: static void Int_SetNewInterrupt(void)
1.1       root      240: {
1.1.1.9 ! root      241:        Sint64 LowestCycleCount = INT_MAX;
        !           242:        interrupt_id LowestInterrupt = 0, i;
1.1       root      243: 
1.1.1.8   root      244:        HATARI_TRACE ( HATARI_TRACE_INT , "int set new in video_cyc=%d active_int=%d pending_count=%d\n",
                    245:                       Cycles_GetCounter(CYCLES_COUNTER_VIDEO), ActiveInterrupt, PendingInterruptCount );
1.1.1.2   root      246: 
1.1.1.8   root      247:        /* Find next interrupt to go off */
                    248:        for (i = 1; i < MAX_INTERRUPTS; i++)
                    249:        {
                    250:                /* Is interrupt pending? */
                    251:                if (InterruptHandlers[i].bUsed)
                    252:                {
                    253:                        if (InterruptHandlers[i].Cycles < LowestCycleCount)
                    254:                        {
                    255:                                LowestCycleCount = InterruptHandlers[i].Cycles;
                    256:                                LowestInterrupt = i;
                    257:                        }
                    258:                }
                    259:        }
1.1       root      260: 
1.1.1.8   root      261:        /* Set new counts, active interrupt */
                    262:        PendingInterruptCount = InterruptHandlers[LowestInterrupt].Cycles;
                    263:        PendingInterruptFunction = InterruptHandlers[LowestInterrupt].pFunction;
                    264:        ActiveInterrupt = LowestInterrupt;
                    265: 
                    266:        HATARI_TRACE ( HATARI_TRACE_INT , "int set new out video_cyc=%d active_int=%d pending_count=%d\n",
                    267:                       Cycles_GetCounter(CYCLES_COUNTER_VIDEO), ActiveInterrupt, PendingInterruptCount );
1.1       root      268: }
                    269: 
1.1.1.2   root      270: 
                    271: /*-----------------------------------------------------------------------*/
1.1.1.8   root      272: /**
                    273:  * Adjust all interrupt timings, MUST call Int_SetNewInterrupt after this.
                    274:  */
1.1.1.3   root      275: static void Int_UpdateInterrupt(void)
1.1       root      276: {
1.1.1.9 ! root      277:        Sint64 CycleSubtract;
1.1.1.8   root      278:        int i;
1.1       root      279: 
1.1.1.8   root      280:        /* Find out how many cycles we went over (<=0) */
                    281:        nCyclesOver = PendingInterruptCount;
                    282:        /* Calculate how many cycles have passed, included time we went over */
1.1.1.9 ! root      283:        CycleSubtract = InterruptHandlers[ActiveInterrupt].Cycles - nCyclesOver;
1.1       root      284: 
1.1.1.8   root      285:        /* Adjust table */
                    286:        for (i = 0; i < MAX_INTERRUPTS; i++)
                    287:        {
                    288:                if (InterruptHandlers[i].bUsed)
                    289:                        InterruptHandlers[i].Cycles -= CycleSubtract;
                    290:        }
                    291: 
1.1.1.9 ! root      292:        HATARI_TRACE ( HATARI_TRACE_INT , "int upd video_cyc=%d cycle_over=%d cycle_sub=%lld\n",
1.1.1.8   root      293:                       Cycles_GetCounter(CYCLES_COUNTER_VIDEO), nCyclesOver, CycleSubtract );
1.1       root      294: }
                    295: 
1.1.1.2   root      296: 
                    297: /*-----------------------------------------------------------------------*/
1.1.1.8   root      298: /**
                    299:  * Adjust all interrupt timings as 'ActiveInterrupt' has occured, and
                    300:  * remove from active list.
                    301:  */
1.1       root      302: void Int_AcknowledgeInterrupt(void)
                    303: {
1.1.1.8   root      304:        /* Update list cycle counts */
                    305:        Int_UpdateInterrupt();
1.1       root      306: 
1.1.1.8   root      307:        /* Disable interrupt entry which has just occured */
                    308:        InterruptHandlers[ActiveInterrupt].bUsed = FALSE;
1.1       root      309: 
1.1.1.8   root      310:        /* Set new */
                    311:        Int_SetNewInterrupt();
                    312: 
                    313:        HATARI_TRACE ( HATARI_TRACE_INT , "int ack video_cyc=%d active_int=%d active_cyc=%d pending_count=%d\n",
1.1.1.9 ! root      314:                       Cycles_GetCounter(CYCLES_COUNTER_VIDEO), ActiveInterrupt, (int)InterruptHandlers[ActiveInterrupt].Cycles, PendingInterruptCount );
1.1       root      315: }
                    316: 
1.1.1.2   root      317: 
                    318: /*-----------------------------------------------------------------------*/
1.1.1.8   root      319: /**
                    320:  * Add interrupt from time last one occurred.
                    321:  */
                    322: void Int_AddAbsoluteInterrupt(int CycleTime, int CycleType, interrupt_id Handler)
1.1       root      323: {
1.1.1.8   root      324:        /* Update list cycle counts before adding a new one, */
                    325:        /* since Int_SetNewInterrupt can change the active int / PendingInterruptCount */
                    326:        /* [NP] FIXME : not necessary ? */
                    327: //  if ( ( ActiveInterrupt > 0 ) && ( PendingInterruptCount > 0 ) )
                    328: //    Int_UpdateInterrupt();
                    329: 
                    330:        InterruptHandlers[Handler].bUsed = TRUE;
1.1.1.9 ! root      331:        InterruptHandlers[Handler].Cycles = INT_CONVERT_TO_INTERNAL((Sint64)CycleTime , CycleType) + nCyclesOver;
1.1.1.8   root      332: 
                    333:        /* Set new */
                    334:        Int_SetNewInterrupt();
1.1       root      335: 
1.1.1.9 ! root      336:        HATARI_TRACE ( HATARI_TRACE_INT , "int add abs video_cyc=%d handler=%d handler_cyc=%lld pending_count=%d\n",
1.1.1.8   root      337:                       Cycles_GetCounter(CYCLES_COUNTER_VIDEO), Handler, InterruptHandlers[Handler].Cycles, PendingInterruptCount );
1.1       root      338: }
                    339: 
1.1.1.2   root      340: 
                    341: /*-----------------------------------------------------------------------*/
1.1.1.8   root      342: /**
1.1.1.9 ! root      343:  * Add interrupt to occur from now.
1.1.1.8   root      344:  */
1.1.1.9 ! root      345: void Int_AddRelativeInterrupt(int CycleTime, int CycleType, interrupt_id Handler)
1.1       root      346: {
1.1.1.9 ! root      347:        Int_AddRelativeInterruptWithOffset(CycleTime, CycleType, Handler, 0);
1.1       root      348: }
                    349: 
1.1.1.2   root      350: 
                    351: /*-----------------------------------------------------------------------*/
1.1.1.8   root      352: /**
                    353:  * Add interrupt to occur from now without offset
                    354:  */
                    355: void Int_AddRelativeInterruptNoOffset(int CycleTime, int CycleType, interrupt_id Handler)
1.1       root      356: {
1.1.1.8   root      357:        /* Update list cycle counts before adding a new one, */
                    358:        /* since Int_SetNewInterrupt can change the active int / PendingInterruptCount */
                    359:        if ( ( ActiveInterrupt > 0 ) && ( PendingInterruptCount > 0 ) )
                    360:                Int_UpdateInterrupt();
                    361: 
                    362: //  nCyclesOver = 0;
                    363:        InterruptHandlers[Handler].bUsed = TRUE;
1.1.1.9 ! root      364:        InterruptHandlers[Handler].Cycles = INT_CONVERT_TO_INTERNAL((Sint64)CycleTime , CycleType) + PendingInterruptCount;
1.1       root      365: 
1.1.1.8   root      366:        /* Set new */
                    367:        Int_SetNewInterrupt();
                    368: 
1.1.1.9 ! root      369:        HATARI_TRACE ( HATARI_TRACE_INT , "int add rel no_off video_cyc=%d handler=%d handler_cyc=%lld pending_count=%d\n",
1.1.1.8   root      370:                       Cycles_GetCounter(CYCLES_COUNTER_VIDEO), Handler, InterruptHandlers[Handler].Cycles, PendingInterruptCount );
1.1       root      371: }
                    372: 
1.1.1.2   root      373: 
                    374: /*-----------------------------------------------------------------------*/
1.1.1.8   root      375: /**
1.1.1.9 ! root      376:  * Add interrupt to occur after CycleTime/CycleType + CycleOffset.
        !           377:  * CycleOffset can be used to add another delay to the resulting
        !           378:  * number of internal cycles (should be 0 most of the time, except in
        !           379:  * the MFP emulation to start timers precisely based on the number of
        !           380:  * cycles of the current instruction).
        !           381:  * This allows to restart an MFP timer just after it expired.
1.1.1.8   root      382:  */
                    383: void Int_AddRelativeInterruptWithOffset(int CycleTime, int CycleType, interrupt_id Handler, int CycleOffset)
1.1       root      384: {
1.1.1.8   root      385:        /* Update list cycle counts before adding a new one, */
                    386:        /* since Int_SetNewInterrupt can change the active int / PendingInterruptCount */
                    387:        if ( ( ActiveInterrupt > 0 ) && ( PendingInterruptCount > 0 ) )
                    388:                Int_UpdateInterrupt();
1.1       root      389: 
1.1.1.8   root      390:        InterruptHandlers[Handler].bUsed = TRUE;
1.1.1.9 ! root      391:        InterruptHandlers[Handler].Cycles = INT_CONVERT_TO_INTERNAL((Sint64)CycleTime , CycleType) + CycleOffset;
1.1.1.8   root      392: 
                    393:        /* Set new */
                    394:        Int_SetNewInterrupt();
                    395: 
1.1.1.9 ! root      396:        HATARI_TRACE ( HATARI_TRACE_INT , "int add rel offset video_cyc=%d handler=%d handler_cyc=%lld offset_cyc=%d pending_count=%d\n",
1.1.1.8   root      397:                       Cycles_GetCounter(CYCLES_COUNTER_VIDEO), Handler, InterruptHandlers[Handler].Cycles, CycleOffset, PendingInterruptCount );
1.1       root      398: }
                    399: 
1.1.1.2   root      400: 
                    401: /*-----------------------------------------------------------------------*/
1.1.1.8   root      402: /**
                    403:  * Remove a pending interrupt from our table
                    404:  */
                    405: void Int_RemovePendingInterrupt(interrupt_id Handler)
                    406: {
                    407:        /* Update list cycle counts, including the handler we want to remove */
                    408:        /* to be able to resume it later (for MFP timers) */
                    409:        Int_UpdateInterrupt();
                    410: 
                    411:        /* Stop interrupt after Int_UpdateInterrupt, for Int_ResumeStoppedInterrupt */
                    412:        InterruptHandlers[Handler].bUsed = FALSE;
                    413: 
                    414:        /* Set new */
                    415:        Int_SetNewInterrupt();
                    416: 
1.1.1.9 ! root      417:        HATARI_TRACE ( HATARI_TRACE_INT , "int remove pending video_cyc=%d handler=%d handler_cyc=%lld pending_count=%d\n",
1.1.1.8   root      418:                       Cycles_GetCounter(CYCLES_COUNTER_VIDEO), Handler, InterruptHandlers[Handler].Cycles, PendingInterruptCount );
                    419: }
                    420: 
                    421: 
                    422: /*-----------------------------------------------------------------------*/
                    423: /**
                    424:  * Resume a stopped interrupt from its current cycle count (for MFP timers)
                    425:  */
                    426: void Int_ResumeStoppedInterrupt(interrupt_id Handler)
1.1       root      427: {
1.1.1.8   root      428:        /* Restart interrupt */
                    429:        InterruptHandlers[Handler].bUsed = TRUE;
                    430: 
                    431:        /* Update list cycle counts */
                    432:        Int_UpdateInterrupt();
                    433:        /* Set new */
                    434:        Int_SetNewInterrupt();
                    435: 
1.1.1.9 ! root      436:        HATARI_TRACE ( HATARI_TRACE_INT , "int resume stopped video_cyc=%d handler=%d handler_cyc=%lld pending_count=%d\n",
1.1.1.8   root      437:                       Cycles_GetCounter(CYCLES_COUNTER_VIDEO), Handler, InterruptHandlers[Handler].Cycles, PendingInterruptCount );
                    438: }
                    439: 
                    440: 
                    441: /*-----------------------------------------------------------------------*/
                    442: /**
                    443:  * Return TRUE if interrupt is active in list
                    444:  */
1.1.1.9 ! root      445: bool Int_InterruptActive(interrupt_id Handler)
1.1.1.8   root      446: {
                    447:        /* Is timer active? */
                    448:        if (InterruptHandlers[Handler].bUsed)
                    449:                return TRUE;
                    450: 
                    451:        return FALSE;
                    452: }
                    453: 
                    454: 
                    455: /*-----------------------------------------------------------------------*/
                    456: /**
                    457:  * Return cycles passed for an interrupt handler
                    458:  */
                    459: int Int_FindCyclesPassed(interrupt_id Handler, int CycleType)
                    460: {
1.1.1.9 ! root      461:        Sint64 CyclesPassed, CyclesFromLastInterrupt;
1.1.1.8   root      462: 
                    463:        CyclesFromLastInterrupt = InterruptHandlers[ActiveInterrupt].Cycles - PendingInterruptCount;
                    464:        CyclesPassed = InterruptHandlers[Handler].Cycles - CyclesFromLastInterrupt;
1.1       root      465: 
1.1.1.9 ! root      466:        HATARI_TRACE ( HATARI_TRACE_INT , "int find passed cyc video_cyc=%d handler=%d last_cyc=%lld passed_cyc=%lld\n",
1.1.1.8   root      467:                       Cycles_GetCounter(CYCLES_COUNTER_VIDEO), Handler, CyclesFromLastInterrupt, CyclesPassed );
1.1       root      468: 
1.1.1.8   root      469:        return INT_CONVERT_FROM_INTERNAL ( CyclesPassed , CycleType ) ;
1.1       root      470: }

unix.superglobalmegacorp.com

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