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

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: 
1.1.1.10! root       67: const char Int_fileid[] = "Hatari int.c : " __DATE__ " " __TIME__;
1.1       root       68: 
1.1.1.9   root       69: #include <stdint.h>
1.1       root       70: #include "main.h"
1.1.1.9   root       71: #include "blitter.h"
1.1.1.6   root       72: #include "dmaSnd.h"
1.1.1.8   root       73: #include "fdc.h"
1.1       root       74: #include "ikbd.h"
                     75: #include "int.h"
                     76: #include "m68000.h"
                     77: #include "mfp.h"
1.1.1.10! root       78: #include "midi.h"
        !            79: #include "memorySnapShot.h"
1.1       root       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.10! root      104:        IKBD_InterruptHandler_AutoSend,
1.1.1.8   root      105:        DmaSnd_InterruptHandler,
1.1.1.9   root      106:        DmaSnd_InterruptHandler_Microwire,
                    107:        FDC_InterruptHandler_Update,
1.1.1.10! root      108:        Blitter_InterruptHandler,
        !           109:        Midi_InterruptHandler_Update
1.1       root      110: };
                    111: 
1.1.1.8   root      112: /* Event timer structure - keeps next timer to occur in structure so don't need
                    113:  * to check all entries */
1.1.1.7   root      114: typedef struct
                    115: {
1.1.1.9   root      116:        bool bUsed;                   /* Is interrupt active? */
                    117:        Sint64 Cycles;
1.1.1.8   root      118:        void (*pFunction)(void);
1.1.1.7   root      119: } INTERRUPTHANDLER;
                    120: 
                    121: static INTERRUPTHANDLER InterruptHandlers[MAX_INTERRUPTS];
                    122: static int ActiveInterrupt=0;
1.1       root      123: 
1.1.1.9   root      124: static void Int_SetNewInterrupt(void);
1.1.1.2   root      125: 
                    126: /*-----------------------------------------------------------------------*/
1.1.1.8   root      127: /**
                    128:  * Reset interrupts, handlers
                    129:  */
1.1       root      130: void Int_Reset(void)
                    131: {
1.1.1.8   root      132:        int i;
1.1       root      133: 
1.1.1.8   root      134:        /* Reset counts */
                    135:        PendingInterruptCount = 0;
                    136:        ActiveInterrupt = 0;
                    137:        nCyclesOver = 0;
1.1       root      138: 
1.1.1.8   root      139:        /* Reset interrupt table */
                    140:        for (i=0; i<MAX_INTERRUPTS; i++)
                    141:        {
                    142:                InterruptHandlers[i].bUsed = FALSE;
1.1.1.9   root      143:                InterruptHandlers[i].Cycles = INT_MAX;
1.1.1.8   root      144:                InterruptHandlers[i].pFunction = pIntHandlerFunctions[i];
                    145:        }
1.1       root      146: }
                    147: 
1.1.1.2   root      148: 
                    149: /*-----------------------------------------------------------------------*/
1.1.1.8   root      150: /**
                    151:  * Convert interrupt handler function pointer to ID, used for saving
                    152:  */
                    153: static int Int_HandlerFunctionToID(void (*pHandlerFunction)(void))
1.1       root      154: {
1.1.1.8   root      155:        int i;
1.1       root      156: 
1.1.1.8   root      157:        /* Scan for function match */
                    158:        for (i=0; i<MAX_INTERRUPTS; i++)
                    159:        {
                    160:                if (pIntHandlerFunctions[i]==pHandlerFunction)
                    161:                        return i;
                    162:        }
                    163: 
                    164:        /* Didn't find one! Oops */
                    165:        fprintf(stderr, "\nError: didn't find interrupt function matching 0x%p\n",
                    166:                pHandlerFunction);
                    167:        return 0;
1.1       root      168: }
                    169: 
1.1.1.2   root      170: 
                    171: /*-----------------------------------------------------------------------*/
1.1.1.8   root      172: /**
                    173:  * Convert ID back into interrupt handler function, used for restoring
                    174:  */
                    175: static void *Int_IDToHandlerFunction(int ID)
