I'm working on an implementation for the DMG-01 (A.K.A gameboy 1989) on my github. I've already implemented both the APU and the PPU, with (almost) perfect timing on my pc (and the pc of my friends). However, when I run the emulator on one of my friend's pc, it runs twice as fast as mine or the rest of my friends.
The code for syncronizing the clock (between the gameboy and the pc it's running on) is as follows:
Clock.h Header File:
class Clock
{
// ...
public:
void SyncClock();
private:
/* API::LR35902_HZ_CLOCK is 4'194'304 */
using lr35902_clock_period = std::chrono::duration<int64_t, std::ratio<1, API::LR35902_HZ_CLOCK>>;
static constexpr lr35902_clock_period one_clock_period{1};
using clock = std::chrono::high_resolution_clock;
private:
decltype(clock::now()) _last_tick{std::chrono::time_point_cast<clock::duration>(clock::now() + one_clock_period)};
};
Clock.cpp file
void Clock::SyncClock()
{
// Sleep until one tick has passed.
std::this_thread::sleep_until(this->_last_tick);
// Use time_point_cast to convert (via truncation towards zero) back to
// the "native" duration of high_resolution_clock
this->_last_tick = std::chrono::time_point_cast<clock::duration>(this->_last_tick + one_clock_period);
}
Which gets called in main.cpp like this:
int main()
{
// ...
while (true)
{
// processor.Clock() returns the number of clocks it took for the processor to run the
// current instruction. We need to sleep this thread for each clock passed.
for (std::size_t current_clock = processor.Clock(); current_clock > 0; --current_clock)
{
clock.SyncClock();
}
}
// ...
}
Is there a reason why chrono in this case would be affected in a different way in other computers? Time is absolute, I would understand why in one pc, running the emulator would be slower, but why faster? I checked out the type of my clock (high_resolution_clock) but I don't see why this would be the case. Thanks!
I think you may be running into overflow under the hood of
<chrono>
.The expression:
is problematic.
clock
ishigh_resolution_clock
, and it is common for this to havenanoseconds
resolution.one_clock_period
has units of1/4'194'304
. The resultant expression will be atime_point
with aperiod
of1/8'192'000'000'000
.Using signed 64 bit integral types, the
max()
on such a precision is slightly over 13 days. So ifclock::now()
returns a.time_since_epoch()
greater than 13 days,_last_tick
is going to overflow, and may some times be negative (depending on how muchclock::now()
is beyond 13 days).To correct try casting
one_clock_period
to the precision ofclock
immediately: