From 666bcad077662bd42a0bd4a1cd69520d45ef5db7 Mon Sep 17 00:00:00 2001 From: sinamas Date: Sat, 23 Mar 2013 15:54:38 +0100 Subject: [PATCH] libgambatte: less magic lcd constants --- libgambatte/src/memory.cpp | 17 +++-- libgambatte/src/video.cpp | 123 +++++++++++++++++------------- libgambatte/src/video.h | 2 +- libgambatte/src/video/lcddef.h | 21 +++++ libgambatte/src/video/lyc_irq.cpp | 50 ++++++------ libgambatte/src/video/m0_irq.h | 5 +- libgambatte/src/video/ppu.cpp | 26 ++++--- libgambatte/src/video/ppu.h | 9 ++- 8 files changed, 151 insertions(+), 102 deletions(-) create mode 100644 libgambatte/src/video/lcddef.h diff --git a/libgambatte/src/memory.cpp b/libgambatte/src/memory.cpp index 977186ae..2ea3e726 100644 --- a/libgambatte/src/memory.cpp +++ b/libgambatte/src/memory.cpp @@ -109,7 +109,7 @@ void Memory::loadState(const SaveState &state) { intreq.setEventTime(lastOamDmaUpdate + (oamEventPos - oamDmaPos) * 4); } - intreq.setEventTime(ioamhram[0x140] & 0x80 + intreq.setEventTime(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(ioamhram[0x140] & 0x80 + intreq.setEventTime(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(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); diff --git a/libgambatte/src/video.cpp b/libgambatte/src/video.cpp index f2d172d6..9c3a8970 100644 --- a/libgambatte/src/video.cpp +++ b/libgambatte/src/video.cpp @@ -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( mode2IrqSchedule(statReg_, ppu_.lyCounter(), ppu_.now())); - eventTimes_.setm(statReg_ & 0x08 + eventTimes_.setm(statReg_ & lcdstat_m0irqen ? ppu_.now() + state.ppu.nextM0Irq : static_cast(DISABLED_TIME)); eventTimes_.setm(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(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(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(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( mode2IrqSchedule(statReg_, ppu_.lyCounter(), cc)); - if (statReg_ & 0x08) { + if (statReg_ & lcdstat_m0irqen) { eventTimes_.setm(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(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(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(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(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(eventTimes_(memevent_m1irq) + (70224 << isDoubleSpeed())); @@ -860,7 +875,7 @@ inline void LCD::event() { eventTimes_.flagIrq(ifreg); } - eventTimes_.setm(statReg_ & 0x08 + eventTimes_.setm(statReg_ & lcdstat_m0irqen ? m0IrqTimeFromXpos166Time(ppu_.predictedNextXposTime(166), ppu_.cgb(), isDoubleSpeed()) : static_cast(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()) { diff --git a/libgambatte/src/video.h b/libgambatte/src/video.h index a1506e6e..e6b03b31 100644 --- a/libgambatte/src/video.h +++ b/libgambatte/src/video.h @@ -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); diff --git a/libgambatte/src/video/lcddef.h b/libgambatte/src/video/lcddef.h new file mode 100644 index 00000000..5fbf3756 --- /dev/null +++ b/libgambatte/src/video/lcddef.h @@ -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 diff --git a/libgambatte/src/video/lyc_irq.cpp b/libgambatte/src/video/lyc_irq.cpp index c6a9ad21..3ce4cd11 100644 --- a/libgambatte/src/video/lyc_irq.cpp +++ b/libgambatte/src/video/lyc_irq.cpp @@ -18,30 +18,33 @@ ***************************************************************************/ #include "lyc_irq.h" #include "counterdef.h" +#include "lcddef.h" #include "ly_counter.h" #include "savestate.h" #include 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(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(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)); } diff --git a/libgambatte/src/video/m0_irq.h b/libgambatte/src/video/m0_irq.h index f9e259a9..f07f62fe 100644 --- a/libgambatte/src/video/m0_irq.h +++ b/libgambatte/src/video/m0_irq.h @@ -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; diff --git a/libgambatte/src/video/ppu.cpp b/libgambatte/src/video/ppu.cpp index 6cfad875..fd0dc076 100644 --- a/libgambatte/src/video/ppu.cpp +++ b/libgambatte/src/video/ppu.cpp @@ -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) diff --git a/libgambatte/src/video/ppu.h b/libgambatte/src/video/ppu.h index 45fee493..1bd9a22f 100644 --- a/libgambatte/src/video/ppu.h +++ b/libgambatte/src/video/ppu.h @@ -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 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);