libgambatte: less magic lcd constants

This commit is contained in:
sinamas 2013-03-23 15:54:38 +01:00
parent 471d942549
commit 666bcad077
8 changed files with 151 additions and 102 deletions

View File

@ -109,7 +109,7 @@ void Memory::loadState(const SaveState &state) {
intreq.setEventTime<OAM>(lastOamDmaUpdate + (oamEventPos - oamDmaPos) * 4);
}
intreq.setEventTime<BLIT>(ioamhram[0x140] & 0x80
intreq.setEventTime<BLIT>(ioamhram[0x140] & lcdc_en
? display.nextMode1IrqTime()
: state.cpu.cycleCounter);
blanklcd = false;
@ -172,7 +172,7 @@ unsigned long Memory::event(unsigned long cycleCounter) {
break;
case BLIT:
{
const bool lcden = ioamhram[0x140] >> 7 & 1;
const bool lcden = ioamhram[0x140] & lcdc_en;
unsigned long blitTime = intreq.eventTime(BLIT);
if (lcden | blanklcd) {
@ -214,7 +214,7 @@ unsigned long Memory::event(unsigned long cycleCounter) {
dmaLength -= length;
if (!(ioamhram[0x140] & 0x80))
if (!(ioamhram[0x140] & lcdc_en))
dmaLength = 0;
{
@ -310,7 +310,7 @@ unsigned long Memory::stop(unsigned long cycleCounter) {
display.speedChange(cycleCounter);
ioamhram[0x14D] = ~ioamhram[0x14D] & 0x80;
intreq.setEventTime<BLIT>(ioamhram[0x140] & 0x80
intreq.setEventTime<BLIT>(ioamhram[0x140] & lcdc_en
? display.nextMode1IrqTime()
: cycleCounter + (70224 << isDoubleSpeed()));
@ -785,15 +785,16 @@ void Memory::nontrivial_ff_write(const unsigned P, unsigned data, const unsigned
break;
case 0x40:
if (ioamhram[0x140] != data) {
if ((ioamhram[0x140] ^ data) & 0x80) {
const unsigned lyc = display.getStat(ioamhram[0x145], cycleCounter) & 4;
if ((ioamhram[0x140] ^ data) & lcdc_en) {
const unsigned lyc = display.getStat(ioamhram[0x145], cycleCounter)
& lcdstat_lycflag;
const bool hdmaEnabled = display.hdmaIsEnabled();
display.lcdcChange(data, cycleCounter);
ioamhram[0x144] = 0;
ioamhram[0x141] &= 0xF8;
if (data & 0x80) {
if (data & lcdc_en) {
intreq.setEventTime<BLIT>(blanklcd
? display.nextMode1IrqTime()
: display.nextMode1IrqTime() + (70224 << isDoubleSpeed()));
@ -888,7 +889,7 @@ void Memory::nontrivial_ff_write(const unsigned P, unsigned data, const unsigned
}
} else {
if (data & 0x80) {
if (ioamhram[0x140] & 0x80) {
if (ioamhram[0x140] & lcdc_en) {
display.enableHdma(cycleCounter);
} else
flagHdmaReq(intreq);

View File

@ -96,11 +96,13 @@ void LCD::reset(unsigned char const *oamram, unsigned char const *vram, bool cgb
static unsigned long mode2IrqSchedule(unsigned const statReg,
LyCounter const &lyCounter, unsigned long const cc) {
if (!(statReg & 0x20))
if (!(statReg & lcdstat_m2irqen))
return DISABLED_TIME;
int next = lyCounter.time() - cc;
if (lyCounter.ly() >= 143 || (lyCounter.ly() == 142 && next <= 4) || (statReg & 0x08)) {
if (lyCounter.ly() >= 143
|| (lyCounter.ly() == 142 && next <= 4)
|| (statReg & lcdstat_m0irqen)) {
next += (153u - lyCounter.ly()) * lyCounter.lineTime();
} else {
next -= 4;
@ -151,7 +153,7 @@ void LCD::loadState(SaveState const &state, unsigned char const *const oamram) {
lycIrq_.loadState(state);
m0Irq_.loadState(state);
if (ppu_.lcdc() & 0x80) {
if (ppu_.lcdc() & lcdc_en) {
nextM0Time_.predictNextM0Time(ppu_);
lycIrq_.reschedule(ppu_.lyCounter(), ppu_.now());
@ -171,7 +173,7 @@ void LCD::loadState(SaveState const &state, unsigned char const *const oamram) {
ppu_.lyCounter().nextFrameCycle(144 * 456, ppu_.now()));
eventTimes_.setm<memevent_m2irq>(
mode2IrqSchedule(statReg_, ppu_.lyCounter(), ppu_.now()));
eventTimes_.setm<memevent_m0irq>(statReg_ & 0x08
eventTimes_.setm<memevent_m0irq>(statReg_ & lcdstat_m0irqen
? ppu_.now() + state.ppu.nextM0Irq
: static_cast<unsigned long>(DISABLED_TIME));
eventTimes_.setm<memevent_hdma>(state.mem.hdmaTransfer
@ -272,7 +274,7 @@ void LCD::resetCc(unsigned long const oldCc, unsigned long const newCc) {
update(oldCc);
ppu_.resetCc(oldCc, newCc);
if (ppu_.lcdc() & 0x80) {
if (ppu_.lcdc() & lcdc_en) {
unsigned long const dec = oldCc - newCc;
nextM0Time_.invalidatePredictedNextM0Time();
@ -291,7 +293,7 @@ void LCD::speedChange(unsigned long const cc) {
update(cc);
ppu_.speedChange(cc);
if (ppu_.lcdc() & 0x80) {
if (ppu_.lcdc() & lcdc_en) {
nextM0Time_.predictNextM0Time(ppu_);
lycIrq_.reschedule(ppu_.lyCounter(), cc);
@ -368,7 +370,7 @@ bool LCD::vramAccessible(unsigned long const cc) {
if (cc >= eventTimes_.nextEventTime())
update(cc);
return !(ppu_.lcdc() & 0x80)
return !(ppu_.lcdc() & lcdc_en)
|| ppu_.lyCounter().ly() >= 144
|| ppu_.lyCounter().lineCycles(cc) < 80U
|| cc + isDoubleSpeed() - ppu_.cgb() + 2 >= m0TimeOfCurrentLine(cc);
@ -378,7 +380,7 @@ bool LCD::cgbpAccessible(unsigned long const cc) {
if (cc >= eventTimes_.nextEventTime())
update(cc);
return !(ppu_.lcdc() & 0x80)
return !(ppu_.lcdc() & lcdc_en)
|| ppu_.lyCounter().ly() >= 144
|| ppu_.lyCounter().lineCycles(cc) < 80U + isDoubleSpeed()
|| cc >= m0TimeOfCurrentLine(cc) + 3 - isDoubleSpeed();
@ -406,7 +408,7 @@ void LCD::doCgbSpColorChange(unsigned index, unsigned data, unsigned long cc) {
}
bool LCD::oamReadable(unsigned long const cc) {
if (!(ppu_.lcdc() & 0x80) || ppu_.inactivePeriodAfterDisplayEnable(cc))
if (!(ppu_.lcdc() & lcdc_en) || ppu_.inactivePeriodAfterDisplayEnable(cc))
return true;
if (cc >= eventTimes_.nextEventTime())
@ -420,7 +422,7 @@ bool LCD::oamReadable(unsigned long const cc) {
}
bool LCD::oamWritable(unsigned long const cc) {
if (!(ppu_.lcdc() & 0x80) || ppu_.inactivePeriodAfterDisplayEnable(cc))
if (!(ppu_.lcdc() & lcdc_en) || ppu_.inactivePeriodAfterDisplayEnable(cc))
return true;
if (cc >= eventTimes_.nextEventTime())
@ -468,7 +470,7 @@ void LCD::wyChange(unsigned const newValue, unsigned long const cc) {
// close to when wy1 is read.)
// wy2 is a delayed version of wy. really just slowness of ly == wy comparison.
if (ppu_.cgb() && (ppu_.lcdc() & 0x80)) {
if (ppu_.cgb() && (ppu_.lcdc() & lcdc_en)) {
eventTimes_.setm<memevent_oneshot_updatewy2>(cc + 5);
} else {
update(cc + 2);
@ -489,7 +491,7 @@ void LCD::scyChange(unsigned newValue, unsigned long cycleCounter) {
}
void LCD::oamChange(unsigned long cc) {
if (ppu_.lcdc() & 0x80) {
if (ppu_.lcdc() & lcdc_en) {
update(cc);
ppu_.oamChange(cc);
eventTimes_.setm<memevent_spritemap>(SpriteMapper::schedule(ppu_.lyCounter(), cc));
@ -500,7 +502,7 @@ void LCD::oamChange(unsigned char const *oamram, unsigned long cc) {
update(cc);
ppu_.oamChange(oamram, cc);
if (ppu_.lcdc() & 0x80)
if (ppu_.lcdc() & lcdc_en)
eventTimes_.setm<memevent_spritemap>(SpriteMapper::schedule(ppu_.lyCounter(), cc));
}
@ -508,14 +510,14 @@ void LCD::lcdcChange(unsigned const data, unsigned long const cc) {
unsigned const oldLcdc = ppu_.lcdc();
update(cc);
if ((oldLcdc ^ data) & 0x80) {
if ((oldLcdc ^ data) & lcdc_en) {
ppu_.setLcdc(data, cc);
if (data & 0x80) {
if (data & lcdc_en) {
lycIrq_.lcdReset();
m0Irq_.lcdReset(statReg_, lycIrq_.lycReg());
if (lycIrq_.lycReg() == 0 && (statReg_ & 0x40))
if (lycIrq_.lycReg() == 0 && (statReg_ & lcdstat_lycirqen))
eventTimes_.flagIrq(2);
nextM0Time_.predictNextM0Time(ppu_);
@ -529,7 +531,7 @@ void LCD::lcdcChange(unsigned const data, unsigned long const cc) {
ppu_.lyCounter().nextFrameCycle(144 * 456, cc));
eventTimes_.setm<memevent_m2irq>(
mode2IrqSchedule(statReg_, ppu_.lyCounter(), cc));
if (statReg_ & 0x08) {
if (statReg_ & lcdstat_m0irqen) {
eventTimes_.setm<memevent_m0irq>(m0IrqTimeFromXpos166Time(
ppu_.predictedNextXposTime(166), ppu_.cgb(), isDoubleSpeed()));
}
@ -539,11 +541,12 @@ void LCD::lcdcChange(unsigned const data, unsigned long const cc) {
}
} else for (int i = 0; i < num_memevents; ++i)
eventTimes_.set(MemEvent(i), DISABLED_TIME);
} else if (data & 0x80) {
} else if (data & lcdc_en) {
if (ppu_.cgb()) {
ppu_.setLcdc((oldLcdc & ~0x14) | (data & 0x14), cc);
ppu_.setLcdc( (oldLcdc & ~(lcdc_tdsel | lcdc_obj2x))
| (data & (lcdc_tdsel | lcdc_obj2x)), cc);
if ((oldLcdc ^ data) & 0x04) {
if ((oldLcdc ^ data) & lcdc_obj2x) {
unsigned long t = SpriteMapper::schedule(ppu_.lyCounter(), cc);
eventTimes_.setm<memevent_spritemap>(t);
}
@ -551,17 +554,17 @@ void LCD::lcdcChange(unsigned const data, unsigned long const cc) {
update(cc + isDoubleSpeed() + 1);
ppu_.setLcdc(data, cc + isDoubleSpeed() + 1);
if ((oldLcdc ^ data) & 0x20)
if ((oldLcdc ^ data) & lcdc_we)
mode3CyclesChange();
} else {
ppu_.setLcdc(data, cc);
if ((oldLcdc ^ data) & 0x04) {
if ((oldLcdc ^ data) & lcdc_obj2x) {
unsigned long t = SpriteMapper::schedule(ppu_.lyCounter(), cc);
eventTimes_.setm<memevent_spritemap>(t);
}
if ((oldLcdc ^ data) & 0x22)
if ((oldLcdc ^ data) & (lcdc_we | lcdc_objen))
mode3CyclesChange();
}
} else
@ -598,20 +601,23 @@ inline bool LCD::statChangeTriggersStatIrqDmg(unsigned const old, unsigned long
if (ppu_.lyCounter().ly() < 144) {
if (cc + 1 < m0TimeOfCurrentLine(cc))
return lycCmp.ly == lycIrq_.lycReg() && !(old & 0x40);
return lycCmp.ly == lycIrq_.lycReg() && !(old & lcdstat_lycirqen);
return !(old & 0x08)
&& !(lycCmp.ly == lycIrq_.lycReg() && (old & 0x40));
return !(old & lcdstat_m0irqen)
&& !(lycCmp.ly == lycIrq_.lycReg() && (old & lcdstat_lycirqen));
}
return !(old & 0x10)
&& !(lycCmp.ly == lycIrq_.lycReg() && (old & 0x40));
return !(old & lcdstat_m1irqen)
&& !(lycCmp.ly == lycIrq_.lycReg() && (old & lcdstat_lycirqen));
}
static bool statChangeTriggersM2IrqCgb(unsigned const old,
unsigned const data, unsigned const ly, int const timeToNextLy) {
if ((data & 0x28) != 0x20 || (old & 0x20) || ly >= 144)
if ((old & lcdstat_m2irqen)
|| (data & (lcdstat_m2irqen | lcdstat_m0irqen)) != lcdstat_m2irqen
|| ly >= 144) {
return false;
}
return timeToNextLy == 456 * 2
|| (timeToNextLy <= 4 && ly < 143);
@ -624,31 +630,35 @@ inline bool LCD::statChangeTriggersM0LycOrM1StatIrqCgb(
LyCnt const lycCmp = getLycCmpLy(ppu_.lyCounter(), cc);
bool const lycperiod = lycCmp.ly == lycIrq_.lycReg()
&& lycCmp.timeToNextLy > 4 - isDoubleSpeed() * 4;
if (lycperiod && (old & 0x40))
if (lycperiod && (old & lcdstat_lycirqen))
return false;
if (ly < 144) {
if (cc + isDoubleSpeed() * 2 < m0TimeOfCurrentLine(cc) || timeToNextLy <= 4)
return lycperiod && (data & 0x40);
return lycperiod && (data & lcdstat_lycirqen);
if (old & 0x08)
if (old & lcdstat_m0irqen)
return false;
return (data & 0x08)
|| (lycperiod && (data & 0x40));
return (data & lcdstat_m0irqen)
|| (lycperiod && (data & lcdstat_lycirqen));
}
if (old & 0x10)
if (old & lcdstat_m1irqen)
return false;
return ((data & 0x10) && (ly < 153 || timeToNextLy > 4 - isDoubleSpeed() * 4))
|| (lycperiod && (data & 0x40));
return ((data & lcdstat_m1irqen) && (ly < 153 || timeToNextLy > 4 - isDoubleSpeed() * 4))
|| (lycperiod && (data & lcdstat_lycirqen));
}
inline bool LCD::statChangeTriggersStatIrqCgb(
unsigned const old, unsigned const data, unsigned long const cc) {
if (!(data & ~old & 0x78))
if (!(data & ~old & ( lcdstat_lycirqen
| lcdstat_m2irqen
| lcdstat_m1irqen
| lcdstat_m0irqen))) {
return false;
}
unsigned const ly = ppu_.lyCounter().ly();
int const timeToNextLy = ppu_.lyCounter().time() - cc;
@ -670,11 +680,11 @@ void LCD::lcdstatChange(unsigned const data, unsigned long const cc) {
statReg_ = data;
lycIrq_.statRegChange(data, ppu_.lyCounter(), cc);
if (ppu_.lcdc() & 0x80) {
if (ppu_.lcdc() & lcdc_en) {
if (statChangeTriggersStatIrq(old, data, cc))
eventTimes_.flagIrq(2);
if ((data & 0x08) && eventTimes_(memevent_m0irq) == DISABLED_TIME) {
if ((data & lcdstat_m0irqen) && eventTimes_(memevent_m0irq) == DISABLED_TIME) {
update(cc);
eventTimes_.setm<memevent_m0irq>(m0IrqTimeFromXpos166Time(
ppu_.predictedNextXposTime(166), ppu_.cgb(), isDoubleSpeed()));
@ -686,10 +696,10 @@ void LCD::lcdstatChange(unsigned const data, unsigned long const cc) {
m2IrqStatReg_ = eventTimes_(memevent_m2irq) - cc > (ppu_.cgb() - isDoubleSpeed()) * 4U
? data
: (m2IrqStatReg_ & 0x10) | (statReg_ & ~0x10);
: (m2IrqStatReg_ & lcdstat_m1irqen) | (statReg_ & ~lcdstat_m1irqen);
m1IrqStatReg_ = eventTimes_(memevent_m1irq) - cc > (ppu_.cgb() - isDoubleSpeed()) * 4U
? data
: (m1IrqStatReg_ & 0x08) | (statReg_ & ~0x08);
: (m1IrqStatReg_ & lcdstat_m0irqen) | (statReg_ & ~lcdstat_m0irqen);
m0Irq_.statRegChange(data, eventTimes_(memevent_m0irq), cc, ppu_.cgb());
}
@ -699,12 +709,12 @@ static unsigned incLy(unsigned ly) { return ly == 153 ? 0 : ly + 1; }
inline bool LCD::lycRegChangeStatTriggerBlockedByM0OrM1Irq(unsigned long const cc) {
int const timeToNextLy = ppu_.lyCounter().time() - cc;
if (ppu_.lyCounter().ly() < 144) {
return (statReg_ & 0x08)
return (statReg_ & lcdstat_m0irqen)
&& cc >= m0TimeOfCurrentLine(cc)
&& timeToNextLy > 4 << ppu_.cgb();
}
return (statReg_ & 0x10)
return (statReg_ & lcdstat_m1irqen)
&& !(ppu_.lyCounter().ly() == 153
&& timeToNextLy <= 4
&& ppu_.cgb() && !isDoubleSpeed());
@ -712,8 +722,10 @@ inline bool LCD::lycRegChangeStatTriggerBlockedByM0OrM1Irq(unsigned long const c
bool LCD::lycRegChangeTriggersStatIrq(
unsigned const old, unsigned const data, unsigned long const cc) {
if (!(statReg_ & 0x40) || data >= 154 || lycRegChangeStatTriggerBlockedByM0OrM1Irq(cc))
if (!(statReg_ & lcdstat_lycirqen) || data >= 154
|| lycRegChangeStatTriggerBlockedByM0OrM1Irq(cc)) {
return false;
}
LyCnt lycCmp = getLycCmpLy(ppu_.lyCounter(), cc);
if (lycCmp.timeToNextLy <= 4 << ppu_.cgb()) {
@ -738,7 +750,7 @@ void LCD::lycRegChange(unsigned const data, unsigned long const cc) {
m0Irq_.lycRegChange(data, eventTimes_(memevent_m0irq), cc, isDoubleSpeed(), ppu_.cgb());
lycIrq_.lycRegChange(data, ppu_.lyCounter(), cc);
if (ppu_.lcdc() & 0x80) {
if (ppu_.lcdc() & lcdc_en) {
eventTimes_.setm<memevent_lycirq>(lycIrq_.time());
if (lycRegChangeTriggersStatIrq(old, data, cc)) {
@ -753,7 +765,7 @@ void LCD::lycRegChange(unsigned const data, unsigned long const cc) {
unsigned LCD::getStat(unsigned const lycReg, unsigned long const cc) {
unsigned stat = 0;
if (ppu_.lcdc() & 0x80) {
if (ppu_.lcdc() & lcdc_en) {
if (cc >= eventTimes_.nextEventTime())
update(cc);
@ -773,18 +785,18 @@ unsigned LCD::getStat(unsigned const lycReg, unsigned long const cc) {
LyCnt const lycCmp = getLycCmpLy(ppu_.lyCounter(), cc);
if (lycReg == lycCmp.ly && lycCmp.timeToNextLy > 4 - isDoubleSpeed() * 4)
stat |= 4;
stat |= lcdstat_lycflag;
}
return stat;
}
static bool isMode2IrqEventBlockedByM1Irq(unsigned ly, unsigned statreg) {
return ly == 0 && (statreg & 0x10);
return ly == 0 && (statreg & lcdstat_m1irqen);
}
static bool isMode2IrqEventBlockedByLycIrq(unsigned ly, unsigned statreg, unsigned lycreg) {
return (statreg & 0x40)
return (statreg & lcdstat_lycirqen)
&& (ly == 0 ? ly : ly - 1) == lycreg;
}
@ -802,7 +814,7 @@ inline void LCD::doMode2IrqEvent() {
m2IrqStatReg_ = statReg_;
if (!(statReg_ & 0x08)) {
if (!(statReg_ & lcdstat_m0irqen)) {
unsigned long nextTime = eventTimes_(memevent_m2irq) + ppu_.lyCounter().lineTime();
if (ly == 0) {
nextTime -= 4;
@ -821,7 +833,10 @@ inline void LCD::event() {
case event_mem:
switch (eventTimes_.nextMemEvent()) {
case memevent_m1irq:
eventTimes_.flagIrq((m1IrqStatReg_ & 0x18) == 0x10 ? 3 : 1);
eventTimes_.flagIrq((m1IrqStatReg_ & (lcdstat_m1irqen | lcdstat_m0irqen))
== lcdstat_m1irqen
? 3
: 1);
m1IrqStatReg_ = statReg_;
eventTimes_.setm<memevent_m1irq>(eventTimes_(memevent_m1irq)
+ (70224 << isDoubleSpeed()));
@ -860,7 +875,7 @@ inline void LCD::event() {
eventTimes_.flagIrq(ifreg);
}
eventTimes_.setm<memevent_m0irq>(statReg_ & 0x08
eventTimes_.setm<memevent_m0irq>(statReg_ & lcdstat_m0irqen
? m0IrqTimeFromXpos166Time(ppu_.predictedNextXposTime(166),
ppu_.cgb(), isDoubleSpeed())
: static_cast<unsigned long>(DISABLED_TIME));
@ -888,7 +903,7 @@ inline void LCD::event() {
}
void LCD::update(unsigned long const cycleCounter) {
if (!(ppu_.lcdc() & 0x80))
if (!(ppu_.lcdc() & lcdc_en))
return;
while (cycleCounter >= eventTimes_.nextEventTime()) {

View File

@ -111,7 +111,7 @@ public:
unsigned getLyReg(unsigned long const cc) {
unsigned lyReg = 0;
if (ppu_.lcdc() & 0x80) {
if (ppu_.lcdc() & lcdc_en) {
if (cc >= ppu_.lyCounter().time())
update(cc);

View File

@ -0,0 +1,21 @@
#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,30 +18,33 @@
***************************************************************************/
#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)
LycIrq::LycIrq()
: time_(DISABLED_TIME)
, lycRegSrc_(0)
, statRegSrc_(0)
, lycReg_(0)
, statReg_(0)
, cgb_(false)
{
}
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);
static unsigned long schedule(unsigned statReg,
unsigned lycReg, LyCounter const &lyCounter, unsigned long cc) {
return (statReg & lcdstat_lycirqen) && lycReg < 154
? lyCounter.nextFrameCycle(lycReg ? lycReg * 456 : 153 * 456 + 8, cc)
: static_cast<unsigned long>(DISABLED_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);
void LycIrq::regChange(unsigned const statReg,
unsigned const lycReg, LyCounter const &lyCounter, unsigned long const cc) {
unsigned long const timeSrc = schedule(statReg, lycReg, lyCounter, cc);
statRegSrc_ = statReg;
lycRegSrc_ = lycReg;
time_ = std::min(time_, timeSrc);
@ -59,18 +62,21 @@ void LycIrq::regChange(const unsigned statReg, const unsigned lycReg, const LyCo
if (time_ - cc > 4 || lycReg_ != 0)
statReg_ = statReg;
statReg_ = (statReg_ & 0x40) | (statReg & ~0x40);
statReg_ = (statReg_ & lcdstat_lycirqen) | (statReg & ~lcdstat_lycirqen);
}
}
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();
static bool lycIrqBlockedByM2OrM1StatIrq(unsigned ly, unsigned statreg) {
return ly - 1u < 144u - 1u
? statreg & lcdstat_m2irqen
: statreg & lcdstat_m1irqen;
}
if (lycReg_ == cmpLy &&
(lycReg_ - 1U < 144U - 1U ? !(statReg_ & 0x20) : !(statReg_ & 0x10))) {
void LycIrq::doEvent(unsigned char *const ifreg, LyCounter const &lyCounter) {
if ((statReg_ | statRegSrc_) & lcdstat_lycirqen) {
unsigned cmpLy = lyCounter.time() - time_ < lyCounter.lineTime() ? 0 : lyCounter.ly();
if (lycReg_ == cmpLy && !lycIrqBlockedByM2OrM1StatIrq(lycReg_, statReg_))
*ifreg |= 2;
}
}
lycReg_ = lycRegSrc_;
@ -78,7 +84,7 @@ void LycIrq::doEvent(unsigned char *const ifreg, const LyCounter &lyCounter) {
time_ = schedule(statReg_, lycReg_, lyCounter, time_);
}
void LycIrq::loadState(const SaveState &state) {
void LycIrq::loadState(SaveState const &state) {
lycRegSrc_ = state.mem.ioamhram.get()[0x145];
statRegSrc_ = state.mem.ioamhram.get()[0x141];
lycReg_ = state.ppu.lyc;
@ -89,7 +95,7 @@ void LycIrq::saveState(SaveState &state) const {
state.ppu.lyc = lycReg_;
}
void LycIrq::reschedule(const LyCounter & lyCounter, const unsigned long cc) {
void LycIrq::reschedule(LyCounter const &lyCounter, unsigned long cc) {
time_ = std::min(schedule(statReg_ , lycReg_ , lyCounter, cc),
schedule(statRegSrc_, lycRegSrc_, lyCounter, cc));
}

View File

@ -1,6 +1,7 @@
#ifndef M0_IRQ_H
#define M0_IRQ_H
#include "lcddef.h"
#include "../savestate.h"
namespace gambatte {
@ -32,8 +33,10 @@ public:
}
void doEvent(unsigned char *ifreg, unsigned ly, unsigned statReg, unsigned lycReg) {
if (((statReg_ | statReg) & 0x08) && (!(statReg_ & 0x40) || ly != lycReg_))
if (((statReg_ | statReg) & lcdstat_m0irqen)
&& (!(statReg_ & lcdstat_lycirqen) || ly != lycReg_)) {
*ifreg |= 2;
}
statReg_ = statReg;
lycReg_ = lycReg;

View File

@ -99,7 +99,7 @@ namespace StartWindowDraw {
enum { win_draw_start = 1, win_draw_started = 2 };
enum { m2_ds_offset = 3 };
enum { max_m3start_cycles = 80 };
enum { lcdc_bgen = 0x01, lcdc_objen = 0x02, lcdc_obj2x = 0x04, lcdc_we = 0x20, lcdc_en = 0x80 };
enum { attr_yflip = 0x40, attr_bgpriority = 0x80 };
static inline int lcdcEn( PPUPriv const &p) { return p.lcdc & lcdc_en; }
static inline int lcdcWinEn(PPUPriv const &p) { return p.lcdc & lcdc_we; }
@ -344,7 +344,7 @@ static void doFullTilesUnrolledDmg(PPUPriv &p, int const xend, uint_least32_t *c
unsigned char const *const oam = p.spriteMapper.oamram();
unsigned reg0, reg1 = oam[p.spriteList[nextSprite].oampos + 2] * 16;
unsigned const attrib = oam[p.spriteList[nextSprite].oampos + 3];
unsigned const spline = ( attrib & 0x40
unsigned const spline = ( attrib & attr_yflip
? p.spriteList[nextSprite].line ^ 15
: p.spriteList[nextSprite].line ) * 2;
@ -452,7 +452,7 @@ static void doFullTilesUnrolledDmg(PPUPriv &p, int const xend, uint_least32_t *c
unsigned long const *const spPalette = p.spPalette + (attrib >> 2 & 4);
uint_least32_t *d = dst + pos;
if (!(attrib & 0x80)) {
if (!(attrib & attr_bgpriority)) {
switch (n) {
case 8: if (spword >> 14 ) { d[7] = spPalette[spword >> 14 ]; }
case 7: if (spword >> 12 & 3) { d[6] = spPalette[spword >> 12 & 3]; }
@ -532,7 +532,7 @@ static void doFullTilesUnrolledCgb(PPUPriv &p, int const xend, uint_least32_t *c
unsigned char const *const oam = p.spriteMapper.oamram();
unsigned reg0, reg1 = oam[p.spriteList[nextSprite].oampos + 2] * 16;
unsigned const attrib = oam[p.spriteList[nextSprite].oampos + 3];
unsigned const spline = ( attrib & 0x40
unsigned const spline = ( attrib & attr_yflip
? p.spriteList[nextSprite].line ^ 15
: p.spriteList[nextSprite].line ) * 2;
@ -581,7 +581,7 @@ static void doFullTilesUnrolledCgb(PPUPriv &p, int const xend, uint_least32_t *c
unsigned const tdo = tdoffset & ~(tno << 5);
unsigned char const *const td = vram + tno * 16
+ (nattrib & 0x40 ? tdo ^ 14 : tdo)
+ (nattrib & attr_yflip ? tdo ^ 14 : tdo)
+ (nattrib << 10 & 0x2000);
unsigned short const *const explut = expand_lut + (nattrib << 3 & 0x100);
ntileword = explut[td[0]] + explut[td[1]] * 2;
@ -624,7 +624,7 @@ static void doFullTilesUnrolledCgb(PPUPriv &p, int const xend, uint_least32_t *c
} while (i >= 0 && int(p.spriteList[i].spx) > xpos - 8);
} else {
unsigned char idtab[8] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
unsigned const bgenmask = p.lcdc << 7;
unsigned const bgprioritymask = p.lcdc << 7;
do {
int n;
@ -641,7 +641,7 @@ static void doFullTilesUnrolledCgb(PPUPriv &p, int const xend, uint_least32_t *c
unsigned spword = p.spwordList[i];
unsigned long const *const spPalette = p.spPalette + (sattrib & 7) * 4;
if (!((attrib | sattrib) & bgenmask)) {
if (!((attrib | sattrib) & bgprioritymask)) {
unsigned char *const idt = idtab + pos;
uint_least32_t *const d = dst + pos;
@ -721,7 +721,7 @@ static void doFullTilesUnrolledCgb(PPUPriv &p, int const xend, uint_least32_t *c
unsigned const tdo = tdoffset & ~(tno << 5);
unsigned char const *const td = vram + tno * 16
+ (nattrib & 0x40 ? tdo ^ 14 : tdo)
+ (nattrib & attr_yflip ? tdo ^ 14 : tdo)
+ (nattrib << 10 & 0x2000);
unsigned short const *const explut = expand_lut + (nattrib << 3 & 0x100);
p.ntileword = explut[td[0]] + explut[td[1]] * 2;
@ -826,8 +826,10 @@ static void plotPixel(PPUPriv &p) {
--i;
} while (i >= 0 && int(p.spriteList[i].spx) > xpos - 8);
if (spdata && lcdcObjEn(p) && (!((attrib | p.attrib) & 0x80) || !twdata || !lcdcBgEn(p)))
if (spdata && lcdcObjEn(p)
&& (!((attrib | p.attrib) & attr_bgpriority) || !twdata || !lcdcBgEn(p))) {
pixel = p.spPalette[(attrib & 7) * 4 + spdata];
}
} else {
do {
if (p.spwordList[i] & 3) {
@ -839,7 +841,7 @@ static void plotPixel(PPUPriv &p) {
--i;
} while (i >= 0 && int(p.spriteList[i].spx) > xpos - 8);
if (spdata && lcdcObjEn(p) && (!(attrib & 0x80) || !twdata))
if (spdata && lcdcObjEn(p) && (!(attrib & attr_bgpriority) || !twdata))
pixel = p.spPalette[(attrib >> 2 & 4) + spdata];
}
}
@ -1000,7 +1002,7 @@ namespace LoadSprites {
return StartWindowDraw::f0(p);
unsigned const spline =
( p.spriteList[p.currentSprite].attrib & 0x40
( p.spriteList[p.currentSprite].attrib & attr_yflip
? p.spriteList[p.currentSprite].line ^ 15
: p.spriteList[p.currentSprite].line ) * 2;
p.reg0 = p.vram[(p.spriteList[p.currentSprite].attrib << 10 & p.cgb * 0x2000)
@ -1020,7 +1022,7 @@ namespace LoadSprites {
return StartWindowDraw::f0(p);
unsigned const spline =
( p.spriteList[p.currentSprite].attrib & 0x40
( p.spriteList[p.currentSprite].attrib & attr_yflip
? p.spriteList[p.currentSprite].line ^ 15
: p.spriteList[p.currentSprite].line ) * 2;
p.reg1 = p.vram[(p.spriteList[p.currentSprite].attrib << 10 & p.cgb * 0x2000)

View File

@ -19,15 +19,14 @@
#ifndef PPU_H
#define PPU_H
#include "video/ly_counter.h"
#include "video/sprite_mapper.h"
#include "lcddef.h"
#include "ly_counter.h"
#include "sprite_mapper.h"
#include "gbint.h"
#include <cstddef>
namespace gambatte {
struct PPUPriv;
class PPUFrameBuf {
public:
PPUFrameBuf() : buf_(0), fbline_(nullfbline()), pitch_(0) {}
@ -45,6 +44,8 @@ private:
static uint_least32_t * nullfbline() { static uint_least32_t nullfbline_[160]; return nullfbline_; }
};
struct PPUPriv;
struct PPUState {
void (*f)(PPUPriv &v);
unsigned (*predictCyclesUntilXpos_f)(PPUPriv const &v, int targetxpos, unsigned cycles);