1.1       root      176: {
1.1.1.8   root      177:        /* Get function pointer */
                    178:        return pIntHandlerFunctions[ID];
1.1       root      179: }
                    180: 
1.1.1.2   root      181: 
                    182: /*-----------------------------------------------------------------------*/
1.1.1.8   root      183: /**
                    184:  * Save/Restore snapshot of local variables('MemorySnapShot_Store' handles type)
                    185:  */
1.1.1.9   root      186: void Int_MemorySnapShot_Capture(bool bSave)
1.1       root      187: {
1.1.1.8   root      188:        int i,ID;
                    189: 
                    190:        /* Save/Restore details */
                    191:        for (i=0; i<MAX_INTERRUPTS; i++)
                    192:        {
                    193:                MemorySnapShot_Store(&InterruptHandlers[i].bUsed, sizeof(InterruptHandlers[i].bUsed));
                    194:                MemorySnapShot_Store(&InterruptHandlers[i].Cycles, sizeof(InterruptHandlers[i].Cycles));
                    195:                if (bSave)
                    196:                {
                    197:                        /* Convert function to ID */
                    198:                        ID = Int_HandlerFunctionToID(InterruptHandlers[i].pFunction);
                    199:                        MemorySnapShot_Store(&ID, sizeof(int));
                    200:                }
                    201:                else
                    202:                {
                    203:                        /* Convert ID to function */
                    204:                        MemorySnapShot_Store(&ID, sizeof(int));
                    205:                        InterruptHandlers[i].pFunction = Int_IDToHandlerFunction(ID);
                    206:                }
                    207:        }
                    208:        MemorySnapShot_Store(&nCyclesOver, sizeof(nCyclesOver));
                    209:        MemorySnapShot_Store(&PendingInterruptCount, sizeof(PendingInterruptCount));
                    210:        if (bSave)
                    211:        {
                    212:                /* Convert function to ID */
                    213:                ID = Int_HandlerFunctionToID(PendingInterruptFunction);
                    214:                MemorySnapShot_Store(&ID, sizeof(int));
                    215:        }
                    216:        else
                    217:        {
                    218:                /* Convert ID to function */
                    219:                MemorySnapShot_Store(&ID, sizeof(int));
                    220:                PendingInterruptFunction = Int_IDToHandlerFunction(ID);
                    221:        }
1.1.1.9   root      222: 
                    223: 
                    224:        if (!bSave)
                    225:                Int_SetNewInterrupt();                  /* when restoring snapshot, compute current state after */
1.1       root      226: }
                    227: 
1.1.1.2   root      228: 
                    229: /*-----------------------------------------------------------------------*/
1.1.1.8   root      230: /**
1.1.1.9   root      231:  * Find next interrupt to occur, and store to global variables for decrement
                    232:  * in instruction decode loop.
                    233:  * Note: Although InterruptHandlers.Cycles and LowestCycleCount are 64 bit
                    234:  * variables to get all the cycle counters right (e.g. the DMA sound counter
                    235:  * can get very high), PendingInterruptCount is still a 32 bit variable for
                    236:  * performance reasons (it's decremented after each CPU instruction).
                    237:  * So we have to initialize LowestCycleCount with INT_MAX, not with INT64_MAX!
                    238:  * Since there is always a VBL or HBL counter pending which fits fine into the
                    239:  * 32 bit variable, we can be sure that we don't run into problems here.
1.1.1.8   root      240:  */
1.1.1.7   root      241: static void Int_SetNewInterrupt(void)
1.1       root      242: {
1.1.1.9   root      243:        Sint64 LowestCycleCount = INT_MAX;
                    244:        interrupt_id LowestInterrupt = 0, i;
1.1       root      245: 
1.1.1.8   root      246:        HATARI_TRACE ( HATARI_TRACE_INT , "int set new in video_cyc=%d active_int=%d pending_count=%d\n",
                    247:                       Cycles_GetCounter(CYCLES_COUNTER_VIDEO), ActiveInterrupt, PendingInterruptCount );
1.1.1.2   root      248: 
1.1.1.8   root      249:        /* Find next interrupt to go off */
                    250:        for (i = 1; i < MAX_INTERRUPTS; i++)
                    251:        {
                    252:                /* Is interrupt pending? */
                    253:                if (InterruptHandlers[i].bUsed)
                    254:                {
                    255:                        if (InterruptHandlers[i].Cycles < LowestCycleCount)
                    256:                        {
                    257:                                LowestCycleCount = InterruptHandlers[i].Cycles;
                    258:                                LowestInterrupt = i;
                    259:                        }
                    260:                }
                    261:        }
1.1       root      262: 
1.1.1.8   root      263:        /* Set new counts, active interrupt */
                    264:        PendingInterruptCount = InterruptHandlers[LowestInterrupt].Cycles;
                    265:        PendingInterruptFunction = InterruptHandlers[LowestInterrupt].pFunction;
                    266:        ActiveInterrupt = LowestInterrupt;
                    267: 
                    268:        HATARI_TRACE ( HATARI_TRACE_INT , "int set new out video_cyc=%d active_int=%d pending_count=%d\n",
                    269:                       Cycles_GetCounter(CYCLES_COUNTER_VIDEO), ActiveInterrupt, PendingInterruptCount );
1.1       root      270: }
                    271: 
