(video) Update lyc_irq.cpp

This commit is contained in:
twinaphex 2015-02-17 22:05:38 +01:00
parent 1078477c45
commit 9bc71a1d3b
3 changed files with 153 additions and 100 deletions

View File

@ -0,0 +1,28 @@
#ifndef LCDDEF_H
#define LCDDEF_H
namespace gambatte
{
enum
{
LCDC_BGEN = 0x01,
LCDC_OBJEN = 0x02,
LCDC_OBJ2X = 0x04,
LCDC_TDSEL = 0x10,
LCDC_WE = 0x20,
LCDC_EN = 0x80
};
enum
{
LCDSTAT_LYCFLAG = 0x04,
LCDSTAT_M0IRQEN = 0x08,
LCDSTAT_M1IRQEN = 0x10,
LCDSTAT_M2IRQEN = 0x20,
LCDSTAT_LYCIRQEN = 0x40
};
}
#endif

View File

@ -18,85 +18,104 @@
***************************************************************************/
#include "lyc_irq.h"
#include "counterdef.h"
#include "lcddef.h"
#include "ly_counter.h"
#include "savestate.h"
#include <algorithm>
namespace gambatte {
LycIrq::LycIrq() :
time_(DISABLED_TIME),
lycRegSrc_(0),
statRegSrc_(0),
lycReg_(0),
statReg_(0),
cgb_(false)
namespace gambatte
{
}
static unsigned long schedule(const unsigned statReg, const unsigned lycReg, const LyCounter &lyCounter, const unsigned long cc) {
return (statReg & 0x40) && lycReg < 154
? lyCounter.nextFrameCycle(lycReg ? lycReg * 456 : 153 * 456 + 8, cc)
: static_cast<unsigned long>(DISABLED_TIME);
}
LycIrq::LycIrq()
: time_(DISABLED_TIME)
, lycRegSrc_(0)
, statRegSrc_(0)
, lycReg_(0)
, statReg_(0)
, cgb_(false)
{
}
void LycIrq::regChange(const unsigned statReg, const unsigned lycReg, const LyCounter &lyCounter, const unsigned long cc) {
const unsigned long timeSrc = schedule(statReg, lycReg, lyCounter, cc);
statRegSrc_ = statReg;
lycRegSrc_ = lycReg;
time_ = std::min(time_, timeSrc);
if (cgb_) {
if (time_ - cc > 8 || (timeSrc != time_ && time_ - cc > 4U - lyCounter.isDoubleSpeed() * 4U))
lycReg_ = lycReg;
if (time_ - cc > 4U - lyCounter.isDoubleSpeed() * 4U)
statReg_ = statReg;
} else {
if (time_ - cc > 4 || timeSrc != time_)
lycReg_ = lycReg;
if (time_ - cc > 4 || lycReg_ != 0)
statReg_ = statReg;
statReg_ = (statReg_ & 0x40) | (statReg & ~0x40);
}
}
static unsigned long schedule(const unsigned statReg,
const unsigned lycReg, const LyCounter &lyCounter, const unsigned long cc)
{
return (statReg & 0x40) && lycReg < 154
? lyCounter.nextFrameCycle(lycReg ? lycReg * 456 : 153 * 456 + 8, cc)
: static_cast<unsigned long>(DISABLED_TIME);
}
void LycIrq::doEvent(unsigned char *const ifreg, const LyCounter &lyCounter) {
if ((statReg_ | statRegSrc_) & 0x40) {
const unsigned cmpLy = lyCounter.time() - time_ < lyCounter.lineTime() ? 0 : lyCounter.ly();
if (lycReg_ == cmpLy &&
(lycReg_ - 1U < 144U - 1U ? !(statReg_ & 0x20) : !(statReg_ & 0x10))) {
*ifreg |= 2;
}
}
lycReg_ = lycRegSrc_;
statReg_ = statRegSrc_;
time_ = schedule(statReg_, lycReg_, lyCounter, time_);
}
void LycIrq::regChange(const unsigned statReg,
const unsigned lycReg, const LyCounter &lyCounter, const unsigned long cc)
{
const unsigned long timeSrc = schedule(statReg, lycReg, lyCounter, cc);
statRegSrc_ = statReg;
lycRegSrc_ = lycReg;
time_ = std::min(time_, timeSrc);
void LycIrq::loadState(const SaveState &state) {
lycRegSrc_ = state.mem.ioamhram.get()[0x145];
statRegSrc_ = state.mem.ioamhram.get()[0x141];
lycReg_ = state.ppu.lyc;
statReg_ = statRegSrc_;
}
if (cgb_)
{
if (time_ - cc > 8 || (timeSrc != time_ && time_ - cc > 4U - lyCounter.isDoubleSpeed() * 4U))
lycReg_ = lycReg;
void LycIrq::saveState(SaveState &state) const {
state.ppu.lyc = lycReg_;
}
if (time_ - cc > 4U - lyCounter.isDoubleSpeed() * 4U)
statReg_ = statReg;
}
else
{
if (time_ - cc > 4 || timeSrc != time_)
lycReg_ = lycReg;
void LycIrq::reschedule(const LyCounter & lyCounter, const unsigned long cc) {
time_ = std::min(schedule(statReg_ , lycReg_ , lyCounter, cc),
schedule(statRegSrc_, lycRegSrc_, lyCounter, cc));
}
if (time_ - cc > 4 || lycReg_ != 0)
statReg_ = statReg;
void LycIrq::lcdReset() {
statReg_ = statRegSrc_;
lycReg_ = lycRegSrc_;
}
statReg_ = (statReg_ & LCDSTAT_LYCIRQEN) | (statReg & ~LCDSTAT_LYCIRQEN);
}
}
static bool lycIrqBlockedByM2OrM1StatIrq(unsigned ly, unsigned statreg)
{
return ly - 1u < 144u - 1u
? statreg & LCDSTAT_M2IRQEN
: statreg & LCDSTAT_M1IRQEN;
}
void LycIrq::doEvent(unsigned char *const ifreg, const LyCounter &lyCounter)
{
if ((statReg_ | statRegSrc_) & LCDSTAT_LYCIRQEN)
{
const unsigned cmpLy = lyCounter.time() - time_ < lyCounter.lineTime() ? 0 : lyCounter.ly();
if (lycReg_ == cmpLy && !lycIrqBlockedByM2OrM1StatIrq(lycReg_, statReg_))
*ifreg |= 2;
}
lycReg_ = lycRegSrc_;
statReg_ = statRegSrc_;
time_ = schedule(statReg_, lycReg_, lyCounter, time_);
}
void LycIrq::loadState(const SaveState &state)
{
lycRegSrc_ = state.mem.ioamhram.get()[0x145];
statRegSrc_ = state.mem.ioamhram.get()[0x141];
lycReg_ = state.ppu.lyc;
statReg_ = statRegSrc_;
}
void LycIrq::saveState(SaveState &state) const
{
state.ppu.lyc = lycReg_;
}
void LycIrq::reschedule(const LyCounter & lyCounter, const unsigned long cc)
{
time_ = std::min(schedule(statReg_ , lycReg_ , lyCounter, cc),
schedule(statRegSrc_, lycRegSrc_, lyCounter, cc));
}
void LycIrq::lcdReset()
{
statReg_ = statRegSrc_;
lycReg_ = lycRegSrc_;
}
}

