Annotation of hatari/src/cycInt.c, revision 1.1.1.7

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

unix.superglobalmegacorp.com

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