#include "performanceTest.h"
#include "SupportAsm.h"

// Variable that gives you the realtime cpu frequency, updated in TMClock.c: _TimerISR()
extern volatile unsigned int _cpuFrequencyMHz; // CPU Frequency in MHz

void initPerformanceTest(PerformanceTest this)
{
  int boguscnt;

  /* VMware 2.0 doesn't support this function (it doesn't implement the CR4 register): */
  //__enableClockCountForUser();

  /* Calculate the number of cycles needed for a zero measurement.
  * We could use asm("cli") to disable interrupts and task switches, but
   * making so would limit the use of this function to kernel threads.
   * Second reason is that disabling interrupts is not a good idea if an other
   * method exists that doesn't touch to the interrupt flag.
  * This second method repeats the test until we are lucky and no interrupt or task switch
  * happened in between the start/stop pair. On my PC an average value of 35-40 cycles are
  * needed for the start/stop pair, but if we use VMWare the count can also reache 400 cycles.
  * For this reason we need a boguscnt */
  boguscnt = 20;
  do
  {
    this->errorCycles = 0; // important for zero measurement
    this->deltaMicroSeconds = 0;
    this->deltaCycles = 0;
    this->stopCycle = 0;
    this->startCycle = 0; // Last initialised -> we are sure
    // that this var is in L1 cache.
    startPerformanceTest(this);
    stopPerformanceTest(this);
    this->errorCycles = this->deltaCycles;
  }
  while ((this->errorCycles > 80) && (--boguscnt >= 0));

  if (this->errorCycles > 80)
  {
    /* Perhaps your are running VMware, so lower the constraints a bit */
    boguscnt = 20;
    do
    {
      this->errorCycles = 0; // important for zero measurement
      this->deltaMicroSeconds = 0;
      this->deltaCycles = 0;
      this->stopCycle = 0;
      this->startCycle = 0; // Last initialised -> we are sure
      // that this var is in L1 cache.
      startPerformanceTest(this);
      stopPerformanceTest(this);
      this->errorCycles = this->deltaCycles;
    }
    while ((this->errorCycles > 800) && (--boguscnt >= 0));
  }

  if (this->errorCycles > 800) /* give up */
    this->errorCycles = 0;

  this->deltaMicroSeconds = 0;
  this->deltaCycles = 0;
  this->stopCycle = 0;
  this->startCycle = 0; // Last initialised -> we are sure
  // that this var is in L1 cache.
}


inline void startPerformanceTest(PerformanceTest this)
{
  /* LR 001114 */
  //-LR 	this->startCycle = __getClockCount();
}


inline void stopPerformanceTest(PerformanceTest this)
{
  /* LR 001114 */
  //-LR 	this->stopCycle = __getClockCount();
  if ((this->stopCycle - this->startCycle) >= this->errorCycles)
    this->deltaCycles = this->stopCycle - this->startCycle - this->errorCycles;
  else
    this->deltaCycles = 0;

  /* LR 001114 */
  //-LR 	this->deltaMicroSeconds = (unsigned int)(this->deltaCycles)/_cpuFrequencyMHz;
}
