Beispiel #1
0
void ldp::think_delay(unsigned int uMsDelay)
{
	bool bEmulatedCpu = (get_cpu_hz(0) != 0);	// whether we've got an emulated cpu

	// safety check: make sure that we're not using an emulated CPU
	if (bEmulatedCpu)
	{
		printline("think_delay() should not be used with an emulated CPU. Don't use blocking seeking maybe?");
		set_quitflag();
	}
	// safety check: make sure pre_init has already been called so that m_start_time has been initialized
	else if (!m_bPreInitCalled)
	{
		printline("think_delay() should not be called until pre_init() has been called.");
		set_quitflag();
	}

	// call pre_think the same # of times that uMsDelay tells us to,
	//  to ensure that we aren't caught sleeping during an important event
	for (unsigned int uMs = 0; uMs < uMsDelay; ++uMs)
	{
		pre_think();

		unsigned int uElapsedMs = elapsed_ms_time(m_start_time);

		// if we're ahead of where we need to be, then it's ok to stall ...
		if (uElapsedMs < m_uElapsedMsSinceStart)
		{
			/*
			string msg = "uElapsedMs is " + numstr::ToStr(uElapsedMs) + " and m_uElapsedMssinceStart is " +
				numstr::ToStr(m_uElapsedMsSinceStart);
			printline(msg.c_str());	// REMOVE ME
			*/

			MAKE_DELAY(1);
		}
		// otherwise we're caught up or behind, so just loop so we can make sure we're caught up
	}
}
Beispiel #2
0
clock_t uc3_clock (void)
{
  static U32 last_time=0;
  static U32 overflow=0;
  clock_t time;

  // Get the current time.
  U32 curr_time=Get_system_register(AVR32_COUNT);

  // Track overflow situation. We made the assumtion here that we can detect 1 overflow situation.
  // This is true if the function is called faster than the overflow time.
  // For example, with a CPU at 66 MHz, you must call the function before (1<<32)/66 MHz; i.e.
  // 65 seconds since the last function call.
  if( curr_time<last_time )
     overflow++;

  // Convert the current time into absolute UC3_CLOCKS_PER_SEC ticks, given the known overflow
  // situations.
  time = (U64)(( ((U64)overflow<<32) | curr_time) * UC3_CLOCKS_PER_SEC) / get_cpu_hz();

  // Save the time for the next function call.
  last_time = curr_time;
  return time;
}
Beispiel #3
0
static inline uint64_t ticks_to_us(uint64_t ticks)
{
  return (ticks * 1000000) / get_cpu_hz();
}
Beispiel #4
0
void ldp::pre_think()
{
	// IMPORTANT : By definition, this function must be called every millisecond to update the timer (it is called by our cpu emulation every 1 ms)
	// If it cannot be called every 1 ms (if we are not emulating a cpu for example), then ldp::think_delay() can be
	//  (and should be) used instead of calling this function directly.
	// IMPORTANT : this must be updated no matter what because vldp relies on this timer when we're paused

	// START VBLANK COUNT

	// at the end of this function, if vblank gets asserted, we need to call an event handler in the game class, but we
	//  need to do that after the frame number has been recalculated (if need be), hence the purpose of this variable.
	bool bVblankAsserted = false;

	++m_uElapsedMsSinceStart;

	// if it's time to increase the vblank count
	if (m_uElapsedMsSinceStart >= m_uMsVblankBoundary)
	{
		++m_uVblankCount;

		// compute the next boundary
		m_uMsVblankBoundary = (unsigned int) ((((Uint64) (m_uVblankCount+1)) * 1000000) / VBLANKS_PER_KILOSECOND);

		// only increment the mini count if we aren't waiting for vblank to start counting frames
		if (!m_bWaitingForVblankToPlay)
		{
			++m_uVblankMiniCount;
		}
		// else if we have been waiting for vblank to play, then make sure we reset the vblankminicount
		else
		{
			// we want to start at the beginning of a new frame boundary
			m_uVblankMiniCount = 0;

			// we just got a vblank, so we're not waiting ...
			m_bWaitingForVblankToPlay = false;
		}

		bVblankAsserted = true;
	}
	// END VBLANK COUNT

	// if we're not waiting to sync up with vblank, then increase timer
	// (this must be done even if we're paused so VLDP will update our video overlay)
	if (!m_bWaitingForVblankToPlay)
	{
		++m_uElapsedMsSincePlay;
	}

	// If the disc is supposed to be playing then compute which frame # we're on
	// IMPORTANT:
	// ldp-vldp.cpp's nonblocking_seek() RELIES on this function NOT calling get_status()!!!
	// Be very careful about changing this 'm_status' to a get_status()
	if (m_status == LDP_PLAYING)
	{
		unsigned int uDiscFPKS = g_game->get_disc_fpks();

		// if our frame counter is in sync with vblank, then just increment frame every 2 vblanks ...
		if ((uDiscFPKS << 1) == VBLANKS_PER_KILOSECOND)
		{
			// if we've had 2 vblanks, then 1 frame has elapsed
			if (m_uVblankMiniCount > 1)
			{
				increment_current_frame();
				m_uVblankMiniCount = 0;
			}
			// else we've not had enough vblanks, so don't do anything ...
		}

		// else if we're not in sync with the vblank (for example if we're dragon's lair with a 24 FPS disc),
		//  then use the elapsed ms since play to determine if the frame has changed
		else if (m_uElapsedMsSincePlay >= m_uMsFrameBoundary)
		{
			increment_current_frame();

			// compute the next boundary
			m_uMsFrameBoundary = (unsigned int) ((((Uint64) (m_uCurrentOffsetFrame+1)) * 1000000) / uDiscFPKS);
		}

		// else the current frame has not changed

#ifdef DEBUG
#ifndef GP2X	// GP2X is slow enough that we don't want to do this safety check by default
		// SAFETY CHECK
		// This ensures that the number that is calculated is not far off what it should be.
		// (this test is only meaningful if we are emulating a cpu, because otherwise we may deliberately
		//  be calling this function slower than every 1 ms, such as ffr() or vldp's internal tests )
		if (get_cpu_hz(0))
		{
			unsigned int uElapsedMS = elapsed_ms_time(m_play_time); // compute milliseconds
			unsigned int time_result = m_last_seeked_frame + m_iSkipOffsetSincePlay +
				(unsigned int) ((((Uint64) uElapsedMS) * g_game->get_disc_fpks()) / 1000000);
			Uint16 diff = 0;

			// this isn't necessarily the same as m_uCurrentFrame due to potential skips that can occur
			// (this is updated immediately, m_uCurrentFrame is updated on a time boundary)
			unsigned int uCurrentFrame = m_last_seeked_frame + m_iSkipOffsetSincePlay + m_uCurrentOffsetFrame;

			if (uCurrentFrame > time_result) diff = uCurrentFrame - time_result;
			else diff = time_result - uCurrentFrame;

			// if the difference is noticeable, then alert the developer
			if (diff > 5)
			{
				static unsigned int last_warning = 0;

				if (elapsed_ms_time(last_warning) > 1000)
				{
					string s = "WARNING : cycle frame is ";
					s += numstr::ToStr(uCurrentFrame) + " but time frame is ";
					s += numstr::ToStr(time_result) + " which has a diff of ";
					s += numstr::ToStr(diff);
					printline(s.c_str());
					last_warning = refresh_ms_time();
				}
			}
		}
#endif // not GP2X
#endif // DEBUG

	}
	// otherwise the disc is idle, so we need not change the current frame

	think();	// call implementation-specific function

	// If vblank was asserted, let game know about it...
	// NOTE : this should probably come at the end of this function
	if (bVblankAsserted)
	{
		// let game know about vblank ...
		g_game->OnVblank();
	}
}