1.1.1.2   root      272: 
                    273: /*-----------------------------------------------------------------------*/
1.1.1.8   root      274: /**
                    275:  * Adjust all interrupt timings, MUST call Int_SetNewInterrupt after this.
                    276:  */
1.1.1.3   root      277: static void Int_UpdateInterrupt(void)
1.1       root      278: {
1.1.1.9   root      279:        Sint64 CycleSubtract;
1.1.1.8   root      280:        int i;
1.1       root      281: 
1.1.1.8   root      282:        /* Find out how many cycles we went over (<=0) */
                    283:        nCyclesOver = PendingInterruptCount;
                    284:        /* Calculate how many cycles have passed, included time we went over */
1.1.1.9   root      285:        CycleSubtract = InterruptHandlers[ActiveInterrupt].Cycles - nCyclesOver;
1.1       root      286: 
1.1.1.8   root      287:        /* Adjust table */
                    288:        for (i = 0; i < MAX_INTERRUPTS; i++)
                    289:        {
                    290:                if (InterruptHandlers[i].bUsed)
                    291:                        InterruptHandlers[i].Cycles -= CycleSubtract;
                    292:        }
                    293: 
1.1.1.9   root      294:        HATARI_TRACE ( HATARI_TRACE_INT , "int upd video_cyc=%d cycle_over=%d cycle_sub=%lld\n",
1.1.1.8   root      295:                       Cycles_GetCounter(CYCLES_COUNTER_VIDEO), nCyclesOver, CycleSubtract );
1.1       root      296: }
                    297: 
1.1.1.2   root      298: 
                    299: /*-----------------------------------------------------------------------*/
1.1.1.8   root      300: /**
                    301:  * Adjust all interrupt timings as 'ActiveInterrupt' has occured, and
                    302:  * remove from active list.
                    303:  */
1.1       root      304: void Int_AcknowledgeInterrupt(void)
                    305: {
1.1.1.8   root      306:        /* Update list cycle counts */
                    307:        Int_UpdateInterrupt();
1.1       root      308: 
1.1.1.8   root      309:        /* Disable interrupt entry which has just occured */
                    310:        InterruptHandlers[ActiveInterrupt].bUsed = FALSE;
1.1       root      311: 
1.1.1.8   root      312:        /* Set new */
                    313:        Int_SetNewInterrupt();
                    314: 
                    315:        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      316:                       Cycles_GetCounter(CYCLES_COUNTER_VIDEO), ActiveInterrupt, (int)InterruptHandlers[ActiveInterrupt].Cycles, PendingInterruptCount );
1.1       root      317: }
                    318: 
1.1.1.2   root      319: 
                    320: /*-----------------------------------------------------------------------*/
1.1.1.8   root      321: /**
                    322:  * Add interrupt from time last one occurred.
                    323:  */
                    324: void Int_AddAbsoluteInterrupt(int CycleTime, int CycleType, interrupt_id Handler)