View File

@ -19,40 +19,46 @@
#ifndef VIDEO_LYC_IRQ_H
#define VIDEO_LYC_IRQ_H
namespace gambatte {
namespace gambatte
{
struct SaveState;
class LyCounter;
struct SaveState;
class LyCounter;
class LycIrq {
unsigned long time_;
unsigned char lycRegSrc_;
unsigned char statRegSrc_;
unsigned char lycReg_;
unsigned char statReg_;
bool cgb_;
void regChange(unsigned statReg, unsigned lycReg, const LyCounter &lyCounter, unsigned long cc);
public:
LycIrq();
void doEvent(unsigned char *ifreg, const LyCounter &lyCounter);
unsigned lycReg() const { return lycRegSrc_; }
void loadState(const SaveState &state);
void saveState(SaveState &state) const;
unsigned long time() const { return time_; }
void setCgb(const bool cgb) { cgb_ = cgb; }
void lcdReset();
void reschedule(const LyCounter & lyCounter, unsigned long cc);
void statRegChange(unsigned statReg, const LyCounter &lyCounter, unsigned long cc) {
regChange(statReg, lycRegSrc_, lyCounter, cc);
}
void lycRegChange(unsigned lycReg, const LyCounter &lyCounter, unsigned long cc) {
regChange(statRegSrc_, lycReg, lyCounter, cc);
}
};
class LycIrq
{
public:
LycIrq();
void doEvent(unsigned char *ifreg, const LyCounter &lyCounter);
unsigned lycReg() const { return lycRegSrc_; }
void loadState(const SaveState &state);
void saveState(SaveState &state) const;
unsigned long time() const { return time_; }
void setCgb(const bool cgb) { cgb_ = cgb; }
void lcdReset();
void reschedule(const LyCounter & lyCounter, unsigned long cc);
void statRegChange(unsigned statReg, const LyCounter &lyCounter, unsigned long cc)
{
regChange(statReg, lycRegSrc_, lyCounter, cc);
}
void lycRegChange(unsigned lycReg, const LyCounter &lyCounter, unsigned long cc)
{
regChange(statRegSrc_, lycReg, lyCounter, cc);
}
private:
unsigned long time_;
unsigned char lycRegSrc_;
unsigned char statRegSrc_;
unsigned char lycReg_;
unsigned char statReg_;
bool cgb_;
void regChange(unsigned statReg, unsigned lycReg, const LyCounter &lyCounter, unsigned long cc);
};
}