timerintr.c 4.81 KB

/**************************************************************************
 *									  *
 *		 Copyright (C) 1994, Silicon Graphics, Inc.		  *
 *									  *
 *  These coded instructions, statements, and computer programs  contain  *
 *  unpublished  proprietary  information of Silicon Graphics, Inc., and  *
 *  are protected by Federal copyright law.  They  may  not be disclosed  *
 *  to  third  parties  or copied or duplicated in any form, in whole or  *
 *  in part, without the prior written consent of Silicon Graphics, Inc.  *
 *									  *
 **************************************************************************/


#include <rmon.h>
#include "osint.h"

/* 
 * Global counter to keep track of elapsed ticks since calling 
 * TimerServicesInit
 */
OSTime	__osCurrentTime;
/* 
 * Global variable  for the count reigster value from last retrace 
 * interrupt
 */
u32	__osBaseCounter;

u32	__osViIntrCount;	/* # of  VI interrupts */

/* 
 * Global variable  for the count reigster value from last __osSetTimerIntr 
 */
u32	__osTimerCounter;

/* Global double-linked timer list structure */
OSTimer __osBaseTimer;
OSTimer *__osTimerList = &__osBaseTimer;

/*
 * Profiling variables, placed in this file so that profile code
 * doesn't get sucked in by makerom unnecessarily.
 */
#ifndef _FINALROM
OSMesgQueue 	__osProfTimerQ;
OSProf 		*__osProfileList;
OSProf 		*__osProfileListEnd;
u32 		__osProfileOverflowBin;
#endif

/* 
 * Initialize timer services global data structures
 */
void
__osTimerServicesInit(void)
{
    __osCurrentTime = 0;	/* Reset the current time counter */
    __osBaseCounter = 0;
    __osViIntrCount = 0;

    /* Initialize the global timer list */

    __osTimerList->next = __osTimerList->prev = __osTimerList;
    __osTimerList->interval = __osTimerList->value = (OSTime)0;
    __osTimerList->mq = (OSMesgQueue *)NULL;
    __osTimerList->msg = (OSMesg *)NULL;
}

/*
 * Processes the R4300 timer interrupt
 */
void
__osTimerInterrupt(void)
{
    OSTimer *t;
    u32	count, elapsed_cycles;

#ifndef _FINALROM
    /* profiler stuff */
    u32 pc;
    s32 offset;
    OSProf *prof = __osProfileList;
#endif 


    if (__osTimerList->next == __osTimerList)
	/* there is no active timer */
	return;

    for (;;) {
	t = __osTimerList->next;
	if (t == __osTimerList) {
	    /* timer list has been emptied */
	    __osSetCompare(0);
	    __osTimerCounter = 0;
	    break;
	}

	/* Compute time since timer was set */

	count = osGetCount();
	elapsed_cycles = count - __osTimerCounter;
	/* Have enough ticks gone by since timer was set? */
	__osTimerCounter = count;

	if ((OSTime)elapsed_cycles < t->value) {

	    /* not yet ready for next item on list */

	    t->value -= (OSTime)elapsed_cycles;
	    __osSetTimerIntr(t->value);
	    break;
	}

	/* Remove head of the list and process it */

	t->prev->next = t->next;
	t->next->prev = t->prev;
	t->next = NULL;
	t->prev = NULL;

	/* Send signal to wake up waiting threads */

	if (t->mq != NULL) {
#ifdef _FINALROM
	    (void)osSendMesg(t->mq, t->msg, OS_MESG_NOBLOCK);
	}
#else
	    if (t->mq != &__osProfTimerQ) {
		(void)osSendMesg(t->mq, t->msg, OS_MESG_NOBLOCK);
	    }
	    else {

		/*
		 *  Determine which bin to put pc in.
		 */

		pc = __osRunQueue->context.pc;

		for (prof = __osProfileList;
			prof < __osProfileListEnd; prof++) {
		    offset = (s32) (pc - (u32)prof->text_start);
		    if ((offset >= 0) && 
		        	((s32)((u32)(prof->text_end) - pc) > 0)) {
			++*((u16 *) ((offset >> 2) + prof->histo_base));
			goto __ProfDone;
		    }
		}
		++__osProfileOverflowBin;
	    }
	}

__ProfDone:

#endif /* _FINALROM */


	/* 
	 * if timer is set up to reload, compute next time timer
	 * should go off and inster it to the list 
	 */
	if (t->interval) {
	    t->value = t->interval;
	    __osInsertTimer(t);
	}
    }
}


void
__osSetTimerIntr(OSTime tim)
{

    OSTime NewTime;
    u32 savedMask;

#define WAIT_TIME 10 /* ¿¾¯Ä´À°¤¬É¬Í× */

    if( tim < OS_USEC_TO_CYCLES(WAIT_TIME) ) {
	tim = OS_USEC_TO_CYCLES(WAIT_TIME);
    }

    /* disable interrupts */

    savedMask = __osDisableInt();

    __osTimerCounter = osGetCount();
    NewTime = ((OSTime)(__osTimerCounter) + tim);

    __osSetCompare((u32)(NewTime));
    __osRestoreInt(savedMask);
}

OSTime
__osInsertTimer(OSTimer *t)
{
    OSTimer *timep;
    OSTime  tim;
    u32 savedMask;

    /* disable interrupts */

    savedMask = __osDisableInt();

    /* Insert the new timer into the sorted list */

    timep = __osTimerList->next;
    tim = t->value;

    for ( ; (timep != __osTimerList) && (tim > timep->value);
		timep = timep->next)
	tim -= timep->value;
    t->value = tim;
    if (timep != __osTimerList)
	timep->value -= tim;	/* Subtract off tim from the  */
    /* timer next to the new insted timer */
    t->next = timep;
    t->prev = timep->prev;
    timep->prev->next = t;
    timep->prev = t;

    __osRestoreInt(savedMask);

    return(tim);
}