/*
 *  ======== load.c ========
 *
 *! Revision History
 *! ================
 *! 28-Dec -2006 bf	modified for C64+ with time stamp counter.
 *! 22-Jul-2004 jc      changed cpuLoad calculation to avoid overflow.
 *! 13-Feb-2003 cz      added miniIdleLoop reset after each cpuLoad is calculated.
 *! 15-Jun-2001 kw      original.
 */

#include <csl_tsc.h>

#include "c64+load.h"

/*CPU Load Statistic window size in Kcycles */
volatile Uint32 loadWindow = 1000000;	
/*
 * 'miniIdleLoop' is the shortest time thru the IDL loop.  miniIdleLoop is initialized
 * to the max long unsigned value, and modified by the LOAD_idlefxn() when
 * it finds a shorter path.
 */
CSL_Uint64 miniIdleLoop = 0xfffffff;
CSL_Uint64        preTimeStamp = 0;
/*
 * 'cpuLoadInLastWindow' is the CPU load for the last measured window, 
 * this cpu load is automatically measured periodical according the 'loadWindow'
 */
volatile Int32 cpuLoadInLastWindow = 100;
/*
 * 'cpuLoadFromLastTime' is the CPU load from last memsurement trigger point 
 * to current measurement trigger point 
 * this load is manually measured by call function 'LOAD_getCpuLoadFromLastTime' 
 */
volatile Int32 cpuLoadFromLastTime = 100;

CSL_Uint64 	idleCountFromLastTime = 0;
CSL_Uint64 	idleCountInLastWindow = 0;

CSL_Uint64 	totalIdleCyclesFromLastTime = 0;
CSL_Uint64 	totalIdleCyclesInLastWindow = 0;
/*
 *  return CPU load in last measured window
 */
Int32 LOAD_getCpuLoadInLastWindow(void)
{
	if(cpuLoadInLastWindow<0)
		cpuLoadInLastWindow=0;
    return (cpuLoadInLastWindow);
}

/*
 *  Calculate the CPU load from last memsurement trigger point 
 * to current measurement trigger point 
 */
Int32 LOAD_getCpuLoadFromLastTime(void)
{
	cpuLoadFromLastTime = 100 - 100*(idleCountFromLastTime * miniIdleLoop) /totalIdleCyclesFromLastTime;
	idleCountFromLastTime = totalIdleCyclesFromLastTime = 0;

	if(cpuLoadFromLastTime<0)
		cpuLoadFromLastTime=0;
    return (cpuLoadFromLastTime);
}

/*
 *  ======== LOAD_idlefxn ========
 */
void LOAD_idlefxn(void)
{
    CSL_Uint64               currentTimeStamp = 0;
    CSL_Uint64               deltaTime;

    idleCountFromLastTime++;                   /* bump number of times thru IDL loop */
    idleCountInLastWindow++;                   /* bump number of times thru IDL loop */

    /*
     * Compute the time difference since the last call to LOAD_idlefxn.
     */
    currentTimeStamp = CSL_tscRead();
    deltaTime = currentTimeStamp - preTimeStamp;
    preTimeStamp = currentTimeStamp;
    
    totalIdleCyclesFromLastTime += deltaTime;   /* accumulate time */
    totalIdleCyclesInLastWindow += deltaTime;   /* accumulate time */

    /* 
     * 'miniIdleLoop' keeps track of the shortest time thru the IDL loop.
     * Note that we check to make sure deltaTime is not zero (deltaTime
     * will be zero during IDL loop calibration)
     */ 
    if (deltaTime != 0 && deltaTime < miniIdleLoop) {
        miniIdleLoop = deltaTime;
    }

    /*
     * Compute the CPU load if the time window has expired.
     */
    if (totalIdleCyclesInLastWindow > (loadWindow*1000))
    {
        cpuLoadInLastWindow = 100 - 100*(idleCountInLastWindow * miniIdleLoop) /totalIdleCyclesInLastWindow;
        idleCountInLastWindow = totalIdleCyclesInLastWindow = 0;
    } 
}
/*
 *  ======== LOAD_init ========
 */
void LOAD_init(void)
{
	//initialize miniIdleLoop
    preTimeStamp = CSL_tscRead();
}
/*
 * set measure window size
 */
void LOAD_setWindowSize(Uint32 windowSize)
{
	loadWindow= windowSize;
}
