Update PPU
This commit is contained in:
parent
b99b5a05d6
commit
a6aeef840a
|
@ -2,7 +2,7 @@
|
|||
#define COUNTERDEF_H
|
||||
|
||||
namespace gambatte {
|
||||
enum { DISABLED_TIME = 0xFFFFFFFFul };
|
||||
enum { disabled_time = 0xFFFFFFFFul };
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1200,10 +1200,10 @@ void gambatte::setInitState(SaveState &state, const bool cgb, const bool gbaCgbM
|
|||
|
||||
state.mem.divLastUpdate = 0 - div;
|
||||
state.mem.timaLastUpdate = 0;
|
||||
state.mem.tmatime = DISABLED_TIME;
|
||||
state.mem.nextSerialtime = DISABLED_TIME;
|
||||
state.mem.lastOamDmaUpdate = DISABLED_TIME;
|
||||
state.mem.unhaltTime = DISABLED_TIME;
|
||||
state.mem.tmatime = disabled_time;
|
||||
state.mem.nextSerialtime = disabled_time;
|
||||
state.mem.lastOamDmaUpdate = disabled_time;
|
||||
state.mem.unhaltTime = disabled_time;
|
||||
state.mem.minIntTime = 0;
|
||||
state.mem.rombank = 1;
|
||||
state.mem.dmaSource = 0;
|
||||
|
|
|
@ -29,13 +29,13 @@ void InterruptRequester::loadState(const SaveState &state) {
|
|||
iereg_ = state.mem.ioamhram.get()[0x1FF] & 0x1F;
|
||||
intFlags.set(state.mem.IME, state.mem.halted);
|
||||
|
||||
eventTimes.setValue<INTERRUPTS>(intFlags.imeOrHalted() && pendingIrqs() ? minIntTime : static_cast<unsigned long>(DISABLED_TIME));
|
||||
eventTimes.setValue<INTERRUPTS>(intFlags.imeOrHalted() && pendingIrqs() ? minIntTime : static_cast<unsigned long>(disabled_time));
|
||||
}
|
||||
|
||||
void InterruptRequester::resetCc(const unsigned long oldCc, const unsigned long newCc) {
|
||||
minIntTime = minIntTime < oldCc ? 0 : minIntTime - (oldCc - newCc);
|
||||
|
||||
if (eventTimes.value(INTERRUPTS) != DISABLED_TIME)
|
||||
if (eventTimes.value(INTERRUPTS) != disabled_time)
|
||||
eventTimes.setValue<INTERRUPTS>(minIntTime);
|
||||
}
|
||||
|
||||
|
@ -51,7 +51,7 @@ void InterruptRequester::di() {
|
|||
intFlags.unsetIme();
|
||||
|
||||
if (!intFlags.imeOrHalted())
|
||||
eventTimes.setValue<INTERRUPTS>(DISABLED_TIME);
|
||||
eventTimes.setValue<INTERRUPTS>(disabled_time);
|
||||
}
|
||||
|
||||
void InterruptRequester::halt() {
|
||||
|
@ -65,7 +65,7 @@ void InterruptRequester::unhalt() {
|
|||
intFlags.unsetHalted();
|
||||
|
||||
if (!intFlags.imeOrHalted())
|
||||
eventTimes.setValue<INTERRUPTS>(DISABLED_TIME);
|
||||
eventTimes.setValue<INTERRUPTS>(disabled_time);
|
||||
}
|
||||
|
||||
void InterruptRequester::flagIrq(const unsigned bit) {
|
||||
|
@ -84,14 +84,14 @@ void InterruptRequester::setIereg(const unsigned iereg) {
|
|||
iereg_ = iereg & 0x1F;
|
||||
|
||||
if (intFlags.imeOrHalted())
|
||||
eventTimes.setValue<INTERRUPTS>(pendingIrqs() ? minIntTime : static_cast<unsigned long>(DISABLED_TIME));
|
||||
eventTimes.setValue<INTERRUPTS>(pendingIrqs() ? minIntTime : static_cast<unsigned long>(disabled_time));
|
||||
}
|
||||
|
||||
void InterruptRequester::setIfreg(const unsigned ifreg) {
|
||||
ifreg_ = ifreg;
|
||||
|
||||
if (intFlags.imeOrHalted())
|
||||
eventTimes.setValue<INTERRUPTS>(pendingIrqs() ? minIntTime : static_cast<unsigned long>(DISABLED_TIME));
|
||||
eventTimes.setValue<INTERRUPTS>(pendingIrqs() ? minIntTime : static_cast<unsigned long>(disabled_time));
|
||||
}
|
||||
|
||||
SYNCFUNC(InterruptRequester)
|
||||
|
|
|
@ -87,7 +87,7 @@ public:
|
|||
|
||||
inline void flagHdmaReq(InterruptRequester *const intreq) { intreq->setEventTime<DMA>(0); }
|
||||
inline void flagGdmaReq(InterruptRequester *const intreq) { intreq->setEventTime<DMA>(1); }
|
||||
inline void ackDmaReq(InterruptRequester *const intreq) { intreq->setEventTime<DMA>(DISABLED_TIME); }
|
||||
inline void ackDmaReq(InterruptRequester *const intreq) { intreq->setEventTime<DMA>(disabled_time); }
|
||||
inline bool hdmaReqFlagged(const InterruptRequester &intreq) { return intreq.eventTime(DMA) == 0; }
|
||||
inline bool gdmaReqFlagged(const InterruptRequester &intreq) { return intreq.eventTime(DMA) == 1; }
|
||||
|
||||
|
|
|
@ -32,7 +32,7 @@ Memory::Memory(const Interrupter &interrupter_in, unsigned short &sp, unsigned s
|
|||
linkCallback(0),
|
||||
getInput(0),
|
||||
divLastUpdate(0),
|
||||
lastOamDmaUpdate(DISABLED_TIME),
|
||||
lastOamDmaUpdate(disabled_time),
|
||||
display(ioamhram, 0, VideoInterruptRequester(&intreq)),
|
||||
interrupter(interrupter_in),
|
||||
dmaSource(0),
|
||||
|
@ -80,7 +80,7 @@ void Memory::loadState(const SaveState &state) {
|
|||
dmaSource = state.mem.dmaSource;
|
||||
dmaDestination = state.mem.dmaDestination;
|
||||
oamDmaPos = state.mem.oamDmaPos;
|
||||
serialCnt = intreq.eventTime(SERIAL) != DISABLED_TIME
|
||||
serialCnt = intreq.eventTime(SERIAL) != disabled_time
|
||||
? serialCntFrom(intreq.eventTime(SERIAL) - state.cpu.cycleCounter, ioamhram[0x102] & isCgb() * 2)
|
||||
: 8;
|
||||
|
||||
|
@ -88,7 +88,7 @@ void Memory::loadState(const SaveState &state) {
|
|||
cart.setOamDmaSrc(OAM_DMA_SRC_OFF);
|
||||
cart.setWrambank(isCgb() && (ioamhram[0x170] & 0x07) ? ioamhram[0x170] & 0x07 : 1);
|
||||
|
||||
if (lastOamDmaUpdate != DISABLED_TIME) {
|
||||
if (lastOamDmaUpdate != disabled_time) {
|
||||
oamDmaInitSetup();
|
||||
|
||||
const unsigned oamEventPos = oamDmaPos < 0xA0 ? 0xA0 : 0x100;
|
||||
|
@ -112,11 +112,11 @@ void Memory::setEndtime(const unsigned long cycleCounter, const unsigned long in
|
|||
|
||||
void Memory::updateSerial(const unsigned long cc) {
|
||||
if (!LINKCABLE) {
|
||||
if (intreq.eventTime(SERIAL) != DISABLED_TIME) {
|
||||
if (intreq.eventTime(SERIAL) != disabled_time) {
|
||||
if (intreq.eventTime(SERIAL) <= cc) {
|
||||
ioamhram[0x101] = (((ioamhram[0x101] + 1) << serialCnt) - 1) & 0xFF;
|
||||
ioamhram[0x102] &= 0x7F;
|
||||
intreq.setEventTime<SERIAL>(DISABLED_TIME);
|
||||
intreq.setEventTime<SERIAL>(disabled_time);
|
||||
intreq.flagIrq(8);
|
||||
} else {
|
||||
const int targetCnt = serialCntFrom(intreq.eventTime(SERIAL) - cc, ioamhram[0x102] & isCgb() * 2);
|
||||
|
@ -126,10 +126,10 @@ void Memory::updateSerial(const unsigned long cc) {
|
|||
}
|
||||
}
|
||||
else {
|
||||
if (intreq.eventTime(SERIAL) != DISABLED_TIME) {
|
||||
if (intreq.eventTime(SERIAL) != disabled_time) {
|
||||
if (intreq.eventTime(SERIAL) <= cc) {
|
||||
linkClockTrigger = true;
|
||||
intreq.setEventTime<SERIAL>(DISABLED_TIME);
|
||||
intreq.setEventTime<SERIAL>(disabled_time);
|
||||
if (linkCallback)
|
||||
linkCallback();
|
||||
}
|
||||
|
@ -149,7 +149,7 @@ void Memory::updateIrqs(const unsigned long cc) {
|
|||
}
|
||||
|
||||
unsigned long Memory::event(unsigned long cycleCounter) {
|
||||
if (lastOamDmaUpdate != DISABLED_TIME)
|
||||
if (lastOamDmaUpdate != disabled_time)
|
||||
updateOamDma(cycleCounter);
|
||||
|
||||
switch (intreq.minEventId()) {
|
||||
|
@ -158,15 +158,15 @@ unsigned long Memory::event(unsigned long cycleCounter) {
|
|||
PC = (PC + 1) & 0xFFFF;
|
||||
cycleCounter += 4;
|
||||
intreq.unhalt();
|
||||
intreq.setEventTime<UNHALT>(DISABLED_TIME);
|
||||
intreq.setEventTime<UNHALT>(disabled_time);
|
||||
break;
|
||||
case END:
|
||||
intreq.setEventTime<END>(DISABLED_TIME - 1);
|
||||
intreq.setEventTime<END>(disabled_time - 1);
|
||||
|
||||
while (cycleCounter >= intreq.minEventTime() && intreq.eventTime(END) != DISABLED_TIME)
|
||||
while (cycleCounter >= intreq.minEventTime() && intreq.eventTime(END) != disabled_time)
|
||||
cycleCounter = event(cycleCounter);
|
||||
|
||||
intreq.setEventTime<END>(DISABLED_TIME);
|
||||
intreq.setEventTime<END>(disabled_time);
|
||||
|
||||
break;
|
||||
case BLIT:
|
||||
|
@ -176,8 +176,8 @@ unsigned long Memory::event(unsigned long cycleCounter) {
|
|||
|
||||
if (lcden | blanklcd) {
|
||||
display.updateScreen(blanklcd, cycleCounter);
|
||||
intreq.setEventTime<BLIT>(DISABLED_TIME);
|
||||
intreq.setEventTime<END>(DISABLED_TIME);
|
||||
intreq.setEventTime<BLIT>(disabled_time);
|
||||
intreq.setEventTime<END>(disabled_time);
|
||||
|
||||
while (cycleCounter >= intreq.minEventTime())
|
||||
cycleCounter = event(cycleCounter);
|
||||
|
@ -192,8 +192,8 @@ unsigned long Memory::event(unsigned long cycleCounter) {
|
|||
updateSerial(cycleCounter);
|
||||
break;
|
||||
case OAM:
|
||||
intreq.setEventTime<OAM>(lastOamDmaUpdate == DISABLED_TIME ?
|
||||
static_cast<unsigned long>(DISABLED_TIME) : intreq.eventTime(OAM) + 0xA0 * 4);
|
||||
intreq.setEventTime<OAM>(lastOamDmaUpdate == disabled_time ?
|
||||
static_cast<unsigned long>(disabled_time) : intreq.eventTime(OAM) + 0xA0 * 4);
|
||||
break;
|
||||
case DMA:
|
||||
{
|
||||
|
@ -217,7 +217,7 @@ unsigned long Memory::event(unsigned long cycleCounter) {
|
|||
|
||||
{
|
||||
unsigned long lOamDmaUpdate = lastOamDmaUpdate;
|
||||
lastOamDmaUpdate = DISABLED_TIME;
|
||||
lastOamDmaUpdate = disabled_time;
|
||||
|
||||
while (length--) {
|
||||
const unsigned src = dmaSrc++ & 0xFFFF;
|
||||
|
@ -236,7 +236,7 @@ unsigned long Memory::event(unsigned long cycleCounter) {
|
|||
ioamhram[src & 0xFF] = data;
|
||||
} else if (oamDmaPos == 0xA0) {
|
||||
endOamDma(lOamDmaUpdate - 1);
|
||||
lOamDmaUpdate = DISABLED_TIME;
|
||||
lOamDmaUpdate = disabled_time;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -253,7 +253,7 @@ unsigned long Memory::event(unsigned long cycleCounter) {
|
|||
ioamhram[0x155] = ((dmaLength / 0x10 - 0x1) & 0xFF) | (ioamhram[0x155] & 0x80);
|
||||
|
||||
if ((ioamhram[0x155] & 0x80) && display.hdmaIsEnabled()) {
|
||||
if (lastOamDmaUpdate != DISABLED_TIME)
|
||||
if (lastOamDmaUpdate != disabled_time)
|
||||
updateOamDma(cycleCounter);
|
||||
|
||||
display.disableHdma(cycleCounter);
|
||||
|
@ -269,7 +269,7 @@ unsigned long Memory::event(unsigned long cycleCounter) {
|
|||
break;
|
||||
case INTERRUPTS:
|
||||
if (stopped) {
|
||||
intreq.setEventTime<INTERRUPTS>(DISABLED_TIME);
|
||||
intreq.setEventTime<INTERRUPTS>(disabled_time);
|
||||
break;
|
||||
}
|
||||
if (halted()) {
|
||||
|
@ -277,7 +277,7 @@ unsigned long Memory::event(unsigned long cycleCounter) {
|
|||
cycleCounter += 4;
|
||||
|
||||
intreq.unhalt();
|
||||
intreq.setEventTime<UNHALT>(DISABLED_TIME);
|
||||
intreq.setEventTime<UNHALT>(disabled_time);
|
||||
}
|
||||
|
||||
if (ime()) {
|
||||
|
@ -347,17 +347,17 @@ unsigned long Memory::stop(unsigned long cycleCounter) {
|
|||
}
|
||||
|
||||
static void decCycles(unsigned long &counter, const unsigned long dec) {
|
||||
if (counter != DISABLED_TIME)
|
||||
if (counter != disabled_time)
|
||||
counter -= dec;
|
||||
}
|
||||
|
||||
void Memory::decEventCycles(const MemEventId eventId, const unsigned long dec) {
|
||||
if (intreq.eventTime(eventId) != DISABLED_TIME)
|
||||
if (intreq.eventTime(eventId) != disabled_time)
|
||||
intreq.setEventTime(eventId, intreq.eventTime(eventId) - dec);
|
||||
}
|
||||
|
||||
unsigned long Memory::resetCounters(unsigned long cycleCounter) {
|
||||
if (lastOamDmaUpdate != DISABLED_TIME)
|
||||
if (lastOamDmaUpdate != disabled_time)
|
||||
updateOamDma(cycleCounter);
|
||||
|
||||
updateIrqs(cycleCounter);
|
||||
|
@ -424,7 +424,7 @@ void Memory::updateOamDma(const unsigned long cycleCounter) {
|
|||
ioamhram[oamDmaPos] = oamDmaSrc ? oamDmaSrc[oamDmaPos] : cart.rtcRead();
|
||||
} else if (oamDmaPos == 0xA0) {
|
||||
endOamDma(lastOamDmaUpdate - 1);
|
||||
lastOamDmaUpdate = DISABLED_TIME;
|
||||
lastOamDmaUpdate = disabled_time;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -468,7 +468,7 @@ void Memory::endOamDma(const unsigned long cycleCounter) {
|
|||
}
|
||||
|
||||
unsigned Memory::nontrivial_ff_read(const unsigned P, const unsigned long cycleCounter) {
|
||||
if (lastOamDmaUpdate != DISABLED_TIME)
|
||||
if (lastOamDmaUpdate != disabled_time)
|
||||
updateOamDma(cycleCounter);
|
||||
|
||||
switch (P & 0x7F) {
|
||||
|
@ -562,7 +562,7 @@ static bool isInOamDmaConflictArea(const OamDmaSrc oamDmaSrc, const unsigned add
|
|||
|
||||
unsigned Memory::nontrivial_read(const unsigned P, const unsigned long cycleCounter) {
|
||||
if (P < 0xFF80) {
|
||||
if (lastOamDmaUpdate != DISABLED_TIME) {
|
||||
if (lastOamDmaUpdate != disabled_time) {
|
||||
updateOamDma(cycleCounter);
|
||||
|
||||
if (isInOamDmaConflictArea(cart.oamDmaSrc(), P, isCgb()) && oamDmaPos < 0xA0)
|
||||
|
@ -626,7 +626,7 @@ unsigned Memory::nontrivial_ff_peek(const unsigned P) {
|
|||
}
|
||||
|
||||
void Memory::nontrivial_ff_write(const unsigned P, unsigned data, const unsigned long cycleCounter) {
|
||||
if (lastOamDmaUpdate != DISABLED_TIME)
|
||||
if (lastOamDmaUpdate != disabled_time)
|
||||
updateOamDma(cycleCounter);
|
||||
|
||||
switch (P & 0xFF) {
|
||||
|
@ -645,7 +645,7 @@ void Memory::nontrivial_ff_write(const unsigned P, unsigned data, const unsigned
|
|||
serialCnt = 8;
|
||||
intreq.setEventTime<SERIAL>((data & 0x81) == 0x81
|
||||
? (data & isCgb() * 2 ? (cycleCounter & ~0x7ul) + 0x10 * 8 : (cycleCounter & ~0xFFul) + 0x200 * 8)
|
||||
: static_cast<unsigned long>(DISABLED_TIME));
|
||||
: static_cast<unsigned long>(disabled_time));
|
||||
|
||||
data |= 0x7E - isCgb() * 2;
|
||||
break;
|
||||
|
@ -865,7 +865,7 @@ void Memory::nontrivial_ff_write(const unsigned P, unsigned data, const unsigned
|
|||
display.lycRegChange(data, cycleCounter);
|
||||
break;
|
||||
case 0x46:
|
||||
if (lastOamDmaUpdate != DISABLED_TIME)
|
||||
if (lastOamDmaUpdate != disabled_time)
|
||||
endOamDma(cycleCounter);
|
||||
|
||||
lastOamDmaUpdate = cycleCounter;
|
||||
|
@ -1020,7 +1020,7 @@ void Memory::nontrivial_ff_write(const unsigned P, unsigned data, const unsigned
|
|||
}
|
||||
|
||||
void Memory::nontrivial_write(const unsigned P, const unsigned data, const unsigned long cycleCounter) {
|
||||
if (lastOamDmaUpdate != DISABLED_TIME) {
|
||||
if (lastOamDmaUpdate != disabled_time) {
|
||||
updateOamDma(cycleCounter);
|
||||
|
||||
if (isInOamDmaConflictArea(cart.oamDmaSrc(), P, isCgb()) && oamDmaPos < 0xA0) {
|
||||
|
|
|
@ -125,7 +125,7 @@ public:
|
|||
|
||||
void setLayers(unsigned mask) { display.setLayers(mask); }
|
||||
|
||||
bool isActive() const { return intreq.eventTime(END) != DISABLED_TIME; }
|
||||
bool isActive() const { return intreq.eventTime(END) != disabled_time; }
|
||||
|
||||
long cyclesSinceBlit(const unsigned long cc) const {
|
||||
return cc < intreq.eventTime(BLIT) ? -1 : static_cast<long>((cc - intreq.eventTime(BLIT)) >> isDoubleSpeed());
|
||||
|
|
|
@ -25,7 +25,7 @@ namespace gambatte {
|
|||
|
||||
Tima::Tima() :
|
||||
lastUpdate_(0),
|
||||
tmatime_(DISABLED_TIME),
|
||||
tmatime_(disabled_time),
|
||||
tima_(0),
|
||||
tma_(0),
|
||||
tac_(0)
|
||||
|
@ -41,11 +41,11 @@ void Tima::loadState(const SaveState &state, const TimaInterruptRequester timaIr
|
|||
|
||||
timaIrq.setNextIrqEventTime((tac_ & 4)
|
||||
?
|
||||
(tmatime_ != DISABLED_TIME && tmatime_ > state.cpu.cycleCounter
|
||||
(tmatime_ != disabled_time && tmatime_ > state.cpu.cycleCounter
|
||||
? tmatime_
|
||||
: lastUpdate_ + ((256u - tima_) << timaClock[tac_ & 3]) + 3)
|
||||
:
|
||||
static_cast<unsigned long>(DISABLED_TIME)
|
||||
static_cast<unsigned long>(disabled_time)
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -59,7 +59,7 @@ void Tima::resetCc(const unsigned long oldCc, const unsigned long newCc, const T
|
|||
lastUpdate_ -= dec;
|
||||
timaIrq.setNextIrqEventTime(timaIrq.nextIrqEventTime() - dec);
|
||||
|
||||
if (tmatime_ != DISABLED_TIME)
|
||||
if (tmatime_ != disabled_time)
|
||||
tmatime_ -= dec;
|
||||
}
|
||||
}
|
||||
|
@ -71,7 +71,7 @@ void Tima::updateTima(const unsigned long cycleCounter) {
|
|||
|
||||
if (cycleCounter >= tmatime_) {
|
||||
if (cycleCounter >= tmatime_ + 4)
|
||||
tmatime_ = DISABLED_TIME;
|
||||
tmatime_ = disabled_time;
|
||||
|
||||
tima_ = tma_;
|
||||
}
|
||||
|
@ -87,7 +87,7 @@ void Tima::updateTima(const unsigned long cycleCounter) {
|
|||
|
||||
if (cycleCounter >= tmatime_) {
|
||||
if (cycleCounter >= tmatime_ + 4)
|
||||
tmatime_ = DISABLED_TIME;
|
||||
tmatime_ = disabled_time;
|
||||
|
||||
tmp = tma_;
|
||||
}
|
||||
|
@ -102,7 +102,7 @@ void Tima::setTima(const unsigned data, const unsigned long cycleCounter, const
|
|||
updateTima(cycleCounter);
|
||||
|
||||
if (tmatime_ - cycleCounter < 4)
|
||||
tmatime_ = DISABLED_TIME;
|
||||
tmatime_ = disabled_time;
|
||||
|
||||
timaIrq.setNextIrqEventTime(lastUpdate_ + ((256u - data) << timaClock[tac_ & 3]) + 3);
|
||||
}
|
||||
|
@ -136,8 +136,8 @@ void Tima::setTac(const unsigned data, const unsigned long cycleCounter, const T
|
|||
|
||||
updateTima(cycleCounter);
|
||||
|
||||
tmatime_ = DISABLED_TIME;
|
||||
nextIrqEventTime = DISABLED_TIME;
|
||||
tmatime_ = disabled_time;
|
||||
nextIrqEventTime = disabled_time;
|
||||
}
|
||||
|
||||
if (data & 4) {
|
||||
|
|
|
@ -76,7 +76,7 @@ void LCD::setCgb(bool cgb) {
|
|||
|
||||
static unsigned long mode2IrqSchedule(const unsigned statReg, const LyCounter &lyCounter, const unsigned long cycleCounter) {
|
||||
if (!(statReg & 0x20))
|
||||
return DISABLED_TIME;
|
||||
return disabled_time;
|
||||
|
||||
unsigned next = lyCounter.time() - cycleCounter;
|
||||
|
||||
|
@ -127,20 +127,20 @@ void LCD::loadState(const SaveState &state, const unsigned char *const oamram) {
|
|||
lycIrq.reschedule(ppu.lyCounter(), ppu.now());
|
||||
|
||||
eventTimes_.setm<ONESHOT_LCDSTATIRQ>(state.ppu.pendingLcdstatIrq
|
||||
? ppu.now() + 1 : static_cast<unsigned long>(DISABLED_TIME));
|
||||
? ppu.now() + 1 : static_cast<unsigned long>(disabled_time));
|
||||
eventTimes_.setm<ONESHOT_UPDATEWY2>(state.ppu.oldWy != state.mem.ioamhram.get()[0x14A]
|
||||
? ppu.now() + 1 : static_cast<unsigned long>(DISABLED_TIME));
|
||||
? ppu.now() + 1 : static_cast<unsigned long>(disabled_time));
|
||||
eventTimes_.set<LY_COUNT>(ppu.lyCounter().time());
|
||||
eventTimes_.setm<SPRITE_MAP>(SpriteMapper::schedule(ppu.lyCounter(), ppu.now()));
|
||||
eventTimes_.setm<LYC_IRQ>(lycIrq.time());
|
||||
eventTimes_.setm<MODE1_IRQ>(ppu.lyCounter().nextFrameCycle(144 * 456, ppu.now()));
|
||||
eventTimes_.setm<MODE2_IRQ>(mode2IrqSchedule(statReg, ppu.lyCounter(), ppu.now()));
|
||||
eventTimes_.setm<MODE0_IRQ>((statReg & 0x08) ? ppu.now() + state.ppu.nextM0Irq : static_cast<unsigned long>(DISABLED_TIME));
|
||||
eventTimes_.setm<MODE0_IRQ>((statReg & 0x08) ? ppu.now() + state.ppu.nextM0Irq : static_cast<unsigned long>(disabled_time));
|
||||
eventTimes_.setm<HDMA_REQ>(state.mem.hdmaTransfer
|
||||
? nextHdmaTime(ppu.lastM0Time(), nextM0Time_.predictedNextM0Time(), ppu.now(), isDoubleSpeed())
|
||||
: static_cast<unsigned long>(DISABLED_TIME));
|
||||
: static_cast<unsigned long>(disabled_time));
|
||||
} else for (int i = 0; i < NUM_MEM_EVENTS; ++i)
|
||||
eventTimes_.set(MemEvent(i), DISABLED_TIME);
|
||||
eventTimes_.set(MemEvent(i), disabled_time);
|
||||
|
||||
refreshPalettes();
|
||||
}
|
||||
|
@ -218,7 +218,7 @@ void LCD::resetCc(const unsigned long oldCc, const unsigned long newCc) {
|
|||
lycIrq.reschedule(ppu.lyCounter(), newCc);
|
||||
|
||||
for (int i = 0; i < NUM_MEM_EVENTS; ++i) {
|
||||
if (eventTimes_(MemEvent(i)) != DISABLED_TIME)
|
||||
if (eventTimes_(MemEvent(i)) != disabled_time)
|
||||
eventTimes_.set(MemEvent(i), eventTimes_(MemEvent(i)) - dec);
|
||||
}
|
||||
|
||||
|
@ -240,7 +240,7 @@ void LCD::speedChange(const unsigned long cycleCounter) {
|
|||
eventTimes_.setm<MODE1_IRQ>(ppu.lyCounter().nextFrameCycle(144 * 456, cycleCounter));
|
||||
eventTimes_.setm<MODE2_IRQ>(mode2IrqSchedule(statReg, ppu.lyCounter(), cycleCounter));
|
||||
|
||||
if (eventTimes_(MODE0_IRQ) != DISABLED_TIME && eventTimes_(MODE0_IRQ) - cycleCounter > 1)
|
||||
if (eventTimes_(MODE0_IRQ) != disabled_time && eventTimes_(MODE0_IRQ) - cycleCounter > 1)
|
||||
eventTimes_.setm<MODE0_IRQ>(m0IrqTimeFromXpos166Time(ppu.predictedNextXposTime(166), ppu.cgb(), isDoubleSpeed()));
|
||||
|
||||
if (hdmaIsEnabled() && eventTimes_(HDMA_REQ) - cycleCounter > 1) {
|
||||
|
@ -294,7 +294,7 @@ void LCD::disableHdma(const unsigned long cycleCounter) {
|
|||
if (cycleCounter >= eventTimes_.nextEventTime())
|
||||
update(cycleCounter);
|
||||
|
||||
eventTimes_.setm<HDMA_REQ>(DISABLED_TIME);
|
||||
eventTimes_.setm<HDMA_REQ>(disabled_time);
|
||||
}
|
||||
|
||||
bool LCD::vramAccessible(const unsigned long cycleCounter) {
|
||||
|
@ -365,12 +365,12 @@ bool LCD::oamWritable(const unsigned long cycleCounter) {
|
|||
void LCD::mode3CyclesChange() {
|
||||
nextM0Time_.invalidatePredictedNextM0Time();
|
||||
|
||||
if (eventTimes_(MODE0_IRQ) != DISABLED_TIME
|
||||
if (eventTimes_(MODE0_IRQ) != disabled_time
|
||||
&& eventTimes_(MODE0_IRQ) > m0IrqTimeFromXpos166Time(ppu.now(), ppu.cgb(), isDoubleSpeed())) {
|
||||
eventTimes_.setm<MODE0_IRQ>(m0IrqTimeFromXpos166Time(ppu.predictedNextXposTime(166), ppu.cgb(), isDoubleSpeed()));
|
||||
}
|
||||
|
||||
if (eventTimes_(HDMA_REQ) != DISABLED_TIME
|
||||
if (eventTimes_(HDMA_REQ) != disabled_time
|
||||
&& eventTimes_(HDMA_REQ) > hdmaTimeFromM0Time(ppu.lastM0Time(), isDoubleSpeed())) {
|
||||
nextM0Time_.predictNextM0Time(ppu);
|
||||
eventTimes_.setm<HDMA_REQ>(hdmaTimeFromM0Time(nextM0Time_.predictedNextM0Time(), isDoubleSpeed()));
|
||||
|
@ -456,7 +456,7 @@ void LCD::lcdcChange(const unsigned data, const unsigned long cycleCounter) {
|
|||
nextM0Time_.predictedNextM0Time(), cycleCounter, isDoubleSpeed()));
|
||||
}
|
||||
} else for (int i = 0; i < NUM_MEM_EVENTS; ++i)
|
||||
eventTimes_.set(MemEvent(i), DISABLED_TIME);
|
||||
eventTimes_.set(MemEvent(i), disabled_time);
|
||||
} else if (data & 0x80) {
|
||||
if (ppu.cgb()) {
|
||||
ppu.setLcdc((oldLcdc & ~0x14) | (data & 0x14), cycleCounter);
|
||||
|
@ -557,7 +557,7 @@ void LCD::lcdstatChange(unsigned const data, unsigned long const cycleCounter) {
|
|||
}
|
||||
}
|
||||
|
||||
if ((data & 0x08) && eventTimes_(MODE0_IRQ) == DISABLED_TIME) {
|
||||
if ((data & 0x08) && eventTimes_(MODE0_IRQ) == disabled_time) {
|
||||
update(cycleCounter);
|
||||
eventTimes_.setm<MODE0_IRQ>(m0IrqTimeFromXpos166Time(ppu.predictedNextXposTime(166), ppu.cgb(), isDoubleSpeed()));
|
||||
}
|
||||
|
@ -712,18 +712,18 @@ inline void LCD::event() {
|
|||
|
||||
eventTimes_.setm<MODE0_IRQ>(statReg & 0x08
|
||||
? m0IrqTimeFromXpos166Time(ppu.predictedNextXposTime(166), ppu.cgb(), isDoubleSpeed())
|
||||
: static_cast<unsigned long>(DISABLED_TIME));
|
||||
: static_cast<unsigned long>(disabled_time));
|
||||
break;
|
||||
|
||||
case ONESHOT_LCDSTATIRQ:
|
||||
eventTimes_.flagIrq(2);
|
||||
eventTimes_.setm<ONESHOT_LCDSTATIRQ>(DISABLED_TIME);
|
||||
eventTimes_.setm<ONESHOT_LCDSTATIRQ>(disabled_time);
|
||||
break;
|
||||
|
||||
case ONESHOT_UPDATEWY2:
|
||||
ppu.updateWy2();
|
||||
mode3CyclesChange();
|
||||
eventTimes_.setm<ONESHOT_UPDATEWY2>(DISABLED_TIME);
|
||||
eventTimes_.setm<ONESHOT_UPDATEWY2>(disabled_time);
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
|
||||
#include "video/ppu.h"
|
||||
#include "video/lyc_irq.h"
|
||||
#include "video/m0_irq.h"
|
||||
#include "video/next_m0_time.h"
|
||||
#include "interruptrequester.h"
|
||||
#include "minkeeper.h"
|
||||
|
@ -39,53 +40,6 @@ public:
|
|||
void setNextEventTime(const unsigned long time) const { intreq->setEventTime<VIDEO>(time); }
|
||||
};
|
||||
|
||||
class M0Irq {
|
||||
unsigned char statReg_;
|
||||
unsigned char lycReg_;
|
||||
|
||||
public:
|
||||
M0Irq() : statReg_(0), lycReg_(0) {}
|
||||
|
||||
void lcdReset(const unsigned statReg, const unsigned lycReg) {
|
||||
statReg_ = statReg;
|
||||
lycReg_ = lycReg;
|
||||
}
|
||||
|
||||
void statRegChange(const unsigned statReg,
|
||||
const unsigned long nextM0IrqTime, const unsigned long cc, const bool cgb) {
|
||||
if (nextM0IrqTime - cc > cgb * 2U)
|
||||
statReg_ = statReg;
|
||||
}
|
||||
|
||||
void lycRegChange(const unsigned lycReg,
|
||||
const unsigned long nextM0IrqTime, const unsigned long cc, const bool ds, const bool cgb) {
|
||||
if (nextM0IrqTime - cc > cgb * 5 + 1U - ds)
|
||||
lycReg_ = lycReg;
|
||||
}
|
||||
|
||||
void doEvent(unsigned char *const ifreg, const unsigned ly, const unsigned statReg, const unsigned lycReg) {
|
||||
if (((statReg_ | statReg) & lcdstat_m0irqen) && (!(statReg_ & lcdstat_lycirqen) || ly != lycReg_))
|
||||
*ifreg |= 2;
|
||||
|
||||
statReg_ = statReg;
|
||||
lycReg_ = lycReg;
|
||||
}
|
||||
|
||||
void loadState(const SaveState &state) {
|
||||
lycReg_ = state.ppu.m0lyc;
|
||||
statReg_ = state.mem.ioamhram.get()[0x141];
|
||||
}
|
||||
|
||||
unsigned statReg() const { return statReg_; }
|
||||
|
||||
template<bool isReader>
|
||||
void SyncState(NewState *ns)
|
||||
{
|
||||
NSS(statReg_);
|
||||
NSS(lycReg_);
|
||||
}
|
||||
};
|
||||
|
||||
class LCD {
|
||||
enum Event { MEM_EVENT, LY_COUNT }; enum { NUM_EVENTS = LY_COUNT + 1 };
|
||||
enum MemEvent { ONESHOT_LCDSTATIRQ, ONESHOT_UPDATEWY2, MODE1_IRQ, LYC_IRQ, SPRITE_MAP,
|
||||
|
@ -264,7 +218,7 @@ public:
|
|||
|
||||
void enableHdma(unsigned long cycleCounter);
|
||||
void disableHdma(unsigned long cycleCounter);
|
||||
bool hdmaIsEnabled() const { return eventTimes_(HDMA_REQ) != DISABLED_TIME; }
|
||||
bool hdmaIsEnabled() const { return eventTimes_(HDMA_REQ) != disabled_time; }
|
||||
|
||||
void update(unsigned long cycleCounter);
|
||||
|
||||
|
|
|
@ -1,28 +1,31 @@
|
|||
/***************************************************************************
|
||||
* Copyright (C) 2007 by Sindre Aamås *
|
||||
* aamas@stud.ntnu.no *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License version 2 as *
|
||||
* published by the Free Software Foundation. *
|
||||
* *
|
||||
* 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 version 2 for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* version 2 along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
//
|
||||
// Copyright (C) 2007 by sinamas <sinamas at users.sourceforge.net>
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License version 2 as
|
||||
// published by the Free Software Foundation.
|
||||
//
|
||||
// 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 version 2 for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// version 2 along with this program; if not, write to the
|
||||
// Free Software Foundation, Inc.,
|
||||
// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
//
|
||||
|
||||
#include "ly_counter.h"
|
||||
#include "../savestate.h"
|
||||
|
||||
namespace gambatte {
|
||||
|
||||
LyCounter::LyCounter()
|
||||
: time_(0), lineTime_(0), ly_(0), ds(false)
|
||||
: time_(0)
|
||||
, lineTime_(0)
|
||||
, ly_(0)
|
||||
, ds_(false)
|
||||
{
|
||||
setDoubleSpeed(false);
|
||||
reset(0, 0);
|
||||
|
@ -30,39 +33,36 @@ LyCounter::LyCounter()
|
|||
|
||||
void LyCounter::doEvent() {
|
||||
++ly_;
|
||||
|
||||
if (ly_ == 154)
|
||||
ly_ = 0;
|
||||
|
||||
time_ = time_ + lineTime_;
|
||||
}
|
||||
|
||||
unsigned long LyCounter::nextLineCycle(const unsigned lineCycle, const unsigned long cycleCounter) const {
|
||||
unsigned long tmp = time_ + (lineCycle << ds);
|
||||
|
||||
if (tmp - cycleCounter > lineTime_)
|
||||
unsigned long LyCounter::nextLineCycle(unsigned const lineCycle, unsigned long const cc) const {
|
||||
unsigned long tmp = time_ + (lineCycle << ds_);
|
||||
if (tmp - cc > lineTime_)
|
||||
tmp -= lineTime_;
|
||||
|
||||
return tmp;
|
||||
}
|
||||
|
||||
unsigned long LyCounter::nextFrameCycle(const unsigned long frameCycle, const unsigned long cycleCounter) const {
|
||||
unsigned long tmp = time_ + (((153U - ly()) * 456U + frameCycle) << ds);
|
||||
|
||||
if (tmp - cycleCounter > 70224U << ds)
|
||||
tmp -= 70224U << ds;
|
||||
unsigned long LyCounter::nextFrameCycle(unsigned long const frameCycle, unsigned long const cc) const {
|
||||
unsigned long tmp = time_ + (((153U - ly()) * 456U + frameCycle) << ds_);
|
||||
if (tmp - cc > 70224U << ds_)
|
||||
tmp -= 70224U << ds_;
|
||||
|
||||
return tmp;
|
||||
}
|
||||
|
||||
void LyCounter::reset(const unsigned long videoCycles, const unsigned long lastUpdate) {
|
||||
void LyCounter::reset(unsigned long videoCycles, unsigned long lastUpdate) {
|
||||
ly_ = videoCycles / 456;
|
||||
time_ = lastUpdate + ((456 - (videoCycles - ly_ * 456ul)) << isDoubleSpeed());
|
||||
}
|
||||
|
||||
void LyCounter::setDoubleSpeed(const bool ds_in) {
|
||||
ds = ds_in;
|
||||
lineTime_ = 456U << ds_in;
|
||||
void LyCounter::setDoubleSpeed(bool ds) {
|
||||
ds_ = ds;
|
||||
lineTime_ = 456U << ds;
|
||||
}
|
||||
|
||||
SYNCFUNC(LyCounter)
|
||||
|
@ -70,7 +70,7 @@ SYNCFUNC(LyCounter)
|
|||
NSS(time_);
|
||||
NSS(lineTime_);
|
||||
NSS(ly_);
|
||||
NSS(ds);
|
||||
NSS(ds_);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,21 +1,21 @@
|
|||
/***************************************************************************
|
||||
* Copyright (C) 2007 by Sindre Aamås *
|
||||
* aamas@stud.ntnu.no *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License version 2 as *
|
||||
* published by the Free Software Foundation. *
|
||||
* *
|
||||
* 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 version 2 for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* version 2 along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
//
|
||||
// Copyright (C) 2007 by sinamas <sinamas at users.sourceforge.net>
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License version 2 as
|
||||
// published by the Free Software Foundation.
|
||||
//
|
||||
// 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 version 2 for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// version 2 along with this program; if not, write to the
|
||||
// Free Software Foundation, Inc.,
|
||||
// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
//
|
||||
|
||||
#ifndef LY_COUNTER_H
|
||||
#define LY_COUNTER_H
|
||||
|
||||
|
@ -26,21 +26,16 @@ namespace gambatte {
|
|||
struct SaveState;
|
||||
|
||||
class LyCounter {
|
||||
unsigned long time_;
|
||||
unsigned short lineTime_;
|
||||
unsigned char ly_;
|
||||
bool ds;
|
||||
|
||||
public:
|
||||
LyCounter();
|
||||
void doEvent();
|
||||
bool isDoubleSpeed() const { return ds; }
|
||||
bool isDoubleSpeed() const { return ds_; }
|
||||
|
||||
unsigned long frameCycles(const unsigned long cc) const {
|
||||
unsigned long frameCycles(unsigned long cc) const {
|
||||
return ly_ * 456ul + lineCycles(cc);
|
||||
}
|
||||
|
||||
unsigned lineCycles(const unsigned long cc) const {
|
||||
unsigned lineCycles(unsigned long cc) const {
|
||||
return 456u - ((time_ - cc) >> isDoubleSpeed());
|
||||
}
|
||||
|
||||
|
@ -49,9 +44,16 @@ public:
|
|||
unsigned long nextLineCycle(unsigned lineCycle, unsigned long cycleCounter) const;
|
||||
unsigned long nextFrameCycle(unsigned long frameCycle, unsigned long cycleCounter) const;
|
||||
void reset(unsigned long videoCycles, unsigned long lastUpdate);
|
||||
void setDoubleSpeed(bool ds_in);
|
||||
void setDoubleSpeed(bool ds);
|
||||
unsigned long time() const { return time_; }
|
||||
|
||||
private:
|
||||
unsigned long time_;
|
||||
unsigned short lineTime_;
|
||||
unsigned char ly_;
|
||||
bool ds_;
|
||||
|
||||
public:
|
||||
template<bool isReader>void SyncState(NewState *ns);
|
||||
};
|
||||
|
||||
|
|
|
@ -1,47 +1,50 @@
|
|||
/***************************************************************************
|
||||
* Copyright (C) 2007 by Sindre Aamås *
|
||||
* aamas@stud.ntnu.no *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License version 2 as *
|
||||
* published by the Free Software Foundation. *
|
||||
* *
|
||||
* 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 version 2 for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* version 2 along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
//
|
||||
// Copyright (C) 2007 by sinamas <sinamas at users.sourceforge.net>
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License version 2 as
|
||||
// published by the Free Software Foundation.
|
||||
//
|
||||
// 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 version 2 for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// version 2 along with this program; if not, write to the
|
||||
// Free Software Foundation, Inc.,
|
||||
// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
//
|
||||
|
||||
#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,14 +84,14 @@ 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;
|
||||
statReg_ = statRegSrc_;
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
||||
|
|
|
@ -1,21 +1,21 @@
|
|||
/***************************************************************************
|
||||
* Copyright (C) 2007 by Sindre Aamås *
|
||||
* aamas@stud.ntnu.no *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License version 2 as *
|
||||
* published by the Free Software Foundation. *
|
||||
* *
|
||||
* 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 version 2 for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* version 2 along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
//
|
||||
// Copyright (C) 2007 by sinamas <sinamas at users.sourceforge.net>
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License version 2 as
|
||||
// published by the Free Software Foundation.
|
||||
//
|
||||
// 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 version 2 for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// version 2 along with this program; if not, write to the
|
||||
// Free Software Foundation, Inc.,
|
||||
// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
//
|
||||
|
||||
#ifndef VIDEO_LYC_IRQ_H
|
||||
#define VIDEO_LYC_IRQ_H
|
||||
|
||||
|
@ -27,6 +27,25 @@ struct SaveState;
|
|||
class LyCounter;
|
||||
|
||||
class LycIrq {
|
||||
public:
|
||||
LycIrq();
|
||||
void doEvent(unsigned char *ifreg, LyCounter const &lyCounter);
|
||||
unsigned lycReg() const { return lycRegSrc_; }
|
||||
void loadState(SaveState const &state);
|
||||
unsigned long time() const { return time_; }
|
||||
void setCgb(bool cgb) { cgb_ = cgb; }
|
||||
void lcdReset();
|
||||
void reschedule(LyCounter const &lyCounter, unsigned long cc);
|
||||
|
||||
void statRegChange(unsigned statReg, LyCounter const &lyCounter, unsigned long cc) {
|
||||
regChange(statReg, lycRegSrc_, lyCounter, cc);
|
||||
}
|
||||
|
||||
void lycRegChange(unsigned lycReg, LyCounter const &lyCounter, unsigned long cc) {
|
||||
regChange(statRegSrc_, lycReg, lyCounter, cc);
|
||||
}
|
||||
|
||||
private:
|
||||
unsigned long time_;
|
||||
unsigned char lycRegSrc_;
|
||||
unsigned char statRegSrc_;
|
||||
|
@ -34,26 +53,10 @@ class LycIrq {
|
|||
unsigned char statReg_;
|
||||
bool cgb_;
|
||||
|
||||
void regChange(unsigned statReg, unsigned lycReg, const LyCounter &lyCounter, unsigned long cc);
|
||||
void regChange(unsigned statReg, unsigned lycReg,
|
||||
LyCounter const &lyCounter, unsigned long cc);
|
||||
|
||||
public:
|
||||
LycIrq();
|
||||
void doEvent(unsigned char *ifreg, const LyCounter &lyCounter);
|
||||
unsigned lycReg() const { return lycRegSrc_; }
|
||||
void loadState(const SaveState &state);
|
||||
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);
|
||||
}
|
||||
|
||||
template<bool isReader>void SyncState(NewState *ns);
|
||||
};
|
||||
|
||||
|
|
|
@ -0,0 +1,68 @@
|
|||
#ifndef M0_IRQ_H
|
||||
#define M0_IRQ_H
|
||||
|
||||
#include "lcddef.h"
|
||||
#include "../savestate.h"
|
||||
#include "../newstate.h"
|
||||
|
||||
namespace gambatte {
|
||||
|
||||
class M0Irq {
|
||||
public:
|
||||
M0Irq()
|
||||
: statReg_(0)
|
||||
, lycReg_(0)
|
||||
{
|
||||
}
|
||||
|
||||
void lcdReset(unsigned statReg, unsigned lycReg) {
|
||||
statReg_ = statReg;
|
||||
lycReg_ = lycReg;
|
||||
}
|
||||
|
||||
void statRegChange(unsigned statReg,
|
||||
unsigned long nextM0IrqTime, unsigned long cc, bool cgb) {
|
||||
if (nextM0IrqTime - cc > cgb * 2U)
|
||||
statReg_ = statReg;
|
||||
}
|
||||
|
||||
void lycRegChange(unsigned lycReg,
|
||||
unsigned long nextM0IrqTime, unsigned long cc,
|
||||
bool ds, bool cgb) {
|
||||
if (nextM0IrqTime - cc > cgb * 5 + 1U - ds)
|
||||
lycReg_ = lycReg;
|
||||
}
|
||||
|
||||
void doEvent(unsigned char *ifreg, unsigned ly, unsigned statReg, unsigned lycReg) {
|
||||
if (((statReg_ | statReg) & lcdstat_m0irqen)
|
||||
&& (!(statReg_ & lcdstat_lycirqen) || ly != lycReg_)) {
|
||||
*ifreg |= 2;
|
||||
}
|
||||
|
||||
statReg_ = statReg;
|
||||
lycReg_ = lycReg;
|
||||
}
|
||||
|
||||
void loadState(SaveState const &state) {
|
||||
lycReg_ = state.ppu.m0lyc;
|
||||
statReg_ = state.mem.ioamhram.get()[0x141];
|
||||
}
|
||||
|
||||
unsigned statReg() const { return statReg_; }
|
||||
|
||||
private:
|
||||
unsigned char statReg_;
|
||||
unsigned char lycReg_;
|
||||
|
||||
public:
|
||||
template<bool isReader>
|
||||
void SyncState(NewState *ns)
|
||||
{
|
||||
NSS(statReg_);
|
||||
NSS(lycReg_);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
|
@ -1,15 +1,11 @@
|
|||
#include "next_m0_time.h"
|
||||
#include "ppu.h"
|
||||
|
||||
namespace gambatte {
|
||||
|
||||
void NextM0Time::predictNextM0Time(const PPU &ppu) {
|
||||
void gambatte::NextM0Time::predictNextM0Time(PPU const &ppu) {
|
||||
predictedNextM0Time_ = ppu.predictedNextXposTime(167);
|
||||
}
|
||||
|
||||
SYNCFUNC(NextM0Time)
|
||||
SYNCFUNC(gambatte::NextM0Time)
|
||||
{
|
||||
NSS(predictedNextM0Time_);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -6,14 +6,16 @@
|
|||
namespace gambatte {
|
||||
|
||||
class NextM0Time {
|
||||
unsigned predictedNextM0Time_;
|
||||
|
||||
public:
|
||||
NextM0Time() : predictedNextM0Time_(0) {}
|
||||
void predictNextM0Time(const class PPU &v);
|
||||
void predictNextM0Time(class PPU const &v);
|
||||
void invalidatePredictedNextM0Time() { predictedNextM0Time_ = 0; }
|
||||
unsigned predictedNextM0Time() const { return predictedNextM0Time_; }
|
||||
|
||||
private:
|
||||
unsigned predictedNextM0Time_;
|
||||
|
||||
public:
|
||||
template<bool isReader>void SyncState(NewState *ns);
|
||||
};
|
||||
|
||||
|
|
|
@ -1,28 +1,29 @@
|
|||
/***************************************************************************
|
||||
* Copyright (C) 2010 by Sindre Aamås *
|
||||
* aamas@stud.ntnu.no *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License version 2 as *
|
||||
* published by the Free Software Foundation. *
|
||||
* *
|
||||
* 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 version 2 for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* version 2 along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
//
|
||||
// Copyright (C) 2010 by sinamas <sinamas at users.sourceforge.net>
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License version 2 as
|
||||
// published by the Free Software Foundation.
|
||||
//
|
||||
// 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 version 2 for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// version 2 along with this program; if not, write to the
|
||||
// Free Software Foundation, Inc.,
|
||||
// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
//
|
||||
|
||||
#ifndef PPU_H
|
||||
#define PPU_H
|
||||
|
||||
#include "lcddef.h"
|
||||
#include "video/ly_counter.h"
|
||||
#include "video/sprite_mapper.h"
|
||||
#include "ly_counter.h"
|
||||
#include "sprite_mapper.h"
|
||||
#include "gbint.h"
|
||||
#include <cstddef>
|
||||
|
||||
#include "newstate.h"
|
||||
|
||||
|
@ -31,28 +32,30 @@ namespace gambatte {
|
|||
enum { LAYER_MASK_BG = 1, LAYER_MASK_OBJ = 2, LAYER_MASK_WINDOW = 4 };
|
||||
|
||||
class PPUFrameBuf {
|
||||
uint_least32_t *buf_;
|
||||
uint_least32_t *fbline_;
|
||||
int pitch_;
|
||||
|
||||
static uint_least32_t * nullfbline() { static uint_least32_t nullfbline_[160]; return nullfbline_; }
|
||||
|
||||
public:
|
||||
PPUFrameBuf() : buf_(0), fbline_(nullfbline()), pitch_(0) {}
|
||||
uint_least32_t * fb() const { return buf_; }
|
||||
uint_least32_t * fbline() const { return fbline_; }
|
||||
int pitch() const { return pitch_; }
|
||||
void setBuf(uint_least32_t *const buf, const int pitch) { buf_ = buf; pitch_ = pitch; fbline_ = nullfbline(); }
|
||||
void setFbline(const unsigned ly) { fbline_ = buf_ ? buf_ + static_cast<long>(ly) * static_cast<long>(pitch_) : nullfbline(); }
|
||||
std::ptrdiff_t pitch() const { return pitch_; }
|
||||
void setBuf(uint_least32_t *buf, std::ptrdiff_t pitch) { buf_ = buf; pitch_ = pitch; fbline_ = nullfbline(); }
|
||||
void setFbline(unsigned ly) { fbline_ = buf_ ? buf_ + std::ptrdiff_t(ly) * pitch_ : nullfbline(); }
|
||||
|
||||
private:
|
||||
uint_least32_t *buf_;
|
||||
uint_least32_t *fbline_;
|
||||
std::ptrdiff_t pitch_;
|
||||
|
||||
static uint_least32_t * nullfbline() { static uint_least32_t nullfbline_[160]; return nullfbline_; }
|
||||
};
|
||||
|
||||
struct PPUPriv;
|
||||
|
||||
struct PPUState {
|
||||
void (*f)(struct PPUPriv &v);
|
||||
unsigned (*predictCyclesUntilXpos_f)(const struct PPUPriv &v, int targetxpos, unsigned cycles);
|
||||
void (*f)(PPUPriv &v);
|
||||
unsigned (*predictCyclesUntilXpos_f)(PPUPriv const &v, int targetxpos, unsigned cycles);
|
||||
unsigned char id;
|
||||
};
|
||||
|
||||
// The PPU loop accesses a lot of state at once, so it's difficult to split this up much beyond grouping stuff into smaller structs.
|
||||
struct PPUPriv {
|
||||
unsigned long bgPalette[8 * 4];
|
||||
unsigned long spPalette[8 * 4];
|
||||
|
@ -62,8 +65,8 @@ struct PPUPriv {
|
|||
unsigned char currentSprite;
|
||||
unsigned layersMask;
|
||||
|
||||
const unsigned char *vram;
|
||||
const PPUState *nextCallPtr;
|
||||
unsigned char const *vram;
|
||||
PPUState const *nextCallPtr;
|
||||
|
||||
unsigned long now;
|
||||
unsigned long lastM0Time;
|
||||
|
@ -95,13 +98,12 @@ struct PPUPriv {
|
|||
bool cgb;
|
||||
bool weMaster;
|
||||
|
||||
PPUPriv(NextM0Time &nextM0Time, const unsigned char *oamram, const unsigned char *vram);
|
||||
PPUPriv(NextM0Time &nextM0Time, unsigned char const *oamram, unsigned char const *vram);
|
||||
};
|
||||
|
||||
class PPU {
|
||||
PPUPriv p_;
|
||||
public:
|
||||
PPU(NextM0Time &nextM0Time, const unsigned char *oamram, const unsigned char *vram)
|
||||
PPU(NextM0Time &nextM0Time, unsigned char const *oamram, unsigned char const *vram)
|
||||
: p_(nextM0Time, oamram, vram)
|
||||
{
|
||||
}
|
||||
|
@ -110,25 +112,29 @@ public:
|
|||
bool cgb() const { return p_.cgb; }
|
||||
void doLyCountEvent() { p_.lyCounter.doEvent(); }
|
||||
unsigned long doSpriteMapEvent(unsigned long time) { return p_.spriteMapper.doEvent(time); }
|
||||
const PPUFrameBuf & frameBuf() const { return p_.framebuf; }
|
||||
bool inactivePeriodAfterDisplayEnable(unsigned long cc) const { return p_.spriteMapper.inactivePeriodAfterDisplayEnable(cc); }
|
||||
PPUFrameBuf const & frameBuf() const { return p_.framebuf; }
|
||||
|
||||
bool inactivePeriodAfterDisplayEnable(unsigned long cc) const {
|
||||
return p_.spriteMapper.inactivePeriodAfterDisplayEnable(cc);
|
||||
}
|
||||
|
||||
unsigned long lastM0Time() const { return p_.lastM0Time; }
|
||||
unsigned lcdc() const { return p_.lcdc; }
|
||||
void loadState(const SaveState &state, const unsigned char *oamram);
|
||||
const LyCounter & lyCounter() const { return p_.lyCounter; }
|
||||
void loadState(SaveState const &state, unsigned char const *oamram);
|
||||
LyCounter const & lyCounter() const { return p_.lyCounter; }
|
||||
unsigned long now() const { return p_.now; }
|
||||
void oamChange(unsigned long cc) { p_.spriteMapper.oamChange(cc); }
|
||||
void oamChange(const unsigned char *oamram, unsigned long cc) { p_.spriteMapper.oamChange(oamram, cc); }
|
||||
void oamChange(unsigned char const *oamram, unsigned long cc) { p_.spriteMapper.oamChange(oamram, cc); }
|
||||
unsigned long predictedNextXposTime(unsigned xpos) const;
|
||||
void reset(const unsigned char *oamram, const unsigned char *vram, bool cgb);
|
||||
void reset(unsigned char const *oamram, unsigned char const *vram, bool cgb);
|
||||
void resetCc(unsigned long oldCc, unsigned long newCc);
|
||||
void setFrameBuf(uint_least32_t *buf, unsigned pitch) { p_.framebuf.setBuf(buf, pitch); }
|
||||
void setFrameBuf(uint_least32_t *buf, std::ptrdiff_t pitch) { p_.framebuf.setBuf(buf, pitch); }
|
||||
void setLcdc(unsigned lcdc, unsigned long cc);
|
||||
void setScx(const unsigned scx) { p_.scx = scx; }
|
||||
void setScy(const unsigned scy) { p_.scy = scy; }
|
||||
void setScx(unsigned scx) { p_.scx = scx; }
|
||||
void setScy(unsigned scy) { p_.scy = scy; }
|
||||
void setStatePtrs(SaveState &ss) { p_.spriteMapper.setStatePtrs(ss); }
|
||||
void setWx(const unsigned wx) { p_.wx = wx; }
|
||||
void setWy(const unsigned wy) { p_.wy = wy; }
|
||||
void setWx(unsigned wx) { p_.wx = wx; }
|
||||
void setWy(unsigned wy) { p_.wy = wy; }
|
||||
void updateWy2() { p_.wy2 = p_.wy; }
|
||||
void speedChange(unsigned long cycleCounter);
|
||||
unsigned long * spPalette() { return p_.spPalette; }
|
||||
|
@ -136,6 +142,10 @@ public:
|
|||
void setLayers(unsigned mask) { p_.layersMask = mask; }
|
||||
void setCgb(bool cgb) { p_.cgb = cgb; }
|
||||
|
||||
private:
|
||||
PPUPriv p_;
|
||||
|
||||
public:
|
||||
template<bool isReader>void SyncState(NewState *ns);
|
||||
};
|
||||
|
||||
|
|
|
@ -1,81 +1,96 @@
|
|||
/***************************************************************************
|
||||
* Copyright (C) 2007 by Sindre Aamås *
|
||||
* aamas@stud.ntnu.no *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License version 2 as *
|
||||
* published by the Free Software Foundation. *
|
||||
* *
|
||||
* 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 version 2 for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* version 2 along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
//
|
||||
// Copyright (C) 2007 by sinamas <sinamas at users.sourceforge.net>
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License version 2 as
|
||||
// published by the Free Software Foundation.
|
||||
//
|
||||
// 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 version 2 for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// version 2 along with this program; if not, write to the
|
||||
// Free Software Foundation, Inc.,
|
||||
// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
//
|
||||
|
||||
#include "sprite_mapper.h"
|
||||
#include "counterdef.h"
|
||||
#include "next_m0_time.h"
|
||||
#include "../insertion_sort.h"
|
||||
#include <cstring>
|
||||
#include <algorithm>
|
||||
#include <cstring>
|
||||
|
||||
namespace {
|
||||
|
||||
class SpxLess {
|
||||
public:
|
||||
explicit SpxLess(unsigned char const *spxlut) : spxlut_(spxlut) {}
|
||||
|
||||
bool operator()(unsigned char lhs, unsigned char rhs) const {
|
||||
return spxlut_[lhs] < spxlut_[rhs];
|
||||
}
|
||||
|
||||
private:
|
||||
unsigned char const *const spxlut_;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
namespace gambatte {
|
||||
|
||||
SpriteMapper::OamReader::OamReader(const LyCounter &lyCounter, const unsigned char *oamram)
|
||||
: lyCounter(lyCounter), oamram(oamram), cgb_(false) {
|
||||
SpriteMapper::OamReader::OamReader(LyCounter const &lyCounter, unsigned char const *oamram)
|
||||
: lyCounter_(lyCounter)
|
||||
, oamram_(oamram)
|
||||
, cgb_(false)
|
||||
{
|
||||
reset(oamram, false);
|
||||
}
|
||||
|
||||
void SpriteMapper::OamReader::reset(const unsigned char *const oamram, const bool cgb) {
|
||||
this->oamram = oamram;
|
||||
this->cgb_ = cgb;
|
||||
void SpriteMapper::OamReader::reset(unsigned char const *const oamram, bool const cgb) {
|
||||
oamram_ = oamram;
|
||||
cgb_ = cgb;
|
||||
setLargeSpritesSrc(false);
|
||||
lu = 0;
|
||||
lastChange = 0xFF;
|
||||
std::fill_n(szbuf, 40, largeSpritesSrc);
|
||||
lu_ = 0;
|
||||
lastChange_ = 0xFF;
|
||||
std::fill(szbuf_, szbuf_ + 40, largeSpritesSrc_);
|
||||
|
||||
unsigned pos = 0;
|
||||
unsigned distance = 80;
|
||||
|
||||
while (distance--) {
|
||||
buf[pos] = oamram[((pos * 2) & ~3) | (pos & 1)];
|
||||
buf_[pos] = oamram[((pos * 2) & ~3) | (pos & 1)];
|
||||
++pos;
|
||||
}
|
||||
}
|
||||
|
||||
static unsigned toPosCycles(const unsigned long cc, const LyCounter &lyCounter) {
|
||||
static unsigned toPosCycles(unsigned long const cc, LyCounter const &lyCounter) {
|
||||
unsigned lc = lyCounter.lineCycles(cc) + 3 - lyCounter.isDoubleSpeed() * 3u;
|
||||
|
||||
if (lc >= 456)
|
||||
lc -= 456;
|
||||
|
||||
return lc;
|
||||
}
|
||||
|
||||
void SpriteMapper::OamReader::update(const unsigned long cc) {
|
||||
if (cc > lu) {
|
||||
void SpriteMapper::OamReader::update(unsigned long const cc) {
|
||||
if (cc > lu_) {
|
||||
if (changed()) {
|
||||
const unsigned lulc = toPosCycles(lu, lyCounter);
|
||||
|
||||
unsigned const lulc = toPosCycles(lu_, lyCounter_);
|
||||
unsigned pos = std::min(lulc, 80u);
|
||||
unsigned distance = 80;
|
||||
|
||||
if ((cc - lu) >> lyCounter.isDoubleSpeed() < 456) {
|
||||
const unsigned cclc = toPosCycles(cc, lyCounter);
|
||||
|
||||
if ((cc - lu_) >> lyCounter_.isDoubleSpeed() < 456) {
|
||||
unsigned cclc = toPosCycles(cc, lyCounter_);
|
||||
distance = std::min(cclc, 80u) - pos + (cclc < lulc ? 80 : 0);
|
||||
}
|
||||
|
||||
{
|
||||
const unsigned targetDistance = lastChange - pos + (lastChange <= pos ? 80 : 0);
|
||||
|
||||
unsigned targetDistance =
|
||||
lastChange_ - pos + (lastChange_ <= pos ? 80 : 0);
|
||||
if (targetDistance <= distance) {
|
||||
distance = targetDistance;
|
||||
lastChange = 0xFF;
|
||||
lastChange_ = 0xFF;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -85,91 +100,90 @@ void SpriteMapper::OamReader::update(const unsigned long cc) {
|
|||
pos = 0;
|
||||
|
||||
if (cgb_)
|
||||
szbuf[pos >> 1] = largeSpritesSrc;
|
||||
szbuf_[pos >> 1] = largeSpritesSrc_;
|
||||
|
||||
buf[pos ] = oamram[pos * 2 ];
|
||||
buf[pos + 1] = oamram[pos * 2 + 1];
|
||||
buf_[pos ] = oamram_[pos * 2 ];
|
||||
buf_[pos + 1] = oamram_[pos * 2 + 1];
|
||||
} else
|
||||
szbuf[pos >> 1] = (szbuf[pos >> 1] & cgb_) | largeSpritesSrc;
|
||||
szbuf_[pos >> 1] = (szbuf_[pos >> 1] & cgb_) | largeSpritesSrc_;
|
||||
|
||||
++pos;
|
||||
}
|
||||
}
|
||||
|
||||
lu = cc;
|
||||
lu_ = cc;
|
||||
}
|
||||
}
|
||||
|
||||
void SpriteMapper::OamReader::change(const unsigned long cc) {
|
||||
void SpriteMapper::OamReader::change(unsigned long cc) {
|
||||
update(cc);
|
||||
lastChange = std::min(toPosCycles(lu, lyCounter), 80u);
|
||||
lastChange_ = std::min(toPosCycles(lu_, lyCounter_), 80u);
|
||||
}
|
||||
|
||||
void SpriteMapper::OamReader::setStatePtrs(SaveState &state) {
|
||||
state.ppu.oamReaderBuf.set(buf, sizeof buf);
|
||||
state.ppu.oamReaderSzbuf.set(szbuf, sizeof szbuf / sizeof *szbuf);
|
||||
state.ppu.oamReaderBuf.set(buf_, sizeof buf_);
|
||||
state.ppu.oamReaderSzbuf.set(szbuf_, sizeof szbuf_ / sizeof *szbuf_);
|
||||
}
|
||||
|
||||
void SpriteMapper::OamReader::loadState(const SaveState &ss, const unsigned char *const oamram) {
|
||||
this->oamram = oamram;
|
||||
largeSpritesSrc = ss.mem.ioamhram.get()[0x140] >> 2 & 1;
|
||||
lu = ss.ppu.enableDisplayM0Time;
|
||||
change(lu);
|
||||
void SpriteMapper::OamReader::loadState(SaveState const &ss, unsigned char const *const oamram) {
|
||||
oamram_ = oamram;
|
||||
largeSpritesSrc_ = ss.mem.ioamhram.get()[0x140] >> 2 & 1;
|
||||
lu_ = ss.ppu.enableDisplayM0Time;
|
||||
change(lu_);
|
||||
}
|
||||
|
||||
SYNCFUNC(SpriteMapper::OamReader)
|
||||
{
|
||||
NSS(buf);
|
||||
NSS(szbuf);
|
||||
NSS(buf_);
|
||||
NSS(szbuf_);
|
||||
|
||||
NSS(lu);
|
||||
NSS(lastChange);
|
||||
NSS(largeSpritesSrc);
|
||||
NSS(lu_);
|
||||
NSS(lastChange_);
|
||||
NSS(largeSpritesSrc_);
|
||||
NSS(cgb_);
|
||||
}
|
||||
|
||||
void SpriteMapper::OamReader::enableDisplay(const unsigned long cc) {
|
||||
std::memset(buf, 0x00, sizeof buf);
|
||||
std::fill(szbuf, szbuf + 40, false);
|
||||
lu = cc + (80 << lyCounter.isDoubleSpeed());
|
||||
lastChange = 80;
|
||||
void SpriteMapper::OamReader::enableDisplay(unsigned long cc) {
|
||||
std::memset(buf_, 0x00, sizeof buf_);
|
||||
std::fill(szbuf_, szbuf_ + 40, false);
|
||||
lu_ = cc + (80 << lyCounter_.isDoubleSpeed());
|
||||
lastChange_ = 80;
|
||||
}
|
||||
|
||||
SpriteMapper::SpriteMapper(NextM0Time &nextM0Time,
|
||||
const LyCounter &lyCounter,
|
||||
const unsigned char *const oamram) :
|
||||
nextM0Time_(nextM0Time),
|
||||
oamReader(lyCounter, oamram)
|
||||
LyCounter const &lyCounter,
|
||||
unsigned char const *oamram)
|
||||
: nextM0Time_(nextM0Time)
|
||||
, oamReader_(lyCounter, oamram)
|
||||
{
|
||||
clearMap();
|
||||
}
|
||||
|
||||
void SpriteMapper::reset(const unsigned char *const oamram, const bool cgb) {
|
||||
oamReader.reset(oamram, cgb);
|
||||
void SpriteMapper::reset(unsigned char const *oamram, bool cgb) {
|
||||
oamReader_.reset(oamram, cgb);
|
||||
clearMap();
|
||||
}
|
||||
|
||||
void SpriteMapper::clearMap() {
|
||||
std::memset(num, NEED_SORTING_MASK, sizeof num);
|
||||
std::memset(num_, need_sorting_mask, sizeof num_);
|
||||
}
|
||||
|
||||
void SpriteMapper::mapSprites() {
|
||||
clearMap();
|
||||
|
||||
for (unsigned i = 0x00; i < 0x50; i += 2) {
|
||||
const int spriteHeight = 8 << largeSprites(i >> 1);
|
||||
const unsigned bottom_pos = posbuf()[i] - (17u - spriteHeight);
|
||||
int const spriteHeight = 8 << largeSprites(i >> 1);
|
||||
unsigned const bottomPos = posbuf()[i] - (17u - spriteHeight);
|
||||
|
||||
if (bottom_pos < 143u + spriteHeight) {
|
||||
const unsigned startly = static_cast<int>(bottom_pos) + 1 - spriteHeight >= 0
|
||||
? static_cast<int>(bottom_pos) + 1 - spriteHeight : 0;
|
||||
unsigned char *map = spritemap + startly * 10;
|
||||
unsigned char *n = num + startly;
|
||||
unsigned char *const nend = num + (bottom_pos < 143 ? bottom_pos : 143) + 1;
|
||||
if (bottomPos < 143u + spriteHeight) {
|
||||
unsigned const startly = std::max(int(bottomPos) + 1 - spriteHeight, 0);
|
||||
unsigned char *map = spritemap_ + startly * 10;
|
||||
unsigned char *n = num_ + startly;
|
||||
unsigned char *const nend = num_ + std::min(bottomPos, 143u) + 1;
|
||||
|
||||
do {
|
||||
if (*n < NEED_SORTING_MASK + 10)
|
||||
map[(*n)++ - NEED_SORTING_MASK] = i;
|
||||
if (*n < need_sorting_mask + 10)
|
||||
map[(*n)++ - need_sorting_mask] = i;
|
||||
|
||||
map += 10;
|
||||
} while (++n != nend);
|
||||
|
@ -179,24 +193,27 @@ void SpriteMapper::mapSprites() {
|
|||
nextM0Time_.invalidatePredictedNextM0Time();
|
||||
}
|
||||
|
||||
void SpriteMapper::sortLine(const unsigned ly) const {
|
||||
num[ly] &= ~NEED_SORTING_MASK;
|
||||
insertionSort(spritemap + ly * 10, spritemap + ly * 10 + num[ly], SpxLess(posbuf()));
|
||||
void SpriteMapper::sortLine(unsigned const ly) const {
|
||||
num_[ly] &= ~need_sorting_mask;
|
||||
insertionSort(spritemap_ + ly * 10, spritemap_ + ly * 10 + num_[ly],
|
||||
SpxLess(posbuf() + 1));
|
||||
}
|
||||
|
||||
unsigned long SpriteMapper::doEvent(const unsigned long time) {
|
||||
oamReader.update(time);
|
||||
unsigned long SpriteMapper::doEvent(unsigned long const time) {
|
||||
oamReader_.update(time);
|
||||
mapSprites();
|
||||
return oamReader.changed() ? time + oamReader.lyCounter.lineTime() : static_cast<unsigned long>(DISABLED_TIME);
|
||||
return oamReader_.changed()
|
||||
? time + oamReader_.lineTime()
|
||||
: static_cast<unsigned long>(disabled_time);
|
||||
}
|
||||
|
||||
SYNCFUNC(SpriteMapper)
|
||||
{
|
||||
NSS(spritemap);
|
||||
NSS(num);
|
||||
NSS(spritemap_);
|
||||
NSS(num_);
|
||||
|
||||
SSS(nextM0Time_);
|
||||
SSS(oamReader);
|
||||
SSS(oamReader_);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,21 +1,21 @@
|
|||
/***************************************************************************
|
||||
* Copyright (C) 2007 by Sindre Aamås *
|
||||
* aamas@stud.ntnu.no *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License version 2 as *
|
||||
* published by the Free Software Foundation. *
|
||||
* *
|
||||
* 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 version 2 for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* version 2 along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
//
|
||||
// Copyright (C) 2007 by sinamas <sinamas at users.sourceforge.net>
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License version 2 as
|
||||
// published by the Free Software Foundation.
|
||||
//
|
||||
// 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 version 2 for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// version 2 along with this program; if not, write to the
|
||||
// Free Software Foundation, Inc.,
|
||||
// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
//
|
||||
|
||||
#ifndef SPRITE_MAPPER_H
|
||||
#define SPRITE_MAPPER_H
|
||||
|
||||
|
@ -24,106 +24,101 @@
|
|||
#include "newstate.h"
|
||||
|
||||
namespace gambatte {
|
||||
|
||||
class NextM0Time;
|
||||
|
||||
class SpriteMapper {
|
||||
class OamReader {
|
||||
unsigned char buf[80];
|
||||
bool szbuf[40];
|
||||
public:
|
||||
SpriteMapper(NextM0Time &nextM0Time,
|
||||
LyCounter const &lyCounter,
|
||||
unsigned char const *oamram);
|
||||
void reset(unsigned char const *oamram, bool cgb);
|
||||
unsigned long doEvent(unsigned long time);
|
||||
bool largeSprites(unsigned spNo) const { return oamReader_.largeSprites(spNo); }
|
||||
unsigned numSprites(unsigned ly) const { return num_[ly] & ~need_sorting_mask; }
|
||||
void oamChange(unsigned long cc) { oamReader_.change(cc); }
|
||||
void oamChange(unsigned char const *oamram, unsigned long cc) { oamReader_.change(oamram, cc); }
|
||||
unsigned char const * oamram() const { return oamReader_.oam(); }
|
||||
unsigned char const * posbuf() const { return oamReader_.spritePosBuf(); }
|
||||
void preSpeedChange(unsigned long cc) { oamReader_.update(cc); }
|
||||
void postSpeedChange(unsigned long cc) { oamReader_.change(cc); }
|
||||
|
||||
void resetCycleCounter(unsigned long oldCc, unsigned long newCc) {
|
||||
oamReader_.update(oldCc);
|
||||
oamReader_.resetCycleCounter(oldCc, newCc);
|
||||
}
|
||||
|
||||
void setLargeSpritesSource(bool src) { oamReader_.setLargeSpritesSrc(src); }
|
||||
|
||||
unsigned char const * sprites(unsigned ly) const {
|
||||
if (num_[ly] & need_sorting_mask)
|
||||
sortLine(ly);
|
||||
|
||||
return spritemap_ + ly * 10;
|
||||
}
|
||||
|
||||
void setStatePtrs(SaveState &state) { oamReader_.setStatePtrs(state); }
|
||||
void enableDisplay(unsigned long cc) { oamReader_.enableDisplay(cc); }
|
||||
|
||||
void loadState(SaveState const &state, unsigned char const *oamram) {
|
||||
oamReader_.loadState(state, oamram);
|
||||
mapSprites();
|
||||
}
|
||||
|
||||
bool inactivePeriodAfterDisplayEnable(unsigned long cc) const {
|
||||
return oamReader_.inactivePeriodAfterDisplayEnable(cc);
|
||||
}
|
||||
|
||||
static unsigned long schedule(LyCounter const &lyCounter, unsigned long cc) {
|
||||
return lyCounter.nextLineCycle(80, cc);
|
||||
}
|
||||
|
||||
private:
|
||||
class OamReader {
|
||||
public:
|
||||
const LyCounter &lyCounter;
|
||||
OamReader(LyCounter const &lyCounter, unsigned char const *oamram);
|
||||
void reset(unsigned char const *oamram, bool cgb);
|
||||
void change(unsigned long cc);
|
||||
void change(unsigned char const *oamram, unsigned long cc) { change(cc); oamram_ = oamram; }
|
||||
bool changed() const { return lastChange_ != 0xFF; }
|
||||
bool largeSprites(unsigned spNo) const { return szbuf_[spNo]; }
|
||||
unsigned char const * oam() const { return oamram_; }
|
||||
void resetCycleCounter(unsigned long oldCc, unsigned long newCc) { lu_ -= oldCc - newCc; }
|
||||
void setLargeSpritesSrc(bool src) { largeSpritesSrc_ = src; }
|
||||
void update(unsigned long cc);
|
||||
unsigned char const * spritePosBuf() const { return buf_; }
|
||||
void setStatePtrs(SaveState &state);
|
||||
void enableDisplay(unsigned long cc);
|
||||
void loadState(SaveState const &ss, unsigned char const *oamram);
|
||||
bool inactivePeriodAfterDisplayEnable(unsigned long cc) const { return cc < lu_; }
|
||||
unsigned lineTime() const { return lyCounter_.lineTime(); }
|
||||
|
||||
private:
|
||||
const unsigned char *oamram;
|
||||
unsigned long lu;
|
||||
unsigned char lastChange;
|
||||
bool largeSpritesSrc;
|
||||
unsigned char buf_[80];
|
||||
bool szbuf_[40];
|
||||
LyCounter const &lyCounter_;
|
||||
unsigned char const *oamram_;
|
||||
unsigned long lu_;
|
||||
unsigned char lastChange_;
|
||||
bool largeSpritesSrc_;
|
||||
bool cgb_;
|
||||
|
||||
public:
|
||||
OamReader(const LyCounter &lyCounter, const unsigned char *oamram);
|
||||
void reset(const unsigned char *oamram, bool cgb);
|
||||
void change(unsigned long cc);
|
||||
void change(const unsigned char *oamram, unsigned long cc) { change(cc); this->oamram = oamram; }
|
||||
bool changed() const { return lastChange != 0xFF; }
|
||||
bool largeSprites(unsigned spNr) const { return szbuf[spNr]; }
|
||||
const unsigned char *oam() const { return oamram; }
|
||||
void resetCycleCounter(const unsigned long oldCc, const unsigned long newCc) { lu -= oldCc - newCc; }
|
||||
void setLargeSpritesSrc(const bool src) { largeSpritesSrc = src; }
|
||||
void update(unsigned long cc);
|
||||
const unsigned char *spritePosBuf() const { return buf; }
|
||||
void setStatePtrs(SaveState &state);
|
||||
void enableDisplay(unsigned long cc);
|
||||
void loadState(const SaveState &ss, const unsigned char *oamram);
|
||||
bool inactivePeriodAfterDisplayEnable(const unsigned long cc) const { return cc < lu; }
|
||||
|
||||
template<bool isReader>void SyncState(NewState *ns);
|
||||
};
|
||||
|
||||
enum { NEED_SORTING_MASK = 0x80 };
|
||||
|
||||
public:
|
||||
class SpxLess {
|
||||
const unsigned char *const posbuf_plus1;
|
||||
|
||||
public:
|
||||
explicit SpxLess(const unsigned char *const posbuf) : posbuf_plus1(posbuf + 1) {}
|
||||
|
||||
bool operator()(const unsigned char l, const unsigned char r) const {
|
||||
return posbuf_plus1[l] < posbuf_plus1[r];
|
||||
}
|
||||
};
|
||||
|
||||
private:
|
||||
mutable unsigned char spritemap[144*10];
|
||||
mutable unsigned char num[144];
|
||||
enum { need_sorting_mask = 0x80 };
|
||||
|
||||
mutable unsigned char spritemap_[144 * 10];
|
||||
mutable unsigned char num_[144];
|
||||
NextM0Time &nextM0Time_;
|
||||
OamReader oamReader;
|
||||
OamReader oamReader_;
|
||||
|
||||
void clearMap();
|
||||
void mapSprites();
|
||||
void sortLine(unsigned ly) const;
|
||||
|
||||
public:
|
||||
SpriteMapper(NextM0Time &nextM0Time,
|
||||
const LyCounter &lyCounter,
|
||||
const unsigned char *oamram_in);
|
||||
void reset(const unsigned char *oamram, bool cgb);
|
||||
unsigned long doEvent(unsigned long time);
|
||||
bool largeSprites(unsigned spNr) const { return oamReader.largeSprites(spNr); }
|
||||
unsigned numSprites(const unsigned ly) const { return num[ly] & ~NEED_SORTING_MASK; }
|
||||
void oamChange(unsigned long cc) { oamReader.change(cc); }
|
||||
void oamChange(const unsigned char *oamram, unsigned long cc) { oamReader.change(oamram, cc); }
|
||||
const unsigned char *oamram() const { return oamReader.oam(); }
|
||||
const unsigned char *posbuf() const { return oamReader.spritePosBuf(); }
|
||||
void preSpeedChange(const unsigned long cc) { oamReader.update(cc); }
|
||||
void postSpeedChange(const unsigned long cc) { oamReader.change(cc); }
|
||||
|
||||
void resetCycleCounter(const unsigned long oldCc, const unsigned long newCc) {
|
||||
oamReader.update(oldCc);
|
||||
oamReader.resetCycleCounter(oldCc, newCc);
|
||||
}
|
||||
|
||||
static unsigned long schedule(const LyCounter &lyCounter, const unsigned long cycleCounter) {
|
||||
return lyCounter.nextLineCycle(80, cycleCounter);
|
||||
}
|
||||
|
||||
void setLargeSpritesSource(bool src) { oamReader.setLargeSpritesSrc(src); }
|
||||
|
||||
const unsigned char* sprites(const unsigned ly) const {
|
||||
if (num[ly] & NEED_SORTING_MASK)
|
||||
sortLine(ly);
|
||||
|
||||
return spritemap + ly * 10;
|
||||
}
|
||||
|
||||
void setStatePtrs(SaveState &state) { oamReader.setStatePtrs(state); }
|
||||
void enableDisplay(unsigned long cc) { oamReader.enableDisplay(cc); }
|
||||
void loadState(const SaveState &state, const unsigned char *const oamram) { oamReader.loadState(state, oamram); mapSprites(); }
|
||||
bool inactivePeriodAfterDisplayEnable(unsigned long cc) const { return oamReader.inactivePeriodAfterDisplayEnable(cc); }
|
||||
|
||||
template<bool isReader>void SyncState(NewState *ns);
|
||||
};
|
||||
|
||||
|
|
Binary file not shown.
Loading…
Reference in New Issue