mirror of
https://github.com/libretro/gambatte-libretro.git
synced 2024-11-23 07:49:48 +00:00
(video) Update lyc_irq.cpp
This commit is contained in:
parent
1078477c45
commit
9bc71a1d3b
28
libgambatte/src/video/lcddef.h
Normal file
28
libgambatte/src/video/lcddef.h
Normal 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
|
@ -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_;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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);
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user