126 lines
2.7 KiB
C++
126 lines
2.7 KiB
C++
// Meteor - A Nintendo Gameboy Advance emulator
|
|
// Copyright (C) 2009-2011 Philippe Daouadi
|
|
//
|
|
// This program is free software: you can redistribute it and/or modify
|
|
// it under the terms of the GNU General Public License as published by
|
|
// the Free Software Foundation, either version 3 of the License, or
|
|
// (at your option) any later version.
|
|
//
|
|
// This program is distributed in the hope that it will be useful,
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
// GNU General Public License for more details.
|
|
//
|
|
// You should have received a copy of the GNU General Public License
|
|
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
#include "ameteor/clock.hpp"
|
|
#include "globals.hpp"
|
|
#include "ameteor.hpp"
|
|
|
|
#include "debug.hpp"
|
|
|
|
namespace AMeteor
|
|
{
|
|
void Clock::Reset ()
|
|
{
|
|
// lcd is enabled by default
|
|
m_first = m_count = m_cycles = m_lcd = m_sound = 0;
|
|
// timers and battery are disabled by default
|
|
/*m_battery =*/ m_timer[0] = m_timer[1] = m_timer[2] = m_timer[3] =
|
|
INT_MAX;
|
|
}
|
|
|
|
void Clock::Commit ()
|
|
{
|
|
unsigned short tocommit;
|
|
|
|
//m_count += m_cycles;
|
|
|
|
// this loop is here because a timer can trigger a dma which will take a
|
|
// long time, during this time the lcd must draw and the timers continue
|
|
while (m_cycles >= m_first)
|
|
{
|
|
m_count += m_cycles;
|
|
|
|
tocommit = m_cycles;
|
|
m_cycles = 0;
|
|
|
|
m_lcd -= tocommit;
|
|
while (m_lcd <= 0)
|
|
LCD.TimeEvent();
|
|
|
|
m_sound -= tocommit;
|
|
while (m_sound <= 0)
|
|
{
|
|
SOUND.TimeEvent();
|
|
// XXX freq
|
|
m_sound += SOUND_PERIOD;
|
|
}
|
|
|
|
#define COMMIT(dev, obj) \
|
|
if (m_##dev != INT_MAX) \
|
|
{ \
|
|
m_##dev -= tocommit; \
|
|
while (m_##dev <= 0) \
|
|
obj.TimeEvent(); \
|
|
}
|
|
COMMIT(timer[0], TIMER0)
|
|
COMMIT(timer[1], TIMER1)
|
|
COMMIT(timer[2], TIMER2)
|
|
COMMIT(timer[3], TIMER3)
|
|
//COMMIT(battery, MEM)
|
|
#undef COMMIT
|
|
|
|
SetFirst();
|
|
}
|
|
}
|
|
|
|
void Clock::WaitForNext ()
|
|
{
|
|
m_cycles = m_first;
|
|
Commit();
|
|
}
|
|
|
|
#define SETFIRST(dev) \
|
|
if (m_##dev < m_first) \
|
|
m_first = m_##dev
|
|
void Clock::SetFirst ()
|
|
{
|
|
m_first = m_lcd;
|
|
SETFIRST(timer[0]);
|
|
SETFIRST(timer[1]);
|
|
SETFIRST(timer[2]);
|
|
SETFIRST(timer[3]);
|
|
SETFIRST(sound);
|
|
//SETFIRST(battery);
|
|
}
|
|
#undef SETFIRST
|
|
|
|
bool Clock::SaveState (std::ostream& stream)
|
|
{
|
|
SS_WRITE_VAR(m_cycles);
|
|
SS_WRITE_VAR(m_first);
|
|
SS_WRITE_VAR(m_lcd);
|
|
SS_WRITE_VAR(m_sound);
|
|
//SS_WRITE_VAR(m_battery);
|
|
|
|
SS_WRITE_ARRAY(m_timer);
|
|
|
|
return true;
|
|
}
|
|
|
|
bool Clock::LoadState (std::istream& stream)
|
|
{
|
|
SS_READ_VAR(m_cycles);
|
|
SS_READ_VAR(m_first);
|
|
SS_READ_VAR(m_lcd);
|
|
SS_READ_VAR(m_sound);
|
|
//SS_READ_VAR(m_battery);
|
|
|
|
SS_READ_ARRAY(m_timer);
|
|
|
|
return true;
|
|
}
|
|
}
|