// timer.cc 
//	Routines to emulate a hardware timer device.
//
//      A hardware timer generates a CPU interrupt every X milliseconds.
//      This means it can be used for implementing time-slicing.
//
//      We emulate a hardware timer by scheduling an interrupt to occur
//      every time stats->totalTicks has increased by TimerTicks.
//
//      In order to introduce some randomness into time-slicing, if "doRandom"
//      is set, then the interrupt is comes after a random number of ticks.
//
//	Remember -- nothing in here is part of Nachos.  It is just
//	an emulation for the hardware that Nachos is running on top of.
//
//  DO NOT CHANGE -- part of the machine emulation
//
// Copyright (c) 1992-1993 The Regents of the University of California.
// All rights reserved.  See copyright.h for copyright notice and limitation 
// of liability and disclaimer of warranty provisions.

#include "copyright.h"
#include "timer.h"
#include "system.h"

// dummy function because C++ does not allow pointers to member functions
static void TimerHandler(int arg)
{ Timer *p = (Timer *)arg; p->TimerExpired(); }

//----------------------------------------------------------------------
// Timer::Timer
//      Initialize a hardware timer device.  Save the place to call
//	on each interrupt, and then arrange for the timer to start
//	generating interrupts.
//
//      "timerHandler" is the interrupt handler for the timer device.
//		It is called with interrupts disabled every time the
//		the timer expires.
//      "callArg" is the parameter to be passed to the interrupt handler.
//      "doRandom" -- if true, arrange for the interrupts to occur
//		at random, instead of fixed, intervals.
//----------------------------------------------------------------------

Timer::Timer(VoidFunctionPtr timerHandler, int callArg, bool doRandom)
{
    randomize = doRandom;
    handler = timerHandler;
    arg = callArg; 

    // schedule the first interrupt from the timer device
    interrupt->Schedule(TimerHandler, (int) this, TimeOfNextInterrupt(), 
		TimerInt); 
}

//----------------------------------------------------------------------
// Timer::TimerExpired
//      Routine to simulate the interrupt generated by the hardware 
//	timer device.  Schedule the next interrupt, and invoke the
//	interrupt handler.
//----------------------------------------------------------------------
void  Timer::TimerExpired() 
{
    // schedule the next timer device interrupt
    interrupt->Schedule(TimerHandler, (int) this, TimeOfNextInterrupt(), 
		TimerInt);

    // invoke the Nachos interrupt handler for this device
    (*handler)(arg);
}

//----------------------------------------------------------------------
// Timer::TimeOfNextInterrupt
//      Return when the hardware timer device will next cause an interrupt.
//	If randomize is turned on, make it a (pseudo-)random delay.
//----------------------------------------------------------------------

int  Timer::TimeOfNextInterrupt() 
{
    if (randomize)
	return 1 + (Random() % (TimerTicks * 2));
    else
	return TimerTicks; 
}