1.1       root      325: {
1.1.1.8   root      326:        /* Update list cycle counts before adding a new one, */
                    327:        /* since Int_SetNewInterrupt can change the active int / PendingInterruptCount */
                    328:        /* [NP] FIXME : not necessary ? */
                    329: //  if ( ( ActiveInterrupt > 0 ) && ( PendingInterruptCount > 0 ) )
                    330: //    Int_UpdateInterrupt();
                    331: 
                    332:        InterruptHandlers[Handler].bUsed = TRUE;
1.1.1.9   root      333:        InterruptHandlers[Handler].Cycles = INT_CONVERT_TO_INTERNAL((Sint64)CycleTime , CycleType) + nCyclesOver;
1.1.1.8   root      334: 
                    335:        /* Set new */
                    336:        Int_SetNewInterrupt();
1.1       root      337: 
1.1.1.9   root      338:        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      339:                       Cycles_GetCounter(CYCLES_COUNTER_VIDEO), Handler, InterruptHandlers[Handler].Cycles, PendingInterruptCount );
1.1       root      340: }
                    341: 
1.1.1.2   root      342: 
                    343: /*-----------------------------------------------------------------------*/
1.1.1.8   root      344: /**
1.1.1.9   root      345:  * Add interrupt to occur from now.
1.1.1.8   root      346:  */
1.1.1.9   root      347: void Int_AddRelativeInterrupt(int CycleTime, int CycleType, interrupt_id Handler)
1.1       root      348: {
1.1.1.9   root      349:        Int_AddRelativeInterruptWithOffset(CycleTime, CycleType, Handler, 0);
1.1       root      350: }
                    351: 
1.1.1.2   root      352: 
                    353: /*-----------------------------------------------------------------------*/
1.1.1.8   root      354: /**
                    355:  * Add interrupt to occur from now without offset
                    356:  */
                    357: void Int_AddRelativeInterruptNoOffset(int CycleTime, int CycleType, interrupt_id Handler)
1.1       root      358: {
1.1.1.8   root      359:        /* Update list cycle counts before adding a new one, */
                    360:        /* since Int_SetNewInterrupt can change the active int / PendingInterruptCount */
                    361:        if ( ( ActiveInterrupt > 0 ) && ( PendingInterruptCount > 0 ) )
                    362:                Int_UpdateInterrupt();
                    363: 
                    364: //  nCyclesOver = 0;
                    365:        InterruptHandlers[Handler].bUsed = TRUE;
1.1.1.9   root      366:        InterruptHandlers[Handler].Cycles = INT_CONVERT_TO_INTERNAL((Sint64)CycleTime , CycleType) + PendingInterruptCount;
1.1       root      367: 
1.1.1.8   root      368:        /* Set new */
                    369:        Int_SetNewInterrupt();
                    370: 
1.1.1.9   root      371:        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      372:                       Cycles_GetCounter(CYCLES_COUNTER_VIDEO), Handler, InterruptHandlers[Handler].Cycles, PendingInterruptCount );
1.1       root      373: }
                    374: 
1.1.1.2   root      375: 
                    376: /*-----------------------------------------------------------------------*/
1.1.1.8   root      377: /**
1.1.1.9   root      378:  * Add interrupt to occur after CycleTime/CycleType + CycleOffset.
                    379:  * CycleOffset can be used to add another delay to the resulting
                    380:  * number of internal cycles (should be 0 most of the time, except in
                    381:  * the MFP emulation to start timers precisely based on the number of
                    382:  * cycles of the current instruction).
                    383:  * This allows to restart an MFP timer just after it expired.
1.1.1.8   root      384:  */
                    385: void Int_AddRelativeInterruptWithOffset(int CycleTime, int CycleType, interrupt_id Handler, int CycleOffset)
