BizHawk/libgambatte/src/memory.h

345 lines
10 KiB
C++

/***************************************************************************
* 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. *
***************************************************************************/
#ifndef MEMORY_H
#define MEMORY_H
static unsigned char const agbOverride[0xD] = { 0xFF, 0x00, 0xCD, 0x03, 0x35, 0xAA, 0x31, 0x90, 0x94, 0x00, 0x00, 0x00, 0x00 };
#include "mem/cartridge.h"
#include "video.h"
#include "sound.h"
#include "interrupter.h"
#include "tima.h"
#include "newstate.h"
#include "gambatte.h"
namespace gambatte {
class InputGetter;
class FilterInfo;
class Memory {
Cartridge cart;
unsigned char ioamhram[0x200];
unsigned char cgbBios[0x900];
unsigned char dmgBios[0x100];
bool biosMode;
bool cgbSwitching;
bool agbMode;
bool gbIsCgb_;
bool stopped;
unsigned short &SP;
unsigned short &PC;
unsigned long basetime;
unsigned long halttime;
MemoryCallback readCallback;
MemoryCallback writeCallback;
MemoryCallback execCallback;
CDCallback cdCallback;
void(*linkCallback)();
unsigned (*getInput)();
unsigned long divLastUpdate;
unsigned long lastOamDmaUpdate;
InterruptRequester intreq;
Tima tima;
LCD display;
PSG sound;
Interrupter interrupter;
unsigned short dmaSource;
unsigned short dmaDestination;
unsigned char oamDmaPos;
unsigned char serialCnt;
bool blanklcd;
bool LINKCABLE;
bool linkClockTrigger;
void decEventCycles(MemEventId eventId, unsigned long dec);
void oamDmaInitSetup();
void updateOamDma(unsigned long cycleCounter);
void startOamDma(unsigned long cycleCounter);
void endOamDma(unsigned long cycleCounter);
const unsigned char * oamDmaSrcPtr() const;
unsigned nontrivial_ff_read(unsigned P, unsigned long cycleCounter);
unsigned nontrivial_read(unsigned P, unsigned long cycleCounter);
void nontrivial_ff_write(unsigned P, unsigned data, unsigned long cycleCounter);
void nontrivial_write(unsigned P, unsigned data, unsigned long cycleCounter);
unsigned nontrivial_peek(unsigned P);
unsigned nontrivial_ff_peek(unsigned P);
void updateSerial(unsigned long cc);
void updateTimaIrq(unsigned long cc);
void updateIrqs(unsigned long cc);
bool isDoubleSpeed() const { return display.isDoubleSpeed(); }
public:
explicit Memory(const Interrupter &interrupter, unsigned short &sp, unsigned short &pc);
bool loaded() const { return cart.loaded(); }
unsigned curRomBank() const { return cart.curRomBank(); }
const char * romTitle() const { return cart.romTitle(); }
int debugGetLY() const { return display.debugGetLY(); }
void setStatePtrs(SaveState &state);
void loadState(const SaveState &state/*, unsigned long oldCc*/);
void loadSavedata(const char *data) { cart.loadSavedata(data); }
int saveSavedataLength() {return cart.saveSavedataLength(); }
void saveSavedata(char *dest) { cart.saveSavedata(dest); }
void updateInput();
unsigned char* cgbBiosBuffer() { return (unsigned char*)cgbBios; }
unsigned char* dmgBiosBuffer() { return (unsigned char*)dmgBios; }
bool gbIsCgb() { return gbIsCgb_; }
bool getMemoryArea(int which, unsigned char **data, int *length); // { return cart.getMemoryArea(which, data, length); }
unsigned long stop(unsigned long cycleCounter);
bool isCgb() const { return display.isCgb(); }
bool ime() const { return intreq.ime(); }
bool halted() const { return intreq.halted(); }
unsigned long nextEventTime() const { return intreq.minEventTime(); }
void setLayers(unsigned mask) { display.setLayers(mask); }
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());
}
void halt(unsigned long cycleCounter) { halttime = cycleCounter; intreq.halt(); }
void ei(unsigned long cycleCounter) { if (!ime()) { intreq.ei(cycleCounter); } }
void di() { intreq.di(); }
unsigned ff_read(const unsigned P, const unsigned long cycleCounter) {
if (readCallback)
readCallback(P, (cycleCounter - basetime) >> 1);
return P < 0xFF80 ? nontrivial_ff_read(P, cycleCounter) : ioamhram[P - 0xFE00];
}
struct CDMapResult
{
eCDLog_AddrType type;
unsigned addr;
};
CDMapResult CDMap(const unsigned P) const
{
if(P<0x4000)
{
CDMapResult ret = { eCDLog_AddrType_ROM, P };
return ret;
}
else if(P<0x8000)
{
unsigned bank = cart.rmem(P>>12) - cart.rmem(0);
unsigned addr = P+bank;
CDMapResult ret = { eCDLog_AddrType_ROM, addr };
return ret;
}
else if(P<0xA000) {}
else if(P<0xC000)
{
if(cart.wsrambankptr())
{
//not bankable. but. we're not sure how much might be here
unsigned char *data;
int length;
bool has = cart.getMemoryArea(3,&data,&length);
unsigned addr = P&(length-1);
if(has && length!=0)
{
CDMapResult ret = { eCDLog_AddrType_CartRAM, addr };
return ret;
}
}
}
else if(P<0xE000)
{
unsigned bank = cart.wramdata(P >> 12 & 1) - cart.wramdata(0);
unsigned addr = (P&0xFFF)+bank;
CDMapResult ret = { eCDLog_AddrType_WRAM, addr };
return ret;
}
else if(P<0xFF80) {}
else
{
////this is just for debugging, really, it's pretty useless
//CDMapResult ret = { eCDLog_AddrType_HRAM, (P-0xFF80) };
//return ret;
}
CDMapResult ret = { eCDLog_AddrType_None };
return ret;
}
unsigned readBios(const unsigned P) {
if (gbIsCgb_) {
if (agbMode && P >= 0xF3 && P < 0x100) {
return (agbOverride[P - 0xF3] + cgbBios[P]) & 0xFF;
}
return cgbBios[P];
}
return dmgBios[P];
}
unsigned read(const unsigned P, const unsigned long cycleCounter) {
if (readCallback)
readCallback(P, (cycleCounter - basetime) >> 1);
if(cdCallback)
{
CDMapResult map = CDMap(P);
if(map.type != eCDLog_AddrType_None)
cdCallback(map.addr,map.type,eCDLog_Flags_Data);
}
if (biosMode && ((!gbIsCgb_ && P < 0x100) || (gbIsCgb_ && P < 0x900 && (P < 0x100 || P >= 0x200)))) {
return readBios(P);
}
return cart.rmem(P >> 12) ? cart.rmem(P >> 12)[P] : nontrivial_read(P, cycleCounter);
}
unsigned read_excb(const unsigned P, const unsigned long cycleCounter, bool first) {
if (execCallback)
execCallback(P, (cycleCounter - basetime) >> 1);
if(cdCallback)
{
CDMapResult map = CDMap(P);
if(map.type != eCDLog_AddrType_None)
cdCallback(map.addr,map.type,first?eCDLog_Flags_ExecFirst : eCDLog_Flags_ExecOperand);
}
if (biosMode && ((!gbIsCgb_ && P < 0x100) || (gbIsCgb_ && P < 0x900 && (P < 0x100 || P >= 0x200)))) {
return readBios(P);
}
return cart.rmem(P >> 12) ? cart.rmem(P >> 12)[P] : nontrivial_read(P, cycleCounter);
}
unsigned peek(const unsigned P) {
if (biosMode && ((!gbIsCgb_ && P < 0x100) || (gbIsCgb_ && P < 0x900 && (P < 0x100 || P >= 0x200)))) {
return readBios(P);
}
return cart.rmem(P >> 12) ? cart.rmem(P >> 12)[P] : nontrivial_peek(P);
}
void write_nocb(const unsigned P, const unsigned data, const unsigned long cycleCounter) {
if (cart.wmem(P >> 12)) {
cart.wmem(P >> 12)[P] = data;
} else
nontrivial_write(P, data, cycleCounter);
}
void write(const unsigned P, const unsigned data, const unsigned long cycleCounter) {
if (cart.wmem(P >> 12)) {
cart.wmem(P >> 12)[P] = data;
} else
nontrivial_write(P, data, cycleCounter);
if (writeCallback)
writeCallback(P, (cycleCounter - basetime) >> 1);
if(cdCallback)
{
CDMapResult map = CDMap(P);
if(map.type != eCDLog_AddrType_None)
cdCallback(map.addr,map.type,eCDLog_Flags_Data);
}
}
void ff_write(const unsigned P, const unsigned data, const unsigned long cycleCounter) {
if (P - 0xFF80u < 0x7Fu) {
ioamhram[P - 0xFE00] = data;
} else
nontrivial_ff_write(P, data, cycleCounter);
if (writeCallback)
writeCallback(P, (cycleCounter - basetime) >> 1);
if(cdCallback)
{
CDMapResult map = CDMap(P);
if(map.type != eCDLog_AddrType_None)
cdCallback(map.addr,map.type,eCDLog_Flags_Data);
}
}
unsigned long event(unsigned long cycleCounter);
unsigned long resetCounters(unsigned long cycleCounter);
int loadROM(const char *romfiledata, unsigned romfilelength, bool forceDmg, bool multicartCompat);
void setInputGetter(unsigned (*getInput)()) {
this->getInput = getInput;
}
void setReadCallback(MemoryCallback callback) {
this->readCallback = callback;
}
void setWriteCallback(MemoryCallback callback) {
this->writeCallback = callback;
}
void setExecCallback(MemoryCallback callback) {
this->execCallback = callback;
}
void setCDCallback(CDCallback cdc) {
this->cdCallback = cdc;
}
void setScanlineCallback(void (*callback)(), int sl) {
display.setScanlineCallback(callback, sl);
}
void setRTCCallback(std::uint32_t (*callback)()) {
cart.setRTCCallback(callback);
}
void setLinkCallback(void(*callback)()) {
this->linkCallback = callback;
}
void setBasetime(unsigned long cc) { basetime = cc; }
void setEndtime(unsigned long cc, unsigned long inc);
void setSoundBuffer(uint_least32_t *const buf) { sound.setBuffer(buf); }
unsigned fillSoundBuffer(unsigned long cc);
void setVideoBuffer(uint_least32_t *const videoBuf, const int pitch) {
display.setVideoBuffer(videoBuf, pitch);
}
void setDmgPaletteColor(unsigned palNum, unsigned colorNum, unsigned long rgb32);
void setCgbPalette(unsigned *lut);
void blackScreen() {
display.blackScreen();
}
int LinkStatus(int which);
template<bool isReader>void SyncState(NewState *ns);
};
}
#endif