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

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

unix.superglobalmegacorp.com

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