1.1       root      386: {
1.1.1.8   root      387:        /* Update list cycle counts before adding a new one, */
                    388:        /* since Int_SetNewInterrupt can change the active int / PendingInterruptCount */
                    389:        if ( ( ActiveInterrupt > 0 ) && ( PendingInterruptCount > 0 ) )
                    390:                Int_UpdateInterrupt();
1.1       root      391: 
1.1.1.8   root      392:        InterruptHandlers[Handler].bUsed = TRUE;
1.1.1.9   root      393:        InterruptHandlers[Handler].Cycles = INT_CONVERT_TO_INTERNAL((Sint64)CycleTime , CycleType) + CycleOffset;
1.1.1.8   root      394: 
                    395:        /* Set new */
                    396:        Int_SetNewInterrupt();
                    397: 
1.1.1.9   root      398:        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      399:                       Cycles_GetCounter(CYCLES_COUNTER_VIDEO), Handler, InterruptHandlers[Handler].Cycles, CycleOffset, PendingInterruptCount );
1.1       root      400: }
                    401: 
1.1.1.2   root      402: 
                    403: /*-----------------------------------------------------------------------*/
1.1.1.8   root      404: /**
                    405:  * Remove a pending interrupt from our table
                    406:  */
                    407: void Int_RemovePendingInterrupt(interrupt_id Handler)
                    408: {
                    409:        /* Update list cycle counts, including the handler we want to remove */
                    410:        /* to be able to resume it later (for MFP timers) */
                    411:        Int_UpdateInterrupt();
                    412: 
                    413:        /* Stop interrupt after Int_UpdateInterrupt, for Int_ResumeStoppedInterrupt */
                    414:        InterruptHandlers[Handler].bUsed = FALSE;
                    415: 
                    416:        /* Set new */
                    417:        Int_SetNewInterrupt();
                    418: 
1.1.1.9   root      419:        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      420:                       Cycles_GetCounter(CYCLES_COUNTER_VIDEO), Handler, InterruptHandlers[Handler].Cycles, PendingInterruptCount );
                    421: }
                    422: 
                    423: 
                    424: /*-----------------------------------------------------------------------*/
                    425: /**
                    426:  * Resume a stopped interrupt from its current cycle count (for MFP timers)
                    427:  */
                    428: void Int_ResumeStoppedInterrupt(interrupt_id Handler)
1.1       root      429: {
1.1.1.8   root      430:        /* Restart interrupt */
                    431:        InterruptHandlers[Handler].bUsed = TRUE;
                    432: 
                    433:        /* Update list cycle counts */
                    434:        Int_UpdateInterrupt();
                    435:        /* Set new */
                    436:        Int_SetNewInterrupt();
                    437: 
1.1.1.9   root      438:        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      439:                       Cycles_GetCounter(CYCLES_COUNTER_VIDEO), Handler, InterruptHandlers[Handler].Cycles, PendingInterruptCount );
                    440: }
                    441: 
                    442: 
                    443: /*-----------------------------------------------------------------------*/
                    444: /**
                    445:  * Return TRUE if interrupt is active in list
                    446:  */
1.1.1.9   root      447: bool Int_InterruptActive(interrupt_id Handler)
1.1.1.8   root      448: {
                    449:        /* Is timer active? */
                    450:        if (InterruptHandlers[Handler].bUsed)
                    451:                return TRUE;
                    452: 
                    453:        return FALSE;
                    454: }
                    455: 
                    456: 
                    457: /*-----------------------------------------------------------------------*/
                    458: /**
                    459:  * Return cycles passed for an interrupt handler
                    460:  */
                    461: int Int_FindCyclesPassed(interrupt_id Handler, int CycleType)
                    462: {
1.1.1.9   root      463:        Sint64 CyclesPassed, CyclesFromLastInterrupt;
1.1.1.8   root      464: 
                    465:        CyclesFromLastInterrupt = InterruptHandlers[ActiveInterrupt].Cycles - PendingInterruptCount;
                    466:        CyclesPassed = InterruptHandlers[Handler].Cycles - CyclesFromLastInterrupt;
1.1       root      467: 
1.1.1.9   root      468:        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      469:                       Cycles_GetCounter(CYCLES_COUNTER_VIDEO), Handler, CyclesFromLastInterrupt, CyclesPassed );
1.1       root      470: 
1.1.1.8   root      471:        return INT_CONVERT_FROM_INTERNAL ( CyclesPassed , CycleType ) ;
1.1       root      472: }

unix.superglobalmegacorp.com

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