Update InterruptRequester

This commit is contained in:
MrWint 2019-05-26 00:13:34 +02:00
parent 6036aefd13
commit 7b518d0cf7
4 changed files with 134 additions and 111 deletions

View File

@ -1,106 +1,120 @@
/***************************************************************************
* 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.
//
#include "interruptrequester.h"
#include "savestate.h"
namespace gambatte {
InterruptRequester::InterruptRequester() : minIntTime(0), ifreg_(0), iereg_(0) {}
InterruptRequester::InterruptRequester()
: eventTimes_(disabled_time)
, minIntTime_(0)
, ifreg_(0)
, iereg_(0)
{
}
void InterruptRequester::loadState(const SaveState &state) {
minIntTime = state.mem.minIntTime;
void InterruptRequester::loadState(SaveState const &state) {
minIntTime_ = state.mem.minIntTime;
ifreg_ = state.mem.ioamhram.get()[0x10F];
iereg_ = state.mem.ioamhram.get()[0x1FF] & 0x1F;
intFlags.set(state.mem.IME, state.mem.halted);
intFlags_.set(state.mem.IME, state.mem.halted);
eventTimes.setValue<intevent_interrupts>(intFlags.imeOrHalted() && pendingIrqs() ? minIntTime : static_cast<unsigned long>(disabled_time));
eventTimes_.setValue<intevent_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);
void InterruptRequester::resetCc(unsigned long oldCc, unsigned long newCc) {
minIntTime_ = minIntTime_ < oldCc ? 0 : minIntTime_ - (oldCc - newCc);
if (eventTimes.value(intevent_interrupts) != disabled_time)
eventTimes.setValue<intevent_interrupts>(minIntTime);
if (eventTimes_.value(intevent_interrupts) != disabled_time)
eventTimes_.setValue<intevent_interrupts>(minIntTime_);
}
void InterruptRequester::ei(const unsigned long cc) {
intFlags.setIme();
minIntTime = cc + 1;
void InterruptRequester::ei(unsigned long cc) {
intFlags_.setIme();
minIntTime_ = cc + 1;
if (pendingIrqs())
eventTimes.setValue<intevent_interrupts>(minIntTime);
eventTimes_.setValue<intevent_interrupts>(minIntTime_);
}
void InterruptRequester::di() {
intFlags.unsetIme();
intFlags_.unsetIme();
if (!intFlags.imeOrHalted())
eventTimes.setValue<intevent_interrupts>(disabled_time);
if (!intFlags_.imeOrHalted())
eventTimes_.setValue<intevent_interrupts>(disabled_time);
}
void InterruptRequester::halt() {
intFlags.setHalted();
intFlags_.setHalted();
if (pendingIrqs())
eventTimes.setValue<intevent_interrupts>(minIntTime);
eventTimes_.setValue<intevent_interrupts>(minIntTime_);
}
void InterruptRequester::unhalt() {
intFlags.unsetHalted();
intFlags_.unsetHalted();
if (!intFlags.imeOrHalted())
eventTimes.setValue<intevent_interrupts>(disabled_time);
if (!intFlags_.imeOrHalted())
eventTimes_.setValue<intevent_interrupts>(disabled_time);
}
void InterruptRequester::flagIrq(const unsigned bit) {
void InterruptRequester::flagIrq(unsigned bit) {
ifreg_ |= bit;
if (intFlags.imeOrHalted() && pendingIrqs())
eventTimes.setValue<intevent_interrupts>(minIntTime);
if (intFlags_.imeOrHalted() && pendingIrqs())
eventTimes_.setValue<intevent_interrupts>(minIntTime_);
}
void InterruptRequester::ackIrq(const unsigned bit) {
void InterruptRequester::ackIrq(unsigned bit) {
ifreg_ ^= bit;
di();
}
void InterruptRequester::setIereg(const unsigned iereg) {
void InterruptRequester::setIereg(unsigned iereg) {
iereg_ = iereg & 0x1F;
if (intFlags.imeOrHalted())
eventTimes.setValue<intevent_interrupts>(pendingIrqs() ? minIntTime : static_cast<unsigned long>(disabled_time));
if (intFlags_.imeOrHalted()) {
eventTimes_.setValue<intevent_interrupts>(pendingIrqs()
? minIntTime_
: static_cast<unsigned long>(disabled_time));
}
}
void InterruptRequester::setIfreg(const unsigned ifreg) {
void InterruptRequester::setIfreg(unsigned ifreg) {
ifreg_ = ifreg;
if (intFlags.imeOrHalted())
eventTimes.setValue<intevent_interrupts>(pendingIrqs() ? minIntTime : static_cast<unsigned long>(disabled_time));
if (intFlags_.imeOrHalted()) {
eventTimes_.setValue<intevent_interrupts>(pendingIrqs()
? minIntTime_
: static_cast<unsigned long>(disabled_time));
}
}
SYNCFUNC(InterruptRequester)
{
SSS(eventTimes);
NSS(minIntTime);
SSS(eventTimes_);
NSS(minIntTime_);
NSS(ifreg_);
NSS(iereg_);
NSS(intFlags.flags_);
NSS(intFlags_.flags_);
}
}

View File

@ -1,21 +1,21 @@
/***************************************************************************
* 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 INTERRUPT_REQUESTER_H
#define INTERRUPT_REQUESTER_H
@ -24,49 +24,29 @@
#include "newstate.h"
namespace gambatte {
struct SaveState;
enum IntEventId { intevent_unhalt, intevent_end, intevent_blit, intevent_serial, intevent_oam, intevent_dma, intevent_tima, intevent_video, intevent_interrupts };
enum IntEventId { intevent_unhalt,
intevent_end,
intevent_blit,
intevent_serial,
intevent_oam,
intevent_dma,
intevent_tima,
intevent_video,
intevent_interrupts, intevent_last = intevent_interrupts };
class InterruptRequester {
MinKeeper<intevent_interrupts + 1> eventTimes;
unsigned long minIntTime;
unsigned ifreg_;
unsigned iereg_;
class IntFlags {
friend class InterruptRequester;
unsigned char flags_;
enum { IME_MASK = 1, HALTED_MASK = 2 };
public:
IntFlags() : flags_(0) {}
bool ime() const { return flags_ & IME_MASK; }
bool halted() const { return flags_ & HALTED_MASK; }
bool imeOrHalted() const { return flags_; }
void setIme() { flags_ |= IME_MASK; }
void unsetIme() { flags_ &= ~IME_MASK; }
void setHalted() { flags_ |= HALTED_MASK; }
void unsetHalted() { flags_ &= ~HALTED_MASK; }
void set(const bool ime, const bool halted) { flags_ = halted * HALTED_MASK + ime * IME_MASK; }
} intFlags;
public:
InterruptRequester();
void loadState(const SaveState &);
void loadState(SaveState const &);
void resetCc(unsigned long oldCc, unsigned long newCc);
unsigned ifreg() const { return ifreg_; }
unsigned iereg() const { return iereg_; }
unsigned pendingIrqs() const { return ifreg_ & iereg_; }
bool ime() const { return intFlags.ime(); }
bool halted() const { return intFlags.halted(); }
bool ime() const { return intFlags_.ime(); }
bool halted() const { return intFlags_.halted(); }
void ei(unsigned long cc);
void di();
void halt();
@ -76,20 +56,47 @@ public:
void setIereg(unsigned iereg);
void setIfreg(unsigned ifreg);
IntEventId minEventId() const { return static_cast<IntEventId>(eventTimes.min()); }
unsigned long minEventTime() const { return eventTimes.minValue(); }
template<IntEventId id> void setEventTime(unsigned long value) { eventTimes.setValue<id>(value); }
void setEventTime(const IntEventId id, unsigned long value) { eventTimes.setValue(id, value); }
unsigned long eventTime(IntEventId id) const { return eventTimes.value(id); }
IntEventId minEventId() const { return static_cast<IntEventId>(eventTimes_.min()); }
unsigned long minEventTime() const { return eventTimes_.minValue(); }
template<IntEventId id> void setEventTime(unsigned long value) { eventTimes_.setValue<id>(value); }
void setEventTime(IntEventId id, unsigned long value) { eventTimes_.setValue(id, value); }
unsigned long eventTime(IntEventId id) const { return eventTimes_.value(id); }
private:
class IntFlags {
friend class InterruptRequester;
public:
IntFlags() : flags_(0) {}
bool ime() const { return flags_ & flag_ime; }
bool halted() const { return flags_ & flag_halted; }
bool imeOrHalted() const { return flags_; }
void setIme() { flags_ |= flag_ime; }
void unsetIme() { flags_ &= ~flag_ime; }
void setHalted() { flags_ |= flag_halted; }
void unsetHalted() { flags_ &= ~flag_halted; }
void set(bool ime, bool halted) { flags_ = halted * flag_halted + ime * flag_ime; }
private:
unsigned char flags_;
enum { flag_ime = 1, flag_halted = 2 };
};
MinKeeper<intevent_last + 1> eventTimes_;
unsigned long minIntTime_;
unsigned ifreg_;
unsigned iereg_;
IntFlags intFlags_;
public:
template<bool isReader>void SyncState(NewState *ns);
};
inline void flagHdmaReq(InterruptRequester &intreq) { intreq.setEventTime<intevent_dma>(0); }
inline void flagGdmaReq(InterruptRequester &intreq) { intreq.setEventTime<intevent_dma>(1); }
inline void ackDmaReq(InterruptRequester &intreq) { intreq.setEventTime<intevent_dma>(disabled_time); }
inline bool hdmaReqFlagged(const InterruptRequester &intreq) { return intreq.eventTime(intevent_dma) == 0; }
inline bool gdmaReqFlagged(const InterruptRequester &intreq) { return intreq.eventTime(intevent_dma) == 1; }
inline bool hdmaReqFlagged(InterruptRequester const &intreq) { return intreq.eventTime(intevent_dma) == 0; }
inline bool gdmaReqFlagged(InterruptRequester const &intreq) { return intreq.eventTime(intevent_dma) == 1; }
}

View File

@ -593,6 +593,8 @@ LoadRes Cartridge::loadROM(const char *romfiledata, unsigned romfilelength, bool
case 0x1C:
case 0x1D:
case 0x1E: type = MBC5; break;
case 0x20: return LOADRES_UNSUPPORTED_MBC_MBC6;
case 0x22: return LOADRES_UNSUPPORTED_MBC_MBC7;
case 0xFC: return LOADRES_UNSUPPORTED_MBC_POCKET_CAMERA;
case 0xFD: return LOADRES_UNSUPPORTED_MBC_TAMA5;
case 0xFE: return LOADRES_UNSUPPORTED_MBC_HUC3;

Binary file not shown.