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

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

unix.superglobalmegacorp.com

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