diff --git a/BizHawk.Emulation.Common/Database/FirmwareDatabase.cs b/BizHawk.Emulation.Common/Database/FirmwareDatabase.cs
index fc48c80b9d..af3d781483 100644
--- a/BizHawk.Emulation.Common/Database/FirmwareDatabase.cs
+++ b/BizHawk.Emulation.Common/Database/FirmwareDatabase.cs
@@ -205,6 +205,9 @@ namespace BizHawk.Emulation.Common
FirmwareAndOption("b2e1955d957a475de2411770452eff4ea19f4cee", 1024, "O2", "BIOS", "Odyssey2.bin", "Odyssey 2 Bios");
FirmwareAndOption("a6120aed50831c9c0d95dbdf707820f601d9452e", 1024, "O2", "BIOS-C52", "PhillipsC52.bin", "Phillips C52 Bios");
+
+ FirmwareAndOption("4ED31EC6B0B175BB109C0EB5FD3D193DA823339F", 256, "GB", "World", "GB_boot_ROM.gb", "Game Boy BIOS");
+ FirmwareAndOption("1293D68BF9643BC4F36954C1E80E38F39864528D", 2304, "GBC", "World", "GBC_boot_ROM.gb", "Game Boy Color BIOS");
}
// adds a defined firmware ID to the database
@@ -336,4 +339,4 @@ namespace BizHawk.Emulation.Common
return found.FirstOrDefault();
}
} // static class FirmwareDatabase
-}
\ No newline at end of file
+}
diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/Gambatte.IEmulator.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/Gambatte.IEmulator.cs
index b13d7e4dc8..38c11b0234 100644
--- a/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/Gambatte.IEmulator.cs
+++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/Gambatte.IEmulator.cs
@@ -95,8 +95,11 @@ namespace BizHawk.Emulation.Cores.Nintendo.Gameboy
{
if (GambatteState != IntPtr.Zero)
{
+ Console.WriteLine("disposing");
LibGambatte.gambatte_destroy(GambatteState);
+ Console.WriteLine("step2");
GambatteState = IntPtr.Zero;
+ Console.WriteLine("disposed");
}
DisposeSound();
diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/Gambatte.ISettable.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/Gambatte.ISettable.cs
index f6cf22c4f1..f213b6cdb1 100644
--- a/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/Gambatte.ISettable.cs
+++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/Gambatte.ISettable.cs
@@ -80,6 +80,11 @@ namespace BizHawk.Emulation.Cores.Nintendo.Gameboy
public class GambatteSyncSettings
{
+ [DisplayName("Enable BIOS: WARNING: File must exist!")]
+ [Description("Boots game using system BIOS. Should be used for TASing")]
+ [DefaultValue(false)]
+ public bool EnableBIOS { get; set; }
+
[DisplayName("Force DMG Mode")]
[Description("Force the game to run on DMG hardware, even if it's detected as a CGB game. Relevant for games that are \"CGB Enhanced\" but do not require CGB.")]
[DefaultValue(false)]
diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/Gambatte.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/Gambatte.cs
index e2e3f6b4ea..d7e3812de6 100644
--- a/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/Gambatte.cs
+++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/Gambatte.cs
@@ -52,6 +52,23 @@ namespace BizHawk.Emulation.Cores.Nintendo.Gameboy
throw new InvalidOperationException("gambatte_create() returned null???");
}
+ Console.WriteLine(game.System);
+
+ byte[] BiosRom;
+
+ if (game.System == "GB")
+ {
+ BiosRom = new byte[256];
+ BiosRom = comm.CoreFileProvider.GetFirmware("GB", "World", false);
+ }
+ else
+ {
+ BiosRom = new byte[2304];
+ BiosRom = comm.CoreFileProvider.GetFirmware("GBC", "World", false);
+ }
+
+ int bios_length = BiosRom == null ? 0 : BiosRom.Length;
+
try
{
_syncSettings = (GambatteSyncSettings)syncSettings ?? new GambatteSyncSettings();
@@ -66,6 +83,25 @@ namespace BizHawk.Emulation.Cores.Nintendo.Gameboy
if (_syncSettings.ForceDMG)
{
flags |= LibGambatte.LoadFlags.FORCE_DMG;
+
+ // we need to change the BIOS to GB bios
+ if (game.System == "GBC")
+ {
+ BiosRom = null;
+ BiosRom = new byte[256];
+ BiosRom = comm.CoreFileProvider.GetFirmware("GB", "World", false);
+ }
+ }
+
+ if (_syncSettings.EnableBIOS && BiosRom == null)
+ {
+ throw new MissingFirmwareException("Boot Rom not found");
+ }
+
+ // to disable BIOS loading into gambatte, just set bios_length to 0
+ if (!_syncSettings.EnableBIOS)
+ {
+ bios_length = 0;
}
if (_syncSettings.GBACGB)
@@ -78,7 +114,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.Gameboy
flags |= LibGambatte.LoadFlags.MULTICART_COMPAT;
}
- if (LibGambatte.gambatte_load(GambatteState, file, (uint)file.Length, GetCurrentTime(), flags) != 0)
+ if (LibGambatte.gambatte_load(GambatteState, file, (uint)file.Length, BiosRom, (uint)bios_length, GetCurrentTime(), flags) != 0)
{
throw new InvalidOperationException("gambatte_load() returned non-zero (is this not a gb or gbc rom?)");
}
diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/LibGambatte.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/LibGambatte.cs
index 86b7e4fffd..06aaa58fa6 100644
--- a/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/LibGambatte.cs
+++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/LibGambatte.cs
@@ -57,7 +57,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.Gameboy
/// ORed combination of LoadFlags.
/// 0 on success, negative value on failure.
[DllImport("libgambatte.dll", CallingConvention = CallingConvention.Cdecl)]
- public static extern int gambatte_load(IntPtr core, byte[] romdata, uint length, long now, LoadFlags flags);
+ public static extern int gambatte_load(IntPtr core, byte[] romdata, uint length, byte[] biosdata, uint bioslength, long now, LoadFlags flags);
///
/// Emulates until at least 'samples' stereo sound samples are produced in the supplied buffer,
diff --git a/libgambatte/include/gambatte.h b/libgambatte/include/gambatte.h
index 43e56d5fb9..2265ffa6d9 100644
--- a/libgambatte/include/gambatte.h
+++ b/libgambatte/include/gambatte.h
@@ -60,7 +60,8 @@ public:
* @param flags ORed combination of LoadFlags.
* @return 0 on success, negative value on failure.
*/
- int load(const char *romfiledata, unsigned romfilelength, std::uint32_t now, unsigned flags = 0);
+ bool use_bios;
+ int load(const char *romfiledata, unsigned romfilelength, const char *biosfiledata, unsigned biosfilelength, std::uint32_t now, unsigned flags = 0);
/** Emulates until at least 'samples' stereo sound samples are produced in the supplied buffer,
* or until a video frame has been drawn.
diff --git a/libgambatte/libgambatte.vcxproj b/libgambatte/libgambatte.vcxproj
index 2f3aaa552c..4d34da2828 100644
--- a/libgambatte/libgambatte.vcxproj
+++ b/libgambatte/libgambatte.vcxproj
@@ -1,5 +1,5 @@
-
+
Debug
@@ -28,23 +28,27 @@
DynamicLibrary
true
Unicode
+ v140
DynamicLibrary
true
Unicode
+ v140
DynamicLibrary
false
true
Unicode
+ v140
DynamicLibrary
false
true
Unicode
+ v140
diff --git a/libgambatte/src/cinterface.cpp b/libgambatte/src/cinterface.cpp
index c224fdf725..6549307c85 100644
--- a/libgambatte/src/cinterface.cpp
+++ b/libgambatte/src/cinterface.cpp
@@ -29,9 +29,9 @@ GBEXPORT void gambatte_destroy(GB *g)
delete g;
}
-GBEXPORT int gambatte_load(GB *g, const char *romfiledata, unsigned romfilelength, long long now, unsigned flags)
+GBEXPORT int gambatte_load(GB *g, const char *romfiledata, unsigned romfilelength, const char *biosfiledata, unsigned biosfilelength, long long now, unsigned flags)
{
- int ret = g->load(romfiledata, romfilelength, now, flags);
+ int ret = g->load(romfiledata, romfilelength, biosfiledata, biosfilelength, now, flags);
return ret;
}
diff --git a/libgambatte/src/cpu.h b/libgambatte/src/cpu.h
index 02fabe979e..1310257e86 100644
--- a/libgambatte/src/cpu.h
+++ b/libgambatte/src/cpu.h
@@ -1,132 +1,136 @@
-/***************************************************************************
- * 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 CPU_H
-#define CPU_H
-
-#include "memory.h"
+/***************************************************************************
+ * 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 CPU_H
+#define CPU_H
+
+#include "memory.h"
#include "newstate.h"
-
-namespace gambatte {
-
-class CPU {
- Memory memory;
-
- unsigned long cycleCounter_;
-
- unsigned short PC;
- unsigned short SP;
-
- unsigned HF1, HF2, ZF, CF;
-
- unsigned char A, B, C, D, E, /*F,*/ H, L;
-
- bool skip;
-
- void process(unsigned long cycles);
-
- void (*tracecallback)(void *);
-
-public:
-
- CPU();
-// void halt();
-
-// unsigned interrupt(unsigned address, unsigned cycleCounter);
-
- long runFor(unsigned long cycles);
- void setStatePtrs(SaveState &state);
- void loadState(const SaveState &state);
- void setLayers(unsigned mask) { memory.setLayers(mask); }
-
- void loadSavedata(const char *data) { memory.loadSavedata(data); }
- int saveSavedataLength() {return memory.saveSavedataLength(); }
- void saveSavedata(char *dest) { memory.saveSavedata(dest); }
-
- bool getMemoryArea(int which, unsigned char **data, int *length) { return memory.getMemoryArea(which, data, length); }
-
- void setVideoBuffer(uint_least32_t *const videoBuf, const int pitch) {
- memory.setVideoBuffer(videoBuf, pitch);
- }
-
- void setInputGetter(unsigned (*getInput)()) {
- memory.setInputGetter(getInput);
- }
-
- void setReadCallback(void (*callback)(unsigned)) {
- memory.setReadCallback(callback);
- }
-
- void setWriteCallback(void (*callback)(unsigned)) {
- memory.setWriteCallback(callback);
- }
-
- void setExecCallback(void (*callback)(unsigned)) {
- memory.setExecCallback(callback);
- }
-
- void setCDCallback(CDCallback cdc) {
- memory.setCDCallback(cdc);
- }
-
- void setTraceCallback(void (*callback)(void *)) {
- tracecallback = callback;
- }
-
- void setScanlineCallback(void (*callback)(), int sl) {
- memory.setScanlineCallback(callback, sl);
- }
-
- void setRTCCallback(std::uint32_t (*callback)()) {
- memory.setRTCCallback(callback);
- }
-
- int load(const char *romfiledata, unsigned romfilelength, bool forceDmg, bool multicartCompat) {
- return memory.loadROM(romfiledata, romfilelength, forceDmg, multicartCompat);
- }
-
- bool loaded() const { return memory.loaded(); }
- const char * romTitle() const { return memory.romTitle(); }
-
- void setSoundBuffer(uint_least32_t *const buf) { memory.setSoundBuffer(buf); }
- unsigned fillSoundBuffer() { return memory.fillSoundBuffer(cycleCounter_); }
-
- bool isCgb() const { return memory.isCgb(); }
-
- void setDmgPaletteColor(unsigned palNum, unsigned colorNum, unsigned rgb32) {
- memory.setDmgPaletteColor(palNum, colorNum, rgb32);
- }
-
- void setCgbPalette(unsigned *lut) {
- memory.setCgbPalette(lut);
- }
-
- //unsigned char ExternalRead(unsigned short addr) { return memory.read(addr, cycleCounter_); }
- unsigned char ExternalRead(unsigned short addr) { return memory.peek(addr); }
- void ExternalWrite(unsigned short addr, unsigned char val) { memory.write_nocb(addr, val, cycleCounter_); }
-
- int LinkStatus(int which) { return memory.LinkStatus(which); }
-
- void GetRegs(int *dest);
-
+
+namespace gambatte {
+
+class CPU {
+ Memory memory;
+
+ unsigned long cycleCounter_;
+
+ unsigned short PC;
+ unsigned short SP;
+
+ unsigned HF1, HF2, ZF, CF;
+
+ unsigned char A, B, C, D, E, /*F,*/ H, L;
+
+ bool skip;
+
+ void process(unsigned long cycles);
+
+ void (*tracecallback)(void *);
+
+public:
+
+ CPU();
+// void halt();
+
+// unsigned interrupt(unsigned address, unsigned cycleCounter);
+
+ long runFor(unsigned long cycles);
+ void setStatePtrs(SaveState &state);
+ void loadState(const SaveState &state);
+ void setLayers(unsigned mask) { memory.setLayers(mask); }
+
+ void loadSavedata(const char *data) { memory.loadSavedata(data); }
+ int saveSavedataLength() {return memory.saveSavedataLength(); }
+ void saveSavedata(char *dest) { memory.saveSavedata(dest); }
+
+ bool getMemoryArea(int which, unsigned char **data, int *length) { return memory.getMemoryArea(which, data, length); }
+
+ void setVideoBuffer(uint_least32_t *const videoBuf, const int pitch) {
+ memory.setVideoBuffer(videoBuf, pitch);
+ }
+
+ void setInputGetter(unsigned (*getInput)()) {
+ memory.setInputGetter(getInput);
+ }
+
+ void setReadCallback(void (*callback)(unsigned)) {
+ memory.setReadCallback(callback);
+ }
+
+ void setWriteCallback(void (*callback)(unsigned)) {
+ memory.setWriteCallback(callback);
+ }
+
+ void setExecCallback(void (*callback)(unsigned)) {
+ memory.setExecCallback(callback);
+ }
+
+ void setCDCallback(CDCallback cdc) {
+ memory.setCDCallback(cdc);
+ }
+
+ void setTraceCallback(void (*callback)(void *)) {
+ tracecallback = callback;
+ }
+
+ void setScanlineCallback(void (*callback)(), int sl) {
+ memory.setScanlineCallback(callback, sl);
+ }
+
+ void setRTCCallback(std::uint32_t (*callback)()) {
+ memory.setRTCCallback(callback);
+ }
+
+ void reset_bios(int setting) {
+ memory.bios_reset(setting);
+ }
+
+ int load(const char *romfiledata, unsigned romfilelength, const char *biosfiledata, unsigned biosfilelength, bool forceDmg, bool multicartCompat) {
+ return memory.loadROM(romfiledata, romfilelength, biosfiledata, biosfilelength, forceDmg, multicartCompat);
+ }
+
+ bool loaded() const { return memory.loaded(); }
+ const char * romTitle() const { return memory.romTitle(); }
+
+ void setSoundBuffer(uint_least32_t *const buf) { memory.setSoundBuffer(buf); }
+ unsigned fillSoundBuffer() { return memory.fillSoundBuffer(cycleCounter_); }
+
+ bool isCgb() const { return memory.isCgb(); }
+
+ void setDmgPaletteColor(unsigned palNum, unsigned colorNum, unsigned rgb32) {
+ memory.setDmgPaletteColor(palNum, colorNum, rgb32);
+ }
+
+ void setCgbPalette(unsigned *lut) {
+ memory.setCgbPalette(lut);
+ }
+
+ //unsigned char ExternalRead(unsigned short addr) { return memory.read(addr, cycleCounter_); }
+ unsigned char ExternalRead(unsigned short addr) { return memory.peek(addr); }
+ void ExternalWrite(unsigned short addr, unsigned char val) { memory.write_nocb(addr, val, cycleCounter_); }
+
+ int LinkStatus(int which) { return memory.LinkStatus(which); }
+
+ void GetRegs(int *dest);
+
templatevoid SyncState(NewState *ns);
-};
-
-}
-
-#endif
+};
+
+}
+
+#endif
diff --git a/libgambatte/src/gambatte.cpp b/libgambatte/src/gambatte.cpp
index d56632d8f5..c3843a862c 100644
--- a/libgambatte/src/gambatte.cpp
+++ b/libgambatte/src/gambatte.cpp
@@ -94,7 +94,12 @@ void GB::reset(const std::uint32_t now) {
SaveState state;
p_->cpu.setStatePtrs(state);
- setInitState(state, p_->cpu.isCgb(), p_->gbaCgbMode, now);
+ if (use_bios)
+ {
+ p_->cpu.reset_bios(0);
+ }
+
+ setInitState(state, p_->cpu.isCgb(), p_->gbaCgbMode, now, use_bios);
p_->cpu.loadState(state);
if (length > 0)
{
@@ -136,16 +141,17 @@ void GB::setRTCCallback(std::uint32_t (*callback)()) {
p_->cpu.setRTCCallback(callback);
}
-int GB::load(const char *romfiledata, unsigned romfilelength, const std::uint32_t now, const unsigned flags) {
+int GB::load(const char *romfiledata, unsigned romfilelength, const char *biosfiledata, unsigned biosfilelength, const std::uint32_t now, const unsigned flags) {
//if (p_->cpu.loaded())
// p_->cpu.saveSavedata();
- const int failed = p_->cpu.load(romfiledata, romfilelength, flags & FORCE_DMG, flags & MULTICART_COMPAT);
+ const int failed = p_->cpu.load(romfiledata, romfilelength, biosfiledata, biosfilelength, flags & FORCE_DMG, flags & MULTICART_COMPAT);
+ use_bios = biosfilelength > 0 ? true : false;
if (!failed) {
SaveState state;
p_->cpu.setStatePtrs(state);
- setInitState(state, p_->cpu.isCgb(), p_->gbaCgbMode = flags & GBA_CGB, now);
+ setInitState(state, p_->cpu.isCgb(), p_->gbaCgbMode = flags & GBA_CGB, now, use_bios);
p_->cpu.loadState(state);
//p_->cpu.loadSavedata();
}
@@ -228,6 +234,7 @@ SYNCFUNC(GB)
SSS(p_->cpu);
NSS(p_->gbaCgbMode);
NSS(p_->vbuff);
+ NSS(use_bios);
}
}
diff --git a/libgambatte/src/initstate.cpp b/libgambatte/src/initstate.cpp
index 6430061789..307a7f460c 100644
--- a/libgambatte/src/initstate.cpp
+++ b/libgambatte/src/initstate.cpp
@@ -1146,7 +1146,7 @@ static void setInitialDmgIoamhram(unsigned char *const ioamhram) {
} // anon namespace
-void gambatte::setInitState(SaveState &state, const bool cgb, const bool gbaCgbMode, const std::uint32_t now) {
+void gambatte::setInitState(SaveState &state, const bool cgb, const bool gbaCgbMode, const std::uint32_t now, bool boot_bios) {
static const unsigned char cgbObjpDump[0x40] = {
0x00, 0x00, 0xF2, 0xAB,
0x61, 0xC2, 0xD9, 0xBA,
@@ -1166,22 +1166,47 @@ void gambatte::setInitState(SaveState &state, const bool cgb, const bool gbaCgbM
0x83, 0x40, 0x0B, 0x77
};
- state.cpu.cycleCounter = cgb ? 0x102A0 : 0x102A0 + 0x8D2C;
- state.cpu.PC = 0x100;
- state.cpu.SP = 0xFFFE;
- state.cpu.A = cgb * 0x10 | 0x01;
- state.cpu.B = cgb & gbaCgbMode;
- state.cpu.C = 0x13;
- state.cpu.D = 0x00;
- state.cpu.E = 0xD8;
- state.cpu.F = 0xB0;
- state.cpu.H = 0x01;
- state.cpu.L = 0x4D;
- state.cpu.skip = false;
+ if (boot_bios)
+ {
+ state.cpu.PC = 0x00;
+ state.cpu.SP = 0xFFFF;
+ state.cpu.A = 0;
+ state.cpu.B = 0;
+ state.cpu.C = 0x0;
+ state.cpu.D = 0x0;
+ state.cpu.E = 0x0;
+ state.cpu.F = 0x0;
+ state.cpu.H = 0x0;
+ state.cpu.L = 0x0;
+ state.cpu.skip = false;
+ state.cpu.cycleCounter = 0;
+ state.mem.ioamhram.ptr[0x140] = 0x00;
+ state.mem.ioamhram.ptr[0x104] = 0x00;
+ state.mem.using_bios = true;
+ }
+ else
+ {
+ state.cpu.PC = 0x100;
+ state.cpu.SP = 0xFFFE;
+ state.cpu.A = cgb * 0x10 | 0x01;
+ state.cpu.B = cgb & gbaCgbMode;
+ state.cpu.C = 0x13;
+ state.cpu.D = 0x00;
+ state.cpu.E = 0xD8;
+ state.cpu.F = 0xB0;
+ state.cpu.H = 0x01;
+ state.cpu.L = 0x4D;
+ state.cpu.skip = false;
+ setInitialVram(state.mem.vram.ptr, cgb);
+ state.cpu.cycleCounter = cgb ? 0x102A0 : 0x102A0 + 0x8D2C;
+ state.mem.ioamhram.ptr[0x140] = 0x91;
+ state.mem.ioamhram.ptr[0x104] = 0x1C;
+
+ }
std::memset(state.mem.sram.ptr, 0xFF, state.mem.sram.getSz());
- setInitialVram(state.mem.vram.ptr, cgb);
+
if (cgb) {
setInitialCgbWram(state.mem.wram.ptr);
@@ -1191,8 +1216,6 @@ void gambatte::setInitState(SaveState &state, const bool cgb, const bool gbaCgbM
setInitialDmgIoamhram(state.mem.ioamhram.ptr);
}
- state.mem.ioamhram.ptr[0x104] = 0x1C;
- state.mem.ioamhram.ptr[0x140] = 0x91;
state.mem.ioamhram.ptr[0x144] = 0x00;
state.mem.divLastUpdate = 0;
@@ -1258,7 +1281,6 @@ void gambatte::setInitState(SaveState &state, const bool cgb, const bool gbaCgbM
state.ppu.oldWy = state.mem.ioamhram.get()[0x14A];
state.ppu.pendingLcdstatIrq = false;
-
state.spu.cycleCounter = 0x1000 | (state.cpu.cycleCounter >> 1 & 0xFFF); // spu.cycleCounter >> 12 & 7 represents the frame sequencer position.
state.spu.ch1.sweep.counter = SoundUnit::COUNTER_DISABLED;
diff --git a/libgambatte/src/initstate.h b/libgambatte/src/initstate.h
index 8d8ed5aaf6..ec56fae045 100644
--- a/libgambatte/src/initstate.h
+++ b/libgambatte/src/initstate.h
@@ -22,7 +22,7 @@
#include
namespace gambatte {
-void setInitState(struct SaveState &state, bool cgb, bool gbaCgbMode, std::uint32_t now);
+void setInitState(struct SaveState &state, bool cgb, bool gbaCgbMode, std::uint32_t now, bool boot_bios);
}
#endif
diff --git a/libgambatte/src/mem/cartridge.cpp b/libgambatte/src/mem/cartridge.cpp
index b8b642f4c4..4117c86f54 100644
--- a/libgambatte/src/mem/cartridge.cpp
+++ b/libgambatte/src/mem/cartridge.cpp
@@ -1,152 +1,153 @@
-/***************************************************************************
- * Copyright (C) 2007-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. *
- ***************************************************************************/
-#include "cartridge.h"
-#include "../savestate.h"
-#include
-#include
-#include
-
-namespace gambatte {
-
-namespace {
-
-static unsigned toMulti64Rombank(const unsigned rombank) {
- return (rombank >> 1 & 0x30) | (rombank & 0xF);
-}
-
-class DefaultMbc : public Mbc {
-public:
- virtual bool isAddressWithinAreaRombankCanBeMappedTo(unsigned addr, unsigned bank) const {
- return (addr< 0x4000) == (bank == 0);
- }
+/***************************************************************************
+ * Copyright (C) 2007-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. *
+ ***************************************************************************/
+#include "cartridge.h"
+#include "../savestate.h"
+#include
+#include
+#include
+#include
+
+namespace gambatte {
+
+namespace {
+
+static unsigned toMulti64Rombank(const unsigned rombank) {
+ return (rombank >> 1 & 0x30) | (rombank & 0xF);
+}
+
+class DefaultMbc : public Mbc {
+public:
+ virtual bool isAddressWithinAreaRombankCanBeMappedTo(unsigned addr, unsigned bank) const {
+ return (addr< 0x4000) == (bank == 0);
+ }
virtual void SyncState(NewState *ns, bool isReader)
{
- }
-};
-
-class Mbc0 : public DefaultMbc {
- MemPtrs &memptrs;
- bool enableRam;
-
-public:
- explicit Mbc0(MemPtrs &memptrs)
- : memptrs(memptrs),
- enableRam(false)
- {
- }
-
- virtual void romWrite(const unsigned P, const unsigned data) {
- if (P < 0x2000) {
- enableRam = (data & 0xF) == 0xA;
- memptrs.setRambank(enableRam ? MemPtrs::READ_EN | MemPtrs::WRITE_EN : 0, 0);
- }
- }
-
- virtual void saveState(SaveState::Mem &ss) const {
- ss.enableRam = enableRam;
- }
-
- virtual void loadState(const SaveState::Mem &ss) {
- enableRam = ss.enableRam;
- memptrs.setRambank(enableRam ? MemPtrs::READ_EN | MemPtrs::WRITE_EN : 0, 0);
- }
-
+ }
+};
+
+class Mbc0 : public DefaultMbc {
+ MemPtrs &memptrs;
+ bool enableRam;
+
+public:
+ explicit Mbc0(MemPtrs &memptrs)
+ : memptrs(memptrs),
+ enableRam(false)
+ {
+ }
+
+ virtual void romWrite(const unsigned P, const unsigned data) {
+ if (P < 0x2000) {
+ enableRam = (data & 0xF) == 0xA;
+ memptrs.setRambank(enableRam ? MemPtrs::READ_EN | MemPtrs::WRITE_EN : 0, 0);
+ }
+ }
+
+ virtual void saveState(SaveState::Mem &ss) const {
+ ss.enableRam = enableRam;
+ }
+
+ virtual void loadState(const SaveState::Mem &ss) {
+ enableRam = ss.enableRam;
+ memptrs.setRambank(enableRam ? MemPtrs::READ_EN | MemPtrs::WRITE_EN : 0, 0);
+ }
+
virtual void SyncState(NewState *ns, bool isReader)
{
NSS(enableRam);
}
-};
-
-static inline unsigned rambanks(const MemPtrs &memptrs) {
- return static_cast(memptrs.rambankdataend() - memptrs.rambankdata()) / 0x2000;
-}
-
-static inline unsigned rombanks(const MemPtrs &memptrs) {
- return static_cast(memptrs.romdataend() - memptrs.romdata() ) / 0x4000;
-}
-
-class Mbc1 : public DefaultMbc {
- MemPtrs &memptrs;
- unsigned char rombank;
- unsigned char rambank;
- bool enableRam;
- bool rambankMode;
-
- static unsigned adjustedRombank(unsigned bank) { return bank & 0x1F ? bank : bank | 1; }
- void setRambank() const { memptrs.setRambank(enableRam ? MemPtrs::READ_EN | MemPtrs::WRITE_EN : 0, rambank & (rambanks(memptrs) - 1)); }
- void setRombank() const { memptrs.setRombank(adjustedRombank(rombank & (rombanks(memptrs) - 1))); }
-
-public:
- explicit Mbc1(MemPtrs &memptrs)
- : memptrs(memptrs),
- rombank(1),
- rambank(0),
- enableRam(false),
- rambankMode(false)
- {
- }
-
- virtual void romWrite(const unsigned P, const unsigned data) {
- switch (P >> 13 & 3) {
- case 0:
- enableRam = (data & 0xF) == 0xA;
- setRambank();
- break;
- case 1:
- rombank = rambankMode ? data & 0x1F : (rombank & 0x60) | (data & 0x1F);
- setRombank();
- break;
- case 2:
- if (rambankMode) {
- rambank = data & 3;
- setRambank();
- } else {
- rombank = (data << 5 & 0x60) | (rombank & 0x1F);
- setRombank();
- }
-
- break;
- case 3:
- // Pretty sure this should take effect immediately, but I have a policy not to change old behavior
- // unless I have something (eg. a verified test or a game) that justifies it.
- rambankMode = data & 1;
- break;
- }
- }
-
- virtual void saveState(SaveState::Mem &ss) const {
- ss.rombank = rombank;
- ss.rambank = rambank;
- ss.enableRam = enableRam;
- ss.rambankMode = rambankMode;
- }
-
- virtual void loadState(const SaveState::Mem &ss) {
- rombank = ss.rombank;
- rambank = ss.rambank;
- enableRam = ss.enableRam;
- rambankMode = ss.rambankMode;
- setRambank();
- setRombank();
- }
-
+};
+
+static inline unsigned rambanks(const MemPtrs &memptrs) {
+ return static_cast(memptrs.rambankdataend() - memptrs.rambankdata()) / 0x2000;
+}
+
+static inline unsigned rombanks(const MemPtrs &memptrs) {
+ return static_cast(memptrs.romdataend() - memptrs.romdata() ) / 0x4000;
+}
+
+class Mbc1 : public DefaultMbc {
+ MemPtrs &memptrs;
+ unsigned char rombank;
+ unsigned char rambank;
+ bool enableRam;
+ bool rambankMode;
+
+ static unsigned adjustedRombank(unsigned bank) { return bank & 0x1F ? bank : bank | 1; }
+ void setRambank() const { memptrs.setRambank(enableRam ? MemPtrs::READ_EN | MemPtrs::WRITE_EN : 0, rambank & (rambanks(memptrs) - 1)); }
+ void setRombank() const { memptrs.setRombank(adjustedRombank(rombank & (rombanks(memptrs) - 1))); }
+
+public:
+ explicit Mbc1(MemPtrs &memptrs)
+ : memptrs(memptrs),
+ rombank(1),
+ rambank(0),
+ enableRam(false),
+ rambankMode(false)
+ {
+ }
+
+ virtual void romWrite(const unsigned P, const unsigned data) {
+ switch (P >> 13 & 3) {
+ case 0:
+ enableRam = (data & 0xF) == 0xA;
+ setRambank();
+ break;
+ case 1:
+ rombank = rambankMode ? data & 0x1F : (rombank & 0x60) | (data & 0x1F);
+ setRombank();
+ break;
+ case 2:
+ if (rambankMode) {
+ rambank = data & 3;
+ setRambank();
+ } else {
+ rombank = (data << 5 & 0x60) | (rombank & 0x1F);
+ setRombank();
+ }
+
+ break;
+ case 3:
+ // Pretty sure this should take effect immediately, but I have a policy not to change old behavior
+ // unless I have something (eg. a verified test or a game) that justifies it.
+ rambankMode = data & 1;
+ break;
+ }
+ }
+
+ virtual void saveState(SaveState::Mem &ss) const {
+ ss.rombank = rombank;
+ ss.rambank = rambank;
+ ss.enableRam = enableRam;
+ ss.rambankMode = rambankMode;
+ }
+
+ virtual void loadState(const SaveState::Mem &ss) {
+ rombank = ss.rombank;
+ rambank = ss.rambank;
+ enableRam = ss.enableRam;
+ rambankMode = ss.rambankMode;
+ setRambank();
+ setRombank();
+ }
+
virtual void SyncState(NewState *ns, bool isReader)
{
NSS(rombank);
@@ -154,267 +155,267 @@ public:
NSS(enableRam);
NSS(rambankMode);
}
-};
-
-class Mbc1Multi64 : public Mbc {
- MemPtrs &memptrs;
- unsigned char rombank;
- bool enableRam;
- bool rombank0Mode;
-
- static unsigned adjustedRombank(unsigned bank) { return bank & 0x1F ? bank : bank | 1; }
-
- void setRombank() const {
- if (rombank0Mode) {
- const unsigned rb = toMulti64Rombank(rombank);
- memptrs.setRombank0(rb & 0x30);
- memptrs.setRombank(adjustedRombank(rb));
- } else {
- memptrs.setRombank0(0);
- memptrs.setRombank(adjustedRombank(rombank & (rombanks(memptrs) - 1)));
- }
- }
-
-public:
- explicit Mbc1Multi64(MemPtrs &memptrs)
- : memptrs(memptrs),
- rombank(1),
- enableRam(false),
- rombank0Mode(false)
- {
- }
-
- virtual void romWrite(const unsigned P, const unsigned data) {
- switch (P >> 13 & 3) {
- case 0:
- enableRam = (data & 0xF) == 0xA;
- memptrs.setRambank(enableRam ? MemPtrs::READ_EN | MemPtrs::WRITE_EN : 0, 0);
- break;
- case 1:
- rombank = (rombank & 0x60) | (data & 0x1F);
- memptrs.setRombank(adjustedRombank(rombank0Mode ? toMulti64Rombank(rombank) : rombank & (rombanks(memptrs) - 1)));
- break;
- case 2:
- rombank = (data << 5 & 0x60) | (rombank & 0x1F);
- setRombank();
- break;
- case 3:
- rombank0Mode = data & 1;
- setRombank();
- break;
- }
- }
-
- virtual void saveState(SaveState::Mem &ss) const {
- ss.rombank = rombank;
- ss.enableRam = enableRam;
- ss.rambankMode = rombank0Mode;
- }
-
- virtual void loadState(const SaveState::Mem &ss) {
- rombank = ss.rombank;
- enableRam = ss.enableRam;
- rombank0Mode = ss.rambankMode;
- memptrs.setRambank(enableRam ? MemPtrs::READ_EN | MemPtrs::WRITE_EN : 0, 0);
- setRombank();
- }
-
- virtual bool isAddressWithinAreaRombankCanBeMappedTo(unsigned addr, unsigned bank) const {
- return (addr < 0x4000) == ((bank & 0xF) == 0);
- }
-
+};
+
+class Mbc1Multi64 : public Mbc {
+ MemPtrs &memptrs;
+ unsigned char rombank;
+ bool enableRam;
+ bool rombank0Mode;
+
+ static unsigned adjustedRombank(unsigned bank) { return bank & 0x1F ? bank : bank | 1; }
+
+ void setRombank() const {
+ if (rombank0Mode) {
+ const unsigned rb = toMulti64Rombank(rombank);
+ memptrs.setRombank0(rb & 0x30);
+ memptrs.setRombank(adjustedRombank(rb));
+ } else {
+ memptrs.setRombank0(0);
+ memptrs.setRombank(adjustedRombank(rombank & (rombanks(memptrs) - 1)));
+ }
+ }
+
+public:
+ explicit Mbc1Multi64(MemPtrs &memptrs)
+ : memptrs(memptrs),
+ rombank(1),
+ enableRam(false),
+ rombank0Mode(false)
+ {
+ }
+
+ virtual void romWrite(const unsigned P, const unsigned data) {
+ switch (P >> 13 & 3) {
+ case 0:
+ enableRam = (data & 0xF) == 0xA;
+ memptrs.setRambank(enableRam ? MemPtrs::READ_EN | MemPtrs::WRITE_EN : 0, 0);
+ break;
+ case 1:
+ rombank = (rombank & 0x60) | (data & 0x1F);
+ memptrs.setRombank(adjustedRombank(rombank0Mode ? toMulti64Rombank(rombank) : rombank & (rombanks(memptrs) - 1)));
+ break;
+ case 2:
+ rombank = (data << 5 & 0x60) | (rombank & 0x1F);
+ setRombank();
+ break;
+ case 3:
+ rombank0Mode = data & 1;
+ setRombank();
+ break;
+ }
+ }
+
+ virtual void saveState(SaveState::Mem &ss) const {
+ ss.rombank = rombank;
+ ss.enableRam = enableRam;
+ ss.rambankMode = rombank0Mode;
+ }
+
+ virtual void loadState(const SaveState::Mem &ss) {
+ rombank = ss.rombank;
+ enableRam = ss.enableRam;
+ rombank0Mode = ss.rambankMode;
+ memptrs.setRambank(enableRam ? MemPtrs::READ_EN | MemPtrs::WRITE_EN : 0, 0);
+ setRombank();
+ }
+
+ virtual bool isAddressWithinAreaRombankCanBeMappedTo(unsigned addr, unsigned bank) const {
+ return (addr < 0x4000) == ((bank & 0xF) == 0);
+ }
+
virtual void SyncState(NewState *ns, bool isReader)
{
NSS(rombank);
NSS(enableRam);
NSS(rombank0Mode);
}
-};
-
-class Mbc2 : public DefaultMbc {
- MemPtrs &memptrs;
- unsigned char rombank;
- bool enableRam;
-
-public:
- explicit Mbc2(MemPtrs &memptrs)
- : memptrs(memptrs),
- rombank(1),
- enableRam(false)
- {
- }
-
- virtual void romWrite(const unsigned P, const unsigned data) {
- switch (P & 0x6100) {
- case 0x0000:
- enableRam = (data & 0xF) == 0xA;
- memptrs.setRambank(enableRam ? MemPtrs::READ_EN | MemPtrs::WRITE_EN : 0, 0);
- break;
- case 0x2100:
- rombank = data & 0xF;
- memptrs.setRombank(rombank & (rombanks(memptrs) - 1));
- break;
- }
- }
-
- virtual void saveState(SaveState::Mem &ss) const {
- ss.rombank = rombank;
- ss.enableRam = enableRam;
- }
-
- virtual void loadState(const SaveState::Mem &ss) {
- rombank = ss.rombank;
- enableRam = ss.enableRam;
- memptrs.setRambank(enableRam ? MemPtrs::READ_EN | MemPtrs::WRITE_EN : 0, 0);
- memptrs.setRombank(rombank & (rombanks(memptrs) - 1));
- }
-
+};
+
+class Mbc2 : public DefaultMbc {
+ MemPtrs &memptrs;
+ unsigned char rombank;
+ bool enableRam;
+
+public:
+ explicit Mbc2(MemPtrs &memptrs)
+ : memptrs(memptrs),
+ rombank(1),
+ enableRam(false)
+ {
+ }
+
+ virtual void romWrite(const unsigned P, const unsigned data) {
+ switch (P & 0x6100) {
+ case 0x0000:
+ enableRam = (data & 0xF) == 0xA;
+ memptrs.setRambank(enableRam ? MemPtrs::READ_EN | MemPtrs::WRITE_EN : 0, 0);
+ break;
+ case 0x2100:
+ rombank = data & 0xF;
+ memptrs.setRombank(rombank & (rombanks(memptrs) - 1));
+ break;
+ }
+ }
+
+ virtual void saveState(SaveState::Mem &ss) const {
+ ss.rombank = rombank;
+ ss.enableRam = enableRam;
+ }
+
+ virtual void loadState(const SaveState::Mem &ss) {
+ rombank = ss.rombank;
+ enableRam = ss.enableRam;
+ memptrs.setRambank(enableRam ? MemPtrs::READ_EN | MemPtrs::WRITE_EN : 0, 0);
+ memptrs.setRombank(rombank & (rombanks(memptrs) - 1));
+ }
+
virtual void SyncState(NewState *ns, bool isReader)
{
NSS(rombank);
NSS(enableRam);
}
-};
-
-class Mbc3 : public DefaultMbc {
- MemPtrs &memptrs;
- Rtc *const rtc;
- unsigned char rombank;
- unsigned char rambank;
- bool enableRam;
-
- static unsigned adjustedRombank(unsigned bank) { return bank & 0x7F ? bank : bank | 1; }
- void setRambank() const {
- unsigned flags = enableRam ? MemPtrs::READ_EN | MemPtrs::WRITE_EN : 0;
-
- if (rtc) {
- rtc->set(enableRam, rambank);
-
- if (rtc->getActive())
- flags |= MemPtrs::RTC_EN;
- }
-
- memptrs.setRambank(flags, rambank & (rambanks(memptrs) - 1));
- }
- // we adjust the rombank before masking with size? this seems correct, as how would the mbc
- // know that high rom address outputs were not connected
- void setRombank() const { memptrs.setRombank(adjustedRombank(rombank) & (rombanks(memptrs) - 1)); }
-
-public:
- Mbc3(MemPtrs &memptrs, Rtc *const rtc)
- : memptrs(memptrs),
- rtc(rtc),
- rombank(1),
- rambank(0),
- enableRam(false)
- {
- }
-
- virtual void romWrite(const unsigned P, const unsigned data) {
- switch (P >> 13 & 3) {
- case 0:
- enableRam = (data & 0xF) == 0xA;
- setRambank();
- break;
- case 1:
- rombank = data & 0x7F;
- setRombank();
- break;
- case 2:
- rambank = data;
- setRambank();
- break;
- case 3:
- if (rtc)
- rtc->latch(data);
-
- break;
- }
- }
-
- virtual void saveState(SaveState::Mem &ss) const {
- ss.rombank = rombank;
- ss.rambank = rambank;
- ss.enableRam = enableRam;
- }
-
- virtual void loadState(const SaveState::Mem &ss) {
- rombank = ss.rombank;
- rambank = ss.rambank;
- enableRam = ss.enableRam;
- setRambank();
- setRombank();
- }
-
+};
+
+class Mbc3 : public DefaultMbc {
+ MemPtrs &memptrs;
+ Rtc *const rtc;
+ unsigned char rombank;
+ unsigned char rambank;
+ bool enableRam;
+
+ static unsigned adjustedRombank(unsigned bank) { return bank & 0x7F ? bank : bank | 1; }
+ void setRambank() const {
+ unsigned flags = enableRam ? MemPtrs::READ_EN | MemPtrs::WRITE_EN : 0;
+
+ if (rtc) {
+ rtc->set(enableRam, rambank);
+
+ if (rtc->getActive())
+ flags |= MemPtrs::RTC_EN;
+ }
+
+ memptrs.setRambank(flags, rambank & (rambanks(memptrs) - 1));
+ }
+ // we adjust the rombank before masking with size? this seems correct, as how would the mbc
+ // know that high rom address outputs were not connected
+ void setRombank() const { memptrs.setRombank(adjustedRombank(rombank) & (rombanks(memptrs) - 1)); }
+
+public:
+ Mbc3(MemPtrs &memptrs, Rtc *const rtc)
+ : memptrs(memptrs),
+ rtc(rtc),
+ rombank(1),
+ rambank(0),
+ enableRam(false)
+ {
+ }
+
+ virtual void romWrite(const unsigned P, const unsigned data) {
+ switch (P >> 13 & 3) {
+ case 0:
+ enableRam = (data & 0xF) == 0xA;
+ setRambank();
+ break;
+ case 1:
+ rombank = data & 0x7F;
+ setRombank();
+ break;
+ case 2:
+ rambank = data;
+ setRambank();
+ break;
+ case 3:
+ if (rtc)
+ rtc->latch(data);
+
+ break;
+ }
+ }
+
+ virtual void saveState(SaveState::Mem &ss) const {
+ ss.rombank = rombank;
+ ss.rambank = rambank;
+ ss.enableRam = enableRam;
+ }
+
+ virtual void loadState(const SaveState::Mem &ss) {
+ rombank = ss.rombank;
+ rambank = ss.rambank;
+ enableRam = ss.enableRam;
+ setRambank();
+ setRombank();
+ }
+
virtual void SyncState(NewState *ns, bool isReader)
{
NSS(rombank);
NSS(rambank);
NSS(enableRam);
}
-};
-
-class HuC1 : public DefaultMbc {
- MemPtrs &memptrs;
- unsigned char rombank;
- unsigned char rambank;
- bool enableRam;
- bool rambankMode;
-
- void setRambank() const {
- memptrs.setRambank(enableRam ? MemPtrs::READ_EN | MemPtrs::WRITE_EN : MemPtrs::READ_EN,
- rambankMode ? rambank & (rambanks(memptrs) - 1) : 0);
- }
-
- void setRombank() const { memptrs.setRombank((rambankMode ? rombank : rambank << 6 | rombank) & (rombanks(memptrs) - 1)); }
-
-public:
- explicit HuC1(MemPtrs &memptrs)
- : memptrs(memptrs),
- rombank(1),
- rambank(0),
- enableRam(false),
- rambankMode(false)
- {
- }
-
- virtual void romWrite(const unsigned P, const unsigned data) {
- switch (P >> 13 & 3) {
- case 0:
- enableRam = (data & 0xF) == 0xA;
- setRambank();
- break;
- case 1:
- rombank = data & 0x3F;
- setRombank();
- break;
- case 2:
- rambank = data & 3;
- rambankMode ? setRambank() : setRombank();
- break;
- case 3:
- rambankMode = data & 1;
- setRambank();
- setRombank();
- break;
- }
- }
-
- virtual void saveState(SaveState::Mem &ss) const {
- ss.rombank = rombank;
- ss.rambank = rambank;
- ss.enableRam = enableRam;
- ss.rambankMode = rambankMode;
- }
-
- virtual void loadState(const SaveState::Mem &ss) {
- rombank = ss.rombank;
- rambank = ss.rambank;
- enableRam = ss.enableRam;
- rambankMode = ss.rambankMode;
- setRambank();
- setRombank();
- }
+};
+
+class HuC1 : public DefaultMbc {
+ MemPtrs &memptrs;
+ unsigned char rombank;
+ unsigned char rambank;
+ bool enableRam;
+ bool rambankMode;
+
+ void setRambank() const {
+ memptrs.setRambank(enableRam ? MemPtrs::READ_EN | MemPtrs::WRITE_EN : MemPtrs::READ_EN,
+ rambankMode ? rambank & (rambanks(memptrs) - 1) : 0);
+ }
+
+ void setRombank() const { memptrs.setRombank((rambankMode ? rombank : rambank << 6 | rombank) & (rombanks(memptrs) - 1)); }
+
+public:
+ explicit HuC1(MemPtrs &memptrs)
+ : memptrs(memptrs),
+ rombank(1),
+ rambank(0),
+ enableRam(false),
+ rambankMode(false)
+ {
+ }
+
+ virtual void romWrite(const unsigned P, const unsigned data) {
+ switch (P >> 13 & 3) {
+ case 0:
+ enableRam = (data & 0xF) == 0xA;
+ setRambank();
+ break;
+ case 1:
+ rombank = data & 0x3F;
+ setRombank();
+ break;
+ case 2:
+ rambank = data & 3;
+ rambankMode ? setRambank() : setRombank();
+ break;
+ case 3:
+ rambankMode = data & 1;
+ setRambank();
+ setRombank();
+ break;
+ }
+ }
+
+ virtual void saveState(SaveState::Mem &ss) const {
+ ss.rombank = rombank;
+ ss.rambank = rambank;
+ ss.enableRam = enableRam;
+ ss.rambankMode = rambankMode;
+ }
+
+ virtual void loadState(const SaveState::Mem &ss) {
+ rombank = ss.rombank;
+ rambank = ss.rambank;
+ enableRam = ss.enableRam;
+ rambankMode = ss.rambankMode;
+ setRambank();
+ setRombank();
+ }
virtual void SyncState(NewState *ns, bool isReader)
{
@@ -423,327 +424,375 @@ public:
NSS(enableRam);
NSS(rambankMode);
}
-};
-
-class Mbc5 : public DefaultMbc {
- MemPtrs &memptrs;
- unsigned short rombank;
- unsigned char rambank;
- bool enableRam;
-
- static unsigned adjustedRombank(const unsigned bank) { return bank; }
- void setRambank() const { memptrs.setRambank(enableRam ? MemPtrs::READ_EN | MemPtrs::WRITE_EN : 0, rambank & (rambanks(memptrs) - 1)); }
- void setRombank() const { memptrs.setRombank(adjustedRombank(rombank & (rombanks(memptrs) - 1))); }
-
-public:
- explicit Mbc5(MemPtrs &memptrs)
- : memptrs(memptrs),
- rombank(1),
- rambank(0),
- enableRam(false)
- {
- }
-
- virtual void romWrite(const unsigned P, const unsigned data) {
- switch (P >> 13 & 3) {
- case 0:
- enableRam = (data & 0xF) == 0xA;
- setRambank();
- break;
- case 1:
- rombank = P < 0x3000 ? (rombank & 0x100) | data
- : (data << 8 & 0x100) | (rombank & 0xFF);
- setRombank();
- break;
- case 2:
- rambank = data & 0xF;
- setRambank();
- break;
- case 3:
- break;
- }
- }
-
- virtual void saveState(SaveState::Mem &ss) const {
- ss.rombank = rombank;
- ss.rambank = rambank;
- ss.enableRam = enableRam;
- }
-
- virtual void loadState(const SaveState::Mem &ss) {
- rombank = ss.rombank;
- rambank = ss.rambank;
- enableRam = ss.enableRam;
- setRambank();
- setRombank();
- }
-
+};
+
+class Mbc5 : public DefaultMbc {
+ MemPtrs &memptrs;
+ unsigned short rombank;
+ unsigned char rambank;
+ bool enableRam;
+
+ static unsigned adjustedRombank(const unsigned bank) { return bank; }
+ void setRambank() const { memptrs.setRambank(enableRam ? MemPtrs::READ_EN | MemPtrs::WRITE_EN : 0, rambank & (rambanks(memptrs) - 1)); }
+ void setRombank() const { memptrs.setRombank(adjustedRombank(rombank & (rombanks(memptrs) - 1))); }
+
+public:
+ explicit Mbc5(MemPtrs &memptrs)
+ : memptrs(memptrs),
+ rombank(1),
+ rambank(0),
+ enableRam(false)
+ {
+ }
+
+ virtual void romWrite(const unsigned P, const unsigned data) {
+ switch (P >> 13 & 3) {
+ case 0:
+ enableRam = (data & 0xF) == 0xA;
+ setRambank();
+ break;
+ case 1:
+ rombank = P < 0x3000 ? (rombank & 0x100) | data
+ : (data << 8 & 0x100) | (rombank & 0xFF);
+ setRombank();
+ break;
+ case 2:
+ rambank = data & 0xF;
+ setRambank();
+ break;
+ case 3:
+ break;
+ }
+ }
+
+ virtual void saveState(SaveState::Mem &ss) const {
+ ss.rombank = rombank;
+ ss.rambank = rambank;
+ ss.enableRam = enableRam;
+ }
+
+ virtual void loadState(const SaveState::Mem &ss) {
+ rombank = ss.rombank;
+ rambank = ss.rambank;
+ enableRam = ss.enableRam;
+ setRambank();
+ setRombank();
+ }
+
virtual void SyncState(NewState *ns, bool isReader)
{
NSS(rombank);
NSS(rambank);
NSS(enableRam);
}
-};
-
-static bool hasRtc(const unsigned headerByte0x147) {
- switch (headerByte0x147) {
- case 0x0F:
- case 0x10: return true;
- default: return false;
- }
-}
-
-}
-
-void Cartridge::setStatePtrs(SaveState &state) {
- state.mem.vram.set(memptrs.vramdata(), memptrs.vramdataend() - memptrs.vramdata());
- state.mem.sram.set(memptrs.rambankdata(), memptrs.rambankdataend() - memptrs.rambankdata());
- state.mem.wram.set(memptrs.wramdata(0), memptrs.wramdataend() - memptrs.wramdata(0));
-}
-
-void Cartridge::loadState(const SaveState &state) {
- rtc.loadState(state);
- mbc->loadState(state.mem);
-}
-
-static void enforce8bit(unsigned char *data, unsigned long sz) {
- if (static_cast(0x100))
- while (sz--)
- *data++ &= 0xFF;
-}
-
-static unsigned pow2ceil(unsigned n) {
- --n;
- n |= n >> 1;
- n |= n >> 2;
- n |= n >> 4;
- n |= n >> 8;
- ++n;
-
- return n;
-}
-
-int Cartridge::loadROM(const char *romfiledata, unsigned romfilelength, const bool forceDmg, const bool multicartCompat) {
- //const std::auto_ptr rom(newFileInstance(romfile));
-
- //if (rom->fail())
- // return -1;
-
- unsigned rambanks = 1;
- unsigned rombanks = 2;
- bool cgb = false;
- enum Cartridgetype { PLAIN, MBC1, MBC2, MBC3, MBC5, HUC1 } type = PLAIN;
-
- {
- unsigned char header[0x150];
- //rom->read(reinterpret_cast(header), sizeof header);
- if (romfilelength >= sizeof header)
- std::memcpy(header, romfiledata, sizeof header);
- else
- return -1;
-
- switch (header[0x0147]) {
- case 0x00: std::puts("Plain ROM loaded."); type = PLAIN; break;
- case 0x01: std::puts("MBC1 ROM loaded."); type = MBC1; break;
- case 0x02: std::puts("MBC1 ROM+RAM loaded."); type = MBC1; break;
- case 0x03: std::puts("MBC1 ROM+RAM+BATTERY loaded."); type = MBC1; break;
- case 0x05: std::puts("MBC2 ROM loaded."); type = MBC2; break;
- case 0x06: std::puts("MBC2 ROM+BATTERY loaded."); type = MBC2; break;
- case 0x08: std::puts("Plain ROM with additional RAM loaded."); type = PLAIN; break;
- case 0x09: std::puts("Plain ROM with additional RAM and Battery loaded."); type = PLAIN; break;
- case 0x0B: std::puts("MM01 ROM not supported."); return -1;
- case 0x0C: std::puts("MM01 ROM not supported."); return -1;
- case 0x0D: std::puts("MM01 ROM not supported."); return -1;
- case 0x0F: std::puts("MBC3 ROM+TIMER+BATTERY loaded."); type = MBC3; break;
- case 0x10: std::puts("MBC3 ROM+TIMER+RAM+BATTERY loaded."); type = MBC3; break;
- case 0x11: std::puts("MBC3 ROM loaded."); type = MBC3; break;
- case 0x12: std::puts("MBC3 ROM+RAM loaded."); type = MBC3; break;
- case 0x13: std::puts("MBC3 ROM+RAM+BATTERY loaded."); type = MBC3; break;
- case 0x15: std::puts("MBC4 ROM not supported."); return -1;
- case 0x16: std::puts("MBC4 ROM not supported."); return -1;
- case 0x17: std::puts("MBC4 ROM not supported."); return -1;
- case 0x19: std::puts("MBC5 ROM loaded."); type = MBC5; break;
- case 0x1A: std::puts("MBC5 ROM+RAM loaded."); type = MBC5; break;
- case 0x1B: std::puts("MBC5 ROM+RAM+BATTERY loaded."); type = MBC5; break;
- case 0x1C: std::puts("MBC5+RUMBLE ROM not supported."); type = MBC5; break;
- case 0x1D: std::puts("MBC5+RUMBLE+RAM ROM not suported."); type = MBC5; break;
- case 0x1E: std::puts("MBC5+RUMBLE+RAM+BATTERY ROM not supported."); type = MBC5; break;
- case 0xFC: std::puts("Pocket Camera ROM not supported."); return -1;
- case 0xFD: std::puts("Bandai TAMA5 ROM not supported."); return -1;
- case 0xFE: std::puts("HuC3 ROM not supported."); return -1;
- case 0xFF: std::puts("HuC1 ROM+RAM+BATTERY loaded."); type = HUC1; break;
- default: std::puts("Wrong data-format, corrupt or unsupported ROM."); return -1;
- }
-
- /*switch (header[0x0148]) {
- case 0x00: rombanks = 2; break;
- case 0x01: rombanks = 4; break;
- case 0x02: rombanks = 8; break;
- case 0x03: rombanks = 16; break;
- case 0x04: rombanks = 32; break;
- case 0x05: rombanks = 64; break;
- case 0x06: rombanks = 128; break;
- case 0x07: rombanks = 256; break;
- case 0x08: rombanks = 512; break;
- case 0x52: rombanks = 72; break;
- case 0x53: rombanks = 80; break;
- case 0x54: rombanks = 96; break;
- default: return -1;
- }
-
- std::printf("rombanks: %u\n", rombanks);*/
-
- switch (header[0x0149]) {
- case 0x00: /*std::puts("No RAM");*/ rambanks = type == MBC2; break;
- case 0x01: /*std::puts("2kB RAM");*/ /*rambankrom=1; break;*/
- case 0x02: /*std::puts("8kB RAM");*/
- rambanks = 1;
- break;
- case 0x03: /*std::puts("32kB RAM");*/
- rambanks = 4;
- break;
- case 0x04: /*std::puts("128kB RAM");*/
- rambanks = 16;
- break;
- case 0x05: /*std::puts("undocumented kB RAM");*/
- rambanks = 16;
- break;
- default: /*std::puts("Wrong data-format, corrupt or unsupported ROM loaded.");*/
- rambanks = 16;
- break;
- }
-
- cgb = header[0x0143] >> 7 & (1 ^ forceDmg);
- std::printf("cgb: %d\n", cgb);
- }
-
- std::printf("rambanks: %u\n", rambanks);
-
- const std::size_t filesize = romfilelength; //rom->size();
- rombanks = std::max(pow2ceil(filesize / 0x4000), 2u);
- std::printf("rombanks: %u\n", static_cast(filesize / 0x4000));
-
- mbc.reset();
- memptrs.reset(rombanks, rambanks, cgb ? 8 : 2);
- rtc.set(false, 0);
-
- //rom->rewind();
- //rom->read(reinterpret_cast(memptrs.romdata()), (filesize / 0x4000) * 0x4000ul);
- std::memcpy(memptrs.romdata(), romfiledata, (filesize / 0x4000) * 0x4000ul);
- std::memset(memptrs.romdata() + (filesize / 0x4000) * 0x4000ul, 0xFF, (rombanks - filesize / 0x4000) * 0x4000ul);
- enforce8bit(memptrs.romdata(), rombanks * 0x4000ul);
-
- //if (rom->fail())
- // return -1;
-
- switch (type) {
- case PLAIN: mbc.reset(new Mbc0(memptrs)); break;
- case MBC1:
- if (!rambanks && rombanks == 64 && multicartCompat) {
- std::puts("Multi-ROM \"MBC1\" presumed");
- mbc.reset(new Mbc1Multi64(memptrs));
- } else
- mbc.reset(new Mbc1(memptrs));
-
- break;
- case MBC2: mbc.reset(new Mbc2(memptrs)); break;
- case MBC3: mbc.reset(new Mbc3(memptrs, hasRtc(memptrs.romdata()[0x147]) ? &rtc : 0)); break;
- case MBC5: mbc.reset(new Mbc5(memptrs)); break;
- case HUC1: mbc.reset(new HuC1(memptrs)); break;
- }
-
- return 0;
-}
-
-static bool hasBattery(const unsigned char headerByte0x147) {
- switch (headerByte0x147) {
- case 0x03:
- case 0x06:
- case 0x09:
- case 0x0F:
- case 0x10:
- case 0x13:
- case 0x1B:
- case 0x1E:
- case 0xFF: return true;
- default: return false;
- }
-}
-
-void Cartridge::loadSavedata(const char *data) {
- if (hasBattery(memptrs.romdata()[0x147])) {
- int length = memptrs.rambankdataend() - memptrs.rambankdata();
- std::memcpy(memptrs.rambankdata(), data, length);
- data += length;
- enforce8bit(memptrs.rambankdata(), length);
- }
-
- if (hasRtc(memptrs.romdata()[0x147])) {
- unsigned long basetime;
- std::memcpy(&basetime, data, 4);
- rtc.setBaseTime(basetime);
- }
-}
-
-int Cartridge::saveSavedataLength() {
- int ret = 0;
- if (hasBattery(memptrs.romdata()[0x147])) {
- ret = memptrs.rambankdataend() - memptrs.rambankdata();
- }
- if (hasRtc(memptrs.romdata()[0x147])) {
- ret += 4;
- }
- return ret;
-}
-
-void Cartridge::saveSavedata(char *dest) {
- if (hasBattery(memptrs.romdata()[0x147])) {
- int length = memptrs.rambankdataend() - memptrs.rambankdata();
- std::memcpy(dest, memptrs.rambankdata(), length);
- dest += length;
- }
-
- if (hasRtc(memptrs.romdata()[0x147])) {
- const unsigned long basetime = rtc.getBaseTime();
- std::memcpy(dest, &basetime, 4);
- }
-}
-
-bool Cartridge::getMemoryArea(int which, unsigned char **data, int *length) const {
- if (!data || !length)
- return false;
-
- switch (which)
- {
- case 0:
- *data = memptrs.vramdata();
- *length = memptrs.vramdataend() - memptrs.vramdata();
- return true;
- case 1:
- *data = memptrs.romdata();
- *length = memptrs.romdataend() - memptrs.romdata();
- return true;
- case 2:
- *data = memptrs.wramdata(0);
- *length = memptrs.wramdataend() - memptrs.wramdata(0);
- return true;
- case 3:
- *data = memptrs.rambankdata();
- *length = memptrs.rambankdataend() - memptrs.rambankdata();
- return true;
-
- default:
- return false;
- }
- return false;
-}
-
+};
+
+static bool hasRtc(const unsigned headerByte0x147) {
+ switch (headerByte0x147) {
+ case 0x0F:
+ case 0x10: return true;
+ default: return false;
+ }
+}
+
+}
+
+void Cartridge::setStatePtrs(SaveState &state) {
+ state.mem.vram.set(memptrs.vramdata(), memptrs.vramdataend() - memptrs.vramdata());
+ state.mem.sram.set(memptrs.rambankdata(), memptrs.rambankdataend() - memptrs.rambankdata());
+ state.mem.wram.set(memptrs.wramdata(0), memptrs.wramdataend() - memptrs.wramdata(0));
+
+}
+
+void Cartridge::loadState(const SaveState &state) {
+ rtc.loadState(state);
+ mbc->loadState(state.mem);
+ //if (state.mem.using_bios) {
+ // bios_remap(0);
+ //}
+}
+
+static void enforce8bit(unsigned char *data, unsigned long sz) {
+ if (static_cast(0x100))
+ while (sz--)
+ *data++ &= 0xFF;
+}
+
+static unsigned pow2ceil(unsigned n) {
+ --n;
+ n |= n >> 1;
+ n |= n >> 2;
+ n |= n >> 4;
+ n |= n >> 8;
+ ++n;
+
+ return n;
+}
+
+void Cartridge::bios_remap(int setting) {
+ // disable the BIOS if writing 1 or 0x22 (GBC)
+ if (setting == 1 || setting == 0x11) {
+ std::memcpy(memptrs.romdata(), memptrs.notbiosdata_, loc_bios_length);
+ using_bios = false;
+ }
+
+ // we'll also use it to reset to BIOS on reset
+ if (setting == 0) {
+ std::memcpy(memptrs.romdata(), memptrs.biosdata_, loc_bios_length);
+ using_bios = true;
+ }
+}
+
+int Cartridge::loadROM(const char *romfiledata, unsigned romfilelength, const char *biosfiledata, unsigned biosfilelength, const bool forceDmg, const bool multicartCompat) {
+ //const std::auto_ptr rom(newFileInstance(romfile));
+
+ //if (rom->fail())
+ // return -1;
+
+ unsigned rambanks = 1;
+ unsigned rombanks = 2;
+ bool cgb = false;
+ enum Cartridgetype { PLAIN, MBC1, MBC2, MBC3, MBC5, HUC1 } type = PLAIN;
+
+ {
+ unsigned char header[0x150];
+ //rom->read(reinterpret_cast(header), sizeof header);
+ if (romfilelength >= sizeof header)
+ std::memcpy(header, romfiledata, sizeof header);
+ else
+ return -1;
+
+ switch (header[0x0147]) {
+ case 0x00: std::puts("Plain ROM loaded."); type = PLAIN; break;
+ case 0x01: std::puts("MBC1 ROM loaded."); type = MBC1; break;
+ case 0x02: std::puts("MBC1 ROM+RAM loaded."); type = MBC1; break;
+ case 0x03: std::puts("MBC1 ROM+RAM+BATTERY loaded."); type = MBC1; break;
+ case 0x05: std::puts("MBC2 ROM loaded."); type = MBC2; break;
+ case 0x06: std::puts("MBC2 ROM+BATTERY loaded."); type = MBC2; break;
+ case 0x08: std::puts("Plain ROM with additional RAM loaded."); type = PLAIN; break;
+ case 0x09: std::puts("Plain ROM with additional RAM and Battery loaded."); type = PLAIN; break;
+ case 0x0B: std::puts("MM01 ROM not supported."); return -1;
+ case 0x0C: std::puts("MM01 ROM not supported."); return -1;
+ case 0x0D: std::puts("MM01 ROM not supported."); return -1;
+ case 0x0F: std::puts("MBC3 ROM+TIMER+BATTERY loaded."); type = MBC3; break;
+ case 0x10: std::puts("MBC3 ROM+TIMER+RAM+BATTERY loaded."); type = MBC3; break;
+ case 0x11: std::puts("MBC3 ROM loaded."); type = MBC3; break;
+ case 0x12: std::puts("MBC3 ROM+RAM loaded."); type = MBC3; break;
+ case 0x13: std::puts("MBC3 ROM+RAM+BATTERY loaded."); type = MBC3; break;
+ case 0x15: std::puts("MBC4 ROM not supported."); return -1;
+ case 0x16: std::puts("MBC4 ROM not supported."); return -1;
+ case 0x17: std::puts("MBC4 ROM not supported."); return -1;
+ case 0x19: std::puts("MBC5 ROM loaded."); type = MBC5; break;
+ case 0x1A: std::puts("MBC5 ROM+RAM loaded."); type = MBC5; break;
+ case 0x1B: std::puts("MBC5 ROM+RAM+BATTERY loaded."); type = MBC5; break;
+ case 0x1C: std::puts("MBC5+RUMBLE ROM not supported."); type = MBC5; break;
+ case 0x1D: std::puts("MBC5+RUMBLE+RAM ROM not suported."); type = MBC5; break;
+ case 0x1E: std::puts("MBC5+RUMBLE+RAM+BATTERY ROM not supported."); type = MBC5; break;
+ case 0xFC: std::puts("Pocket Camera ROM not supported."); return -1;
+ case 0xFD: std::puts("Bandai TAMA5 ROM not supported."); return -1;
+ case 0xFE: std::puts("HuC3 ROM not supported."); return -1;
+ case 0xFF: std::puts("HuC1 ROM+RAM+BATTERY loaded."); type = HUC1; break;
+ default: std::puts("Wrong data-format, corrupt or unsupported ROM."); return -1;
+ }
+
+ /*switch (header[0x0148]) {
+ case 0x00: rombanks = 2; break;
+ case 0x01: rombanks = 4; break;
+ case 0x02: rombanks = 8; break;
+ case 0x03: rombanks = 16; break;
+ case 0x04: rombanks = 32; break;
+ case 0x05: rombanks = 64; break;
+ case 0x06: rombanks = 128; break;
+ case 0x07: rombanks = 256; break;
+ case 0x08: rombanks = 512; break;
+ case 0x52: rombanks = 72; break;
+ case 0x53: rombanks = 80; break;
+ case 0x54: rombanks = 96; break;
+ default: return -1;
+ }
+
+ std::printf("rombanks: %u\n", rombanks);*/
+
+ switch (header[0x0149]) {
+ case 0x00: /*std::puts("No RAM");*/ rambanks = type == MBC2; break;
+ case 0x01: /*std::puts("2kB RAM");*/ /*rambankrom=1; break;*/
+ case 0x02: /*std::puts("8kB RAM");*/
+ rambanks = 1;
+ break;
+ case 0x03: /*std::puts("32kB RAM");*/
+ rambanks = 4;
+ break;
+ case 0x04: /*std::puts("128kB RAM");*/
+ rambanks = 16;
+ break;
+ case 0x05: /*std::puts("undocumented kB RAM");*/
+ rambanks = 16;
+ break;
+ default: /*std::puts("Wrong data-format, corrupt or unsupported ROM loaded.");*/
+ rambanks = 16;
+ break;
+ }
+
+ cgb = header[0x0143] >> 7 & (1 ^ forceDmg);
+ std::printf("cgb: %d\n", cgb);
+ }
+
+ std::printf("rambanks: %u\n", rambanks);
+
+ const std::size_t filesize = romfilelength; //rom->size();
+ rombanks = std::max(pow2ceil(filesize / 0x4000), 2u);
+ std::printf("rombanks: %u\n", static_cast(filesize / 0x4000));
+
+ mbc.reset();
+
+ use_bios = biosfilelength > 0 ? true : false;
+ loc_bios_length = biosfilelength;
+
+ memptrs.reset(rombanks, rambanks, cgb ? 8 : 2);
+ rtc.set(false, 0);
+
+ //rom->rewind();
+ //rom->read(reinterpret_cast(memptrs.romdata()), (filesize / 0x4000) * 0x4000ul);
+
+ std::memcpy(memptrs.romdata(), romfiledata, (filesize / 0x4000) * 0x4000ul);
+ std::memset(memptrs.romdata() + (filesize / 0x4000) * 0x4000ul, 0xFF, (rombanks - filesize / 0x4000) * 0x4000ul);
+ enforce8bit(memptrs.romdata(), rombanks * 0x4000ul);
+
+ //we want to copy in the bios data only if it exists
+ if (use_bios) {
+ using_bios = true;
+ memptrs.use_bios = true;
+
+ memptrs.biosdata_ = new unsigned char[biosfilelength];
+ memptrs.notbiosdata_ = new unsigned char[biosfilelength];
+
+ std::memcpy(memptrs.biosdata_, biosfiledata, biosfilelength);
+ std::memcpy(memptrs.notbiosdata_, romfiledata, biosfilelength);
+
+ //if using GBC, the header is not overwritten by the BIOS
+ if (biosfilelength > 256) {
+ std::memcpy(memptrs.biosdata_ + 256, memptrs.notbiosdata_ + 256, 256);
+ }
+
+
+ std::memcpy(memptrs.romdata(), memptrs.biosdata_, biosfilelength);
+ }
+
+ //if (rom->fail())
+ // return -1;
+
+ switch (type) {
+ case PLAIN: mbc.reset(new Mbc0(memptrs)); break;
+ case MBC1:
+ if (!rambanks && rombanks == 64 && multicartCompat) {
+ std::puts("Multi-ROM \"MBC1\" presumed");
+ mbc.reset(new Mbc1Multi64(memptrs));
+ } else
+ mbc.reset(new Mbc1(memptrs));
+
+ break;
+ case MBC2: mbc.reset(new Mbc2(memptrs)); break;
+ case MBC3: mbc.reset(new Mbc3(memptrs, hasRtc(memptrs.romdata()[0x147]) ? &rtc : 0)); break;
+ case MBC5: mbc.reset(new Mbc5(memptrs)); break;
+ case HUC1: mbc.reset(new HuC1(memptrs)); break;
+ }
+
+ return 0;
+}
+
+static bool hasBattery(const unsigned char headerByte0x147) {
+ switch (headerByte0x147) {
+ case 0x03:
+ case 0x06:
+ case 0x09:
+ case 0x0F:
+ case 0x10:
+ case 0x13:
+ case 0x1B:
+ case 0x1E:
+ case 0xFF: return true;
+ default: return false;
+ }
+}
+
+void Cartridge::loadSavedata(const char *data) {
+ if (hasBattery(memptrs.romdata()[0x147])) {
+ int length = memptrs.rambankdataend() - memptrs.rambankdata();
+ std::memcpy(memptrs.rambankdata(), data, length);
+ data += length;
+ enforce8bit(memptrs.rambankdata(), length);
+ }
+
+ if (hasRtc(memptrs.romdata()[0x147])) {
+ unsigned long basetime;
+ std::memcpy(&basetime, data, 4);
+ rtc.setBaseTime(basetime);
+ }
+}
+
+int Cartridge::saveSavedataLength() {
+ int ret = 0;
+ if (hasBattery(memptrs.romdata()[0x147])) {
+ ret = memptrs.rambankdataend() - memptrs.rambankdata();
+ }
+ if (hasRtc(memptrs.romdata()[0x147])) {
+ ret += 4;
+ }
+ return ret;
+}
+
+void Cartridge::saveSavedata(char *dest) {
+ if (hasBattery(memptrs.romdata()[0x147])) {
+ int length = memptrs.rambankdataend() - memptrs.rambankdata();
+ std::memcpy(dest, memptrs.rambankdata(), length);
+ dest += length;
+ }
+
+ if (hasRtc(memptrs.romdata()[0x147])) {
+ const unsigned long basetime = rtc.getBaseTime();
+ std::memcpy(dest, &basetime, 4);
+ }
+}
+
+bool Cartridge::getMemoryArea(int which, unsigned char **data, int *length) const {
+ if (!data || !length)
+ return false;
+
+ switch (which)
+ {
+ case 0:
+ *data = memptrs.vramdata();
+ *length = memptrs.vramdataend() - memptrs.vramdata();
+ return true;
+ case 1:
+ *data = memptrs.romdata();
+ *length = memptrs.romdataend() - memptrs.romdata();
+ return true;
+ case 2:
+ *data = memptrs.wramdata(0);
+ *length = memptrs.wramdataend() - memptrs.wramdata(0);
+ return true;
+ case 3:
+ *data = memptrs.rambankdata();
+ *length = memptrs.rambankdataend() - memptrs.rambankdata();
+ return true;
+
+ default:
+ return false;
+ }
+ return false;
+}
+
SYNCFUNC(Cartridge)
{
SSS(memptrs);
SSS(rtc);
TSS(mbc);
+ NSS(using_bios);
+
+ if (using_bios) {
+ bios_remap(0);
+ }
+}
+
}
-
-}
diff --git a/libgambatte/src/mem/cartridge.h b/libgambatte/src/mem/cartridge.h
index 54f694df31..c3a3d7ce27 100644
--- a/libgambatte/src/mem/cartridge.h
+++ b/libgambatte/src/mem/cartridge.h
@@ -66,6 +66,10 @@ class Cartridge {
public:
void setStatePtrs(SaveState &);
void loadState(const SaveState &);
+
+ bool use_bios;
+ bool using_bios;
+ unsigned loc_bios_length;
bool loaded() const { return mbc.get(); }
@@ -97,13 +101,15 @@ public:
bool getMemoryArea(int which, unsigned char **data, int *length) const;
- int loadROM(const char *romfiledata, unsigned romfilelength, bool forceDmg, bool multicartCompat);
+ int loadROM(const char *romfiledata, unsigned romfilelength, const char *biosfiledata, unsigned biosfilelength, bool forceDmg, bool multicartCompat);
const char * romTitle() const { return reinterpret_cast(memptrs.romdata() + 0x134); }
void setRTCCallback(std::uint32_t (*callback)()) {
rtc.setRTCCallback(callback);
}
+ void bios_remap(int setting);
+
templatevoid SyncState(NewState *ns);
};
diff --git a/libgambatte/src/mem/memptrs.cpp b/libgambatte/src/mem/memptrs.cpp
index 6e8b2fe644..4ddf5e0149 100644
--- a/libgambatte/src/mem/memptrs.cpp
+++ b/libgambatte/src/mem/memptrs.cpp
@@ -1,151 +1,162 @@
-/***************************************************************************
- * Copyright (C) 2007-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. *
- ***************************************************************************/
-#include "memptrs.h"
-#include
-#include
-
-namespace gambatte {
-
-MemPtrs::MemPtrs()
-: rmem_(), wmem_(), romdata_(), wramdata_(), vrambankptr_(0), rsrambankptr_(0),
- wsrambankptr_(0), memchunk_(0), rambankdata_(0), wramdataend_(0), oamDmaSrc_(OAM_DMA_SRC_OFF),
- memchunk_len(0)
-{
-}
-
-MemPtrs::~MemPtrs() {
- delete []memchunk_;
-}
-
-void MemPtrs::reset(const unsigned rombanks, const unsigned rambanks, const unsigned wrambanks) {
- delete []memchunk_;
- memchunk_len = 0x4000 + rombanks * 0x4000ul + 0x4000 + rambanks * 0x2000ul + wrambanks * 0x1000ul + 0x4000;
- memchunk_ = new unsigned char[memchunk_len];
-
- romdata_[0] = romdata();
- rambankdata_ = romdata_[0] + rombanks * 0x4000ul + 0x4000;
- wramdata_[0] = rambankdata_ + rambanks * 0x2000ul;
- wramdataend_ = wramdata_[0] + wrambanks * 0x1000ul;
-
- std::memset(rdisabledRamw(), 0xFF, 0x2000);
-
- oamDmaSrc_ = OAM_DMA_SRC_OFF;
- rmem_[0x3] = rmem_[0x2] = rmem_[0x1] = rmem_[0x0] = romdata_[0];
- rmem_[0xC] = wmem_[0xC] = wramdata_[0] - 0xC000;
- rmem_[0xE] = wmem_[0xE] = wramdata_[0] - 0xE000;
- setRombank(1);
- setRambank(0, 0);
- setVrambank(0);
- setWrambank(1);
-
- // we save only the ram areas
- memchunk_saveoffs = vramdata() - memchunk_;
- memchunk_savelen = wramdataend() - memchunk_ - memchunk_saveoffs;
-}
-
-void MemPtrs::setRombank0(const unsigned bank) {
- romdata_[0] = romdata() + bank * 0x4000ul;
- rmem_[0x3] = rmem_[0x2] = rmem_[0x1] = rmem_[0x0] = romdata_[0];
- disconnectOamDmaAreas();
-}
-
-void MemPtrs::setRombank(const unsigned bank) {
- romdata_[1] = romdata() + bank * 0x4000ul - 0x4000;
- rmem_[0x7] = rmem_[0x6] = rmem_[0x5] = rmem_[0x4] = romdata_[1];
- disconnectOamDmaAreas();
-}
-
-void MemPtrs::setRambank(const unsigned flags, const unsigned rambank) {
- unsigned char *const srambankptr = flags & RTC_EN
- ? 0
- : (rambankdata() != rambankdataend()
- ? rambankdata_ + rambank * 0x2000ul - 0xA000 : wdisabledRam() - 0xA000);
-
- rsrambankptr_ = (flags & READ_EN) && srambankptr != wdisabledRam() - 0xA000 ? srambankptr : rdisabledRamw() - 0xA000;
- wsrambankptr_ = flags & WRITE_EN ? srambankptr : wdisabledRam() - 0xA000;
- rmem_[0xB] = rmem_[0xA] = rsrambankptr_;
- wmem_[0xB] = wmem_[0xA] = wsrambankptr_;
- disconnectOamDmaAreas();
-}
-
-void MemPtrs::setWrambank(const unsigned bank) {
- wramdata_[1] = wramdata_[0] + ((bank & 0x07) ? (bank & 0x07) : 1) * 0x1000;
- rmem_[0xD] = wmem_[0xD] = wramdata_[1] - 0xD000;
- disconnectOamDmaAreas();
-}
-
-void MemPtrs::setOamDmaSrc(const OamDmaSrc oamDmaSrc) {
- rmem_[0x3] = rmem_[0x2] = rmem_[0x1] = rmem_[0x0] = romdata_[0];
- rmem_[0x7] = rmem_[0x6] = rmem_[0x5] = rmem_[0x4] = romdata_[1];
- rmem_[0xB] = rmem_[0xA] = rsrambankptr_;
- wmem_[0xB] = wmem_[0xA] = wsrambankptr_;
- rmem_[0xC] = wmem_[0xC] = wramdata_[0] - 0xC000;
- rmem_[0xD] = wmem_[0xD] = wramdata_[1] - 0xD000;
- rmem_[0xE] = wmem_[0xE] = wramdata_[0] - 0xE000;
-
- oamDmaSrc_ = oamDmaSrc;
- disconnectOamDmaAreas();
-}
-
-void MemPtrs::disconnectOamDmaAreas() {
- if (isCgb(*this)) {
- switch (oamDmaSrc_) {
- case OAM_DMA_SRC_ROM: // fall through
- case OAM_DMA_SRC_SRAM:
- case OAM_DMA_SRC_INVALID:
- std::fill(rmem_, rmem_ + 8, static_cast(0));
- rmem_[0xB] = rmem_[0xA] = 0;
- wmem_[0xB] = wmem_[0xA] = 0;
- break;
- case OAM_DMA_SRC_VRAM:
- break;
- case OAM_DMA_SRC_WRAM:
- rmem_[0xE] = rmem_[0xD] = rmem_[0xC] = 0;
- wmem_[0xE] = wmem_[0xD] = wmem_[0xC] = 0;
- break;
- case OAM_DMA_SRC_OFF:
- break;
- }
- } else {
- switch (oamDmaSrc_) {
- case OAM_DMA_SRC_ROM: // fall through
- case OAM_DMA_SRC_SRAM:
- case OAM_DMA_SRC_WRAM:
- case OAM_DMA_SRC_INVALID:
- std::fill(rmem_, rmem_ + 8, static_cast(0));
- rmem_[0xB] = rmem_[0xA] = 0;
- wmem_[0xB] = wmem_[0xA] = 0;
- rmem_[0xE] = rmem_[0xD] = rmem_[0xC] = 0;
- wmem_[0xE] = wmem_[0xD] = wmem_[0xC] = 0;
- break;
- case OAM_DMA_SRC_VRAM:
- break;
- case OAM_DMA_SRC_OFF:
- break;
- }
- }
-}
-
-// all pointers here are relative to memchunk_
-#define MSS(a) RSS(a,memchunk_)
-#define MSL(a) RSL(a,memchunk_)
-
+/***************************************************************************
+ * Copyright (C) 2007-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. *
+ ***************************************************************************/
+#include "memptrs.h"
+#include
+#include
+
+namespace gambatte {
+
+MemPtrs::MemPtrs()
+: rmem_(), wmem_(), romdata_(), wramdata_(), vrambankptr_(0), rsrambankptr_(0),
+ wsrambankptr_(0), memchunk_(0), rambankdata_(0), wramdataend_(0), oamDmaSrc_(OAM_DMA_SRC_OFF),
+ memchunk_len(0)
+{
+}
+
+MemPtrs::~MemPtrs() {
+ delete []memchunk_;
+ if (use_bios)
+ {
+ delete[]biosdata_;
+ delete[]notbiosdata_;
+ }
+}
+
+void MemPtrs::reset(const unsigned rombanks, const unsigned rambanks, const unsigned wrambanks) {
+ delete []memchunk_;
+
+ memchunk_len = 0x4000 + rombanks * 0x4000ul + 0x4000 + rambanks * 0x2000ul + wrambanks * 0x1000ul + 0x4000;
+ memchunk_ = new unsigned char[memchunk_len];
+
+ romdata_[0] = romdata();
+
+ rambankdata_ = romdata_[0] + rombanks * 0x4000ul + 0x4000;
+ wramdata_[0] = rambankdata_ + rambanks * 0x2000ul;
+ wramdataend_ = wramdata_[0] + wrambanks * 0x1000ul;
+
+ std::memset(rdisabledRamw(), 0xFF, 0x2000);
+
+ oamDmaSrc_ = OAM_DMA_SRC_OFF;
+ rmem_[0x3] = rmem_[0x2] = rmem_[0x1] = rmem_[0x0] = romdata_[0];
+ rmem_[0xC] = wmem_[0xC] = wramdata_[0] - 0xC000;
+ rmem_[0xE] = wmem_[0xE] = wramdata_[0] - 0xE000;
+ setRombank(1);
+ setRambank(0, 0);
+ setVrambank(0);
+ setWrambank(1);
+
+ // we save only the ram areas
+ memchunk_saveoffs = vramdata() - memchunk_;
+ memchunk_savelen = wramdataend() - memchunk_ - memchunk_saveoffs;
+}
+
+void MemPtrs::setRombank0(const unsigned bank) {
+
+ romdata_[0] = romdata() + bank * 0x4000ul;
+
+ rmem_[0x3] = rmem_[0x2] = rmem_[0x1] = rmem_[0x0] = romdata_[0];
+ disconnectOamDmaAreas();
+}
+
+void MemPtrs::setRombank(const unsigned bank) {
+
+ romdata_[1] = romdata() + bank * 0x4000ul - 0x4000;
+
+ rmem_[0x7] = rmem_[0x6] = rmem_[0x5] = rmem_[0x4] = romdata_[1];
+ disconnectOamDmaAreas();
+}
+
+void MemPtrs::setRambank(const unsigned flags, const unsigned rambank) {
+ unsigned char *const srambankptr = flags & RTC_EN
+ ? 0
+ : (rambankdata() != rambankdataend()
+ ? rambankdata_ + rambank * 0x2000ul - 0xA000 : wdisabledRam() - 0xA000);
+
+ rsrambankptr_ = (flags & READ_EN) && srambankptr != wdisabledRam() - 0xA000 ? srambankptr : rdisabledRamw() - 0xA000;
+ wsrambankptr_ = flags & WRITE_EN ? srambankptr : wdisabledRam() - 0xA000;
+ rmem_[0xB] = rmem_[0xA] = rsrambankptr_;
+ wmem_[0xB] = wmem_[0xA] = wsrambankptr_;
+ disconnectOamDmaAreas();
+}
+
+void MemPtrs::setWrambank(const unsigned bank) {
+ wramdata_[1] = wramdata_[0] + ((bank & 0x07) ? (bank & 0x07) : 1) * 0x1000;
+ rmem_[0xD] = wmem_[0xD] = wramdata_[1] - 0xD000;
+ disconnectOamDmaAreas();
+}
+
+void MemPtrs::setOamDmaSrc(const OamDmaSrc oamDmaSrc) {
+ rmem_[0x3] = rmem_[0x2] = rmem_[0x1] = rmem_[0x0] = romdata_[0];
+ rmem_[0x7] = rmem_[0x6] = rmem_[0x5] = rmem_[0x4] = romdata_[1];
+ rmem_[0xB] = rmem_[0xA] = rsrambankptr_;
+ wmem_[0xB] = wmem_[0xA] = wsrambankptr_;
+ rmem_[0xC] = wmem_[0xC] = wramdata_[0] - 0xC000;
+ rmem_[0xD] = wmem_[0xD] = wramdata_[1] - 0xD000;
+ rmem_[0xE] = wmem_[0xE] = wramdata_[0] - 0xE000;
+
+ oamDmaSrc_ = oamDmaSrc;
+ disconnectOamDmaAreas();
+}
+
+void MemPtrs::disconnectOamDmaAreas() {
+ if (isCgb(*this)) {
+ switch (oamDmaSrc_) {
+ case OAM_DMA_SRC_ROM: // fall through
+ case OAM_DMA_SRC_SRAM:
+ case OAM_DMA_SRC_INVALID:
+ std::fill(rmem_, rmem_ + 8, static_cast(0));
+ rmem_[0xB] = rmem_[0xA] = 0;
+ wmem_[0xB] = wmem_[0xA] = 0;
+ break;
+ case OAM_DMA_SRC_VRAM:
+ break;
+ case OAM_DMA_SRC_WRAM:
+ rmem_[0xE] = rmem_[0xD] = rmem_[0xC] = 0;
+ wmem_[0xE] = wmem_[0xD] = wmem_[0xC] = 0;
+ break;
+ case OAM_DMA_SRC_OFF:
+ break;
+ }
+ } else {
+ switch (oamDmaSrc_) {
+ case OAM_DMA_SRC_ROM: // fall through
+ case OAM_DMA_SRC_SRAM:
+ case OAM_DMA_SRC_WRAM:
+ case OAM_DMA_SRC_INVALID:
+ std::fill(rmem_, rmem_ + 8, static_cast(0));
+ rmem_[0xB] = rmem_[0xA] = 0;
+ wmem_[0xB] = wmem_[0xA] = 0;
+ rmem_[0xE] = rmem_[0xD] = rmem_[0xC] = 0;
+ wmem_[0xE] = wmem_[0xD] = wmem_[0xC] = 0;
+ break;
+ case OAM_DMA_SRC_VRAM:
+ break;
+ case OAM_DMA_SRC_OFF:
+ break;
+ }
+ }
+}
+
+// all pointers here are relative to memchunk_
+#define MSS(a) RSS(a,memchunk_)
+#define MSL(a) RSL(a,memchunk_)
+
SYNCFUNC(MemPtrs)
{
/*
@@ -215,6 +226,10 @@ SYNCFUNC(MemPtrs)
MSS(rambankdata_);
MSS(wramdataend_);
NSS(oamDmaSrc_);
+
+ NSS(biosdata_);
+ NSS(notbiosdata_);
+ NSS(use_bios);
+}
+
}
-
-}
diff --git a/libgambatte/src/mem/memptrs.h b/libgambatte/src/mem/memptrs.h
index af21c02a15..3c63670907 100644
--- a/libgambatte/src/mem/memptrs.h
+++ b/libgambatte/src/mem/memptrs.h
@@ -1,93 +1,97 @@
-/***************************************************************************
- * Copyright (C) 2007-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. *
- ***************************************************************************/
-#ifndef MEMPTRS_H
-#define MEMPTRS_H
-
+/***************************************************************************
+ * Copyright (C) 2007-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. *
+ ***************************************************************************/
+#ifndef MEMPTRS_H
+#define MEMPTRS_H
+
#include "newstate.h"
-
-namespace gambatte {
-
-enum OamDmaSrc { OAM_DMA_SRC_ROM, OAM_DMA_SRC_SRAM, OAM_DMA_SRC_VRAM,
- OAM_DMA_SRC_WRAM, OAM_DMA_SRC_INVALID, OAM_DMA_SRC_OFF };
-
-class MemPtrs {
- const unsigned char *rmem_[0x10];
- unsigned char *wmem_[0x10];
-
- unsigned char *romdata_[2];
- unsigned char *wramdata_[2];
- unsigned char *vrambankptr_;
- unsigned char *rsrambankptr_;
- unsigned char *wsrambankptr_;
- unsigned char *memchunk_;
- unsigned char *rambankdata_;
- unsigned char *wramdataend_;
-
- OamDmaSrc oamDmaSrc_;
-
- int memchunk_len;
- int memchunk_saveoffs;
- int memchunk_savelen;
-
- MemPtrs(const MemPtrs &);
- MemPtrs & operator=(const MemPtrs &);
- void disconnectOamDmaAreas();
- unsigned char * rdisabledRamw() const { return wramdataend_ ; }
- unsigned char * wdisabledRam() const { return wramdataend_ + 0x2000; }
-public:
- enum RamFlag { READ_EN = 1, WRITE_EN = 2, RTC_EN = 4 };
-
- MemPtrs();
- ~MemPtrs();
- void reset(unsigned rombanks, unsigned rambanks, unsigned wrambanks);
-
- const unsigned char * rmem(unsigned area) const { return rmem_[area]; }
- unsigned char * wmem(unsigned area) const { return wmem_[area]; }
- unsigned char * vramdata() const { return rambankdata_ - 0x4000; }
- unsigned char * vramdataend() const { return rambankdata_; }
- unsigned char * romdata() const { return memchunk_ + 0x4000; }
- unsigned char * romdata(unsigned area) const { return romdata_[area]; }
- unsigned char * romdataend() const { return rambankdata_ - 0x4000; }
- unsigned char * wramdata(unsigned area) const { return wramdata_[area]; }
- unsigned char * wramdataend() const { return wramdataend_; }
- unsigned char * rambankdata() const { return rambankdata_; }
- unsigned char * rambankdataend() const { return wramdata_[0]; }
- const unsigned char * rdisabledRam() const { return rdisabledRamw(); }
- const unsigned char * rsrambankptr() const { return rsrambankptr_; }
- unsigned char * wsrambankptr() const { return wsrambankptr_; }
- unsigned char * vrambankptr() const { return vrambankptr_; }
- OamDmaSrc oamDmaSrc() const { return oamDmaSrc_; }
-
- void setRombank0(unsigned bank);
- void setRombank(unsigned bank);
- void setRambank(unsigned ramFlags, unsigned rambank);
- void setVrambank(unsigned bank) { vrambankptr_ = vramdata() + bank * 0x2000ul - 0x8000; }
- void setWrambank(unsigned bank);
- void setOamDmaSrc(OamDmaSrc oamDmaSrc);
-
+
+namespace gambatte {
+
+enum OamDmaSrc { OAM_DMA_SRC_ROM, OAM_DMA_SRC_SRAM, OAM_DMA_SRC_VRAM,
+ OAM_DMA_SRC_WRAM, OAM_DMA_SRC_INVALID, OAM_DMA_SRC_OFF };
+
+class MemPtrs {
+ const unsigned char *rmem_[0x10];
+ unsigned char *wmem_[0x10];
+
+ unsigned char *romdata_[2];
+ unsigned char *wramdata_[2];
+ unsigned char *vrambankptr_;
+ unsigned char *rsrambankptr_;
+ unsigned char *wsrambankptr_;
+ unsigned char *memchunk_;
+ unsigned char *rambankdata_;
+ unsigned char *wramdataend_;
+
+ OamDmaSrc oamDmaSrc_;
+
+ int memchunk_len;
+ int memchunk_saveoffs;
+ int memchunk_savelen;
+
+ MemPtrs(const MemPtrs &);
+ MemPtrs & operator=(const MemPtrs &);
+ void disconnectOamDmaAreas();
+ unsigned char * rdisabledRamw() const { return wramdataend_ ; }
+ unsigned char * wdisabledRam() const { return wramdataend_ + 0x2000; }
+public:
+ unsigned char *biosdata_;
+ unsigned char *notbiosdata_;
+ bool use_bios;
+
+ enum RamFlag { READ_EN = 1, WRITE_EN = 2, RTC_EN = 4 };
+
+ MemPtrs();
+ ~MemPtrs();
+ void reset(unsigned rombanks, unsigned rambanks, unsigned wrambanks);
+
+ const unsigned char * rmem(unsigned area) const { return rmem_[area]; }
+ unsigned char * wmem(unsigned area) const { return wmem_[area]; }
+ unsigned char * vramdata() const { return rambankdata_ - 0x4000; }
+ unsigned char * vramdataend() const { return rambankdata_; }
+ unsigned char * romdata() const { return memchunk_ + 0x4000;}
+ unsigned char * romdata(unsigned area) const { return romdata_[area]; }
+ unsigned char * romdataend() const { return rambankdata_ - 0x4000; }
+ unsigned char * wramdata(unsigned area) const { return wramdata_[area]; }
+ unsigned char * wramdataend() const { return wramdataend_; }
+ unsigned char * rambankdata() const { return rambankdata_; }
+ unsigned char * rambankdataend() const { return wramdata_[0]; }
+ const unsigned char * rdisabledRam() const { return rdisabledRamw(); }
+ const unsigned char * rsrambankptr() const { return rsrambankptr_; }
+ unsigned char * wsrambankptr() const { return wsrambankptr_; }
+ unsigned char * vrambankptr() const { return vrambankptr_; }
+ OamDmaSrc oamDmaSrc() const { return oamDmaSrc_; }
+
+ void setRombank0(unsigned bank);
+ void setRombank(unsigned bank);
+ void setRambank(unsigned ramFlags, unsigned rambank);
+ void setVrambank(unsigned bank) { vrambankptr_ = vramdata() + bank * 0x2000ul - 0x8000; }
+ void setWrambank(unsigned bank);
+ void setOamDmaSrc(OamDmaSrc oamDmaSrc);
+
templatevoid SyncState(NewState *ns);
-};
-
-inline bool isCgb(const MemPtrs &memptrs) {
- return memptrs.wramdataend() - memptrs.wramdata(0) == 0x8000;
-}
-
-}
-
-#endif
+};
+
+inline bool isCgb(const MemPtrs &memptrs) {
+ return memptrs.wramdataend() - memptrs.wramdata(0) == 0x8000;
+}
+
+}
+
+#endif
diff --git a/libgambatte/src/memory.cpp b/libgambatte/src/memory.cpp
index 4bae856679..79d9820e16 100644
--- a/libgambatte/src/memory.cpp
+++ b/libgambatte/src/memory.cpp
@@ -1,361 +1,361 @@
-/***************************************************************************
- * 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. *
- ***************************************************************************/
-#include "memory.h"
-#include "video.h"
-#include "sound.h"
-#include "savestate.h"
-#include
-
-namespace gambatte {
-
-Memory::Memory(const Interrupter &interrupter_in)
-: readCallback(0),
- writeCallback(0),
- execCallback(0),
- cdCallback(0),
- getInput(0),
- divLastUpdate(0),
- lastOamDmaUpdate(DISABLED_TIME),
- display(ioamhram, 0, VideoInterruptRequester(&intreq)),
- interrupter(interrupter_in),
- dmaSource(0),
- dmaDestination(0),
- oamDmaPos(0xFE),
- serialCnt(0),
- blanklcd(false),
- LINKCABLE(false),
- linkClockTrigger(false)
-{
- intreq.setEventTime(144*456ul);
- intreq.setEventTime(0);
-}
-
-void Memory::setStatePtrs(SaveState &state) {
- state.mem.ioamhram.set(ioamhram, sizeof ioamhram);
-
- cart.setStatePtrs(state);
- display.setStatePtrs(state);
- sound.setStatePtrs(state);
-}
-
-
-static inline int serialCntFrom(const unsigned long cyclesUntilDone, const bool cgbFast) {
- return cgbFast ? (cyclesUntilDone + 0xF) >> 4 : (cyclesUntilDone + 0x1FF) >> 9;
-}
-
-void Memory::loadState(const SaveState &state) {
- sound.loadState(state);
- display.loadState(state, state.mem.oamDmaPos < 0xA0 ? cart.rdisabledRam() : ioamhram);
- tima.loadState(state, TimaInterruptRequester(intreq));
- cart.loadState(state);
- intreq.loadState(state);
-
- divLastUpdate = state.mem.divLastUpdate;
- intreq.setEventTime(state.mem.nextSerialtime > state.cpu.cycleCounter ? state.mem.nextSerialtime : state.cpu.cycleCounter);
- intreq.setEventTime(state.mem.unhaltTime);
- lastOamDmaUpdate = state.mem.lastOamDmaUpdate;
- dmaSource = state.mem.dmaSource;
- dmaDestination = state.mem.dmaDestination;
- oamDmaPos = state.mem.oamDmaPos;
- serialCnt = intreq.eventTime(SERIAL) != DISABLED_TIME
- ? serialCntFrom(intreq.eventTime(SERIAL) - state.cpu.cycleCounter, ioamhram[0x102] & isCgb() * 2)
- : 8;
-
- cart.setVrambank(ioamhram[0x14F] & isCgb());
- cart.setOamDmaSrc(OAM_DMA_SRC_OFF);
- cart.setWrambank(isCgb() && (ioamhram[0x170] & 0x07) ? ioamhram[0x170] & 0x07 : 1);
-
- if (lastOamDmaUpdate != DISABLED_TIME) {
- oamDmaInitSetup();
-
- const unsigned oamEventPos = oamDmaPos < 0xA0 ? 0xA0 : 0x100;
-
- intreq.setEventTime(lastOamDmaUpdate + (oamEventPos - oamDmaPos) * 4);
- }
-
- intreq.setEventTime((ioamhram[0x140] & 0x80) ? display.nextMode1IrqTime() : state.cpu.cycleCounter);
- blanklcd = false;
-
- if (!isCgb())
- std::memset(cart.vramdata() + 0x2000, 0, 0x2000);
-}
-
-void Memory::setEndtime(const unsigned long cycleCounter, const unsigned long inc) {
- if (intreq.eventTime(BLIT) <= cycleCounter)
- intreq.setEventTime(intreq.eventTime(BLIT) + (70224 << isDoubleSpeed()));
-
- intreq.setEventTime(cycleCounter + (inc << isDoubleSpeed()));
-}
-
-void Memory::updateSerial(const unsigned long cc) {
- if (!LINKCABLE) {
- if (intreq.eventTime(SERIAL) != DISABLED_TIME) {
- if (intreq.eventTime(SERIAL) <= cc) {
- ioamhram[0x101] = (((ioamhram[0x101] + 1) << serialCnt) - 1) & 0xFF;
- ioamhram[0x102] &= 0x7F;
- intreq.setEventTime(DISABLED_TIME);
- intreq.flagIrq(8);
- } else {
- const int targetCnt = serialCntFrom(intreq.eventTime(SERIAL) - cc, ioamhram[0x102] & isCgb() * 2);
- ioamhram[0x101] = (((ioamhram[0x101] + 1) << (serialCnt - targetCnt)) - 1) & 0xFF;
- serialCnt = targetCnt;
- }
- }
- }
- else {
- if (intreq.eventTime(SERIAL) != DISABLED_TIME) {
- if (intreq.eventTime(SERIAL) <= cc) {
- linkClockTrigger = true;
- intreq.setEventTime(DISABLED_TIME);
- }
- }
- }
-}
-
-void Memory::updateTimaIrq(const unsigned long cc) {
- while (intreq.eventTime(TIMA) <= cc)
- tima.doIrqEvent(TimaInterruptRequester(intreq));
-}
-
-void Memory::updateIrqs(const unsigned long cc) {
- updateSerial(cc);
- updateTimaIrq(cc);
- display.update(cc);
-}
-
-unsigned long Memory::event(unsigned long cycleCounter) {
- if (lastOamDmaUpdate != DISABLED_TIME)
- updateOamDma(cycleCounter);
-
- switch (intreq.minEventId()) {
- case UNHALT:
- intreq.unhalt();
- intreq.setEventTime(DISABLED_TIME);
- break;
- case END:
- intreq.setEventTime(DISABLED_TIME - 1);
-
- while (cycleCounter >= intreq.minEventTime() && intreq.eventTime(END) != DISABLED_TIME)
- cycleCounter = event(cycleCounter);
-
- intreq.setEventTime(DISABLED_TIME);
-
- break;
- case BLIT:
- {
- const bool lcden = ioamhram[0x140] >> 7 & 1;
- unsigned long blitTime = intreq.eventTime(BLIT);
-
- if (lcden | blanklcd) {
- display.updateScreen(blanklcd, cycleCounter);
- intreq.setEventTime(DISABLED_TIME);
- intreq.setEventTime(DISABLED_TIME);
-
- while (cycleCounter >= intreq.minEventTime())
- cycleCounter = event(cycleCounter);
- } else
- blitTime += 70224 << isDoubleSpeed();
-
- blanklcd = lcden ^ 1;
- intreq.setEventTime(blitTime);
- }
- break;
- case SERIAL:
- updateSerial(cycleCounter);
- break;
- case OAM:
- intreq.setEventTime(lastOamDmaUpdate == DISABLED_TIME ?
- static_cast(DISABLED_TIME) : intreq.eventTime(OAM) + 0xA0 * 4);
- break;
- case DMA:
- {
- const bool doubleSpeed = isDoubleSpeed();
- unsigned dmaSrc = dmaSource;
- unsigned dmaDest = dmaDestination;
- unsigned dmaLength = ((ioamhram[0x155] & 0x7F) + 0x1) * 0x10;
- unsigned length = hdmaReqFlagged(intreq) ? 0x10 : dmaLength;
-
- ackDmaReq(&intreq);
-
- if ((static_cast(dmaDest) + length) & 0x10000) {
- length = 0x10000 - dmaDest;
- ioamhram[0x155] |= 0x80;
- }
-
- dmaLength -= length;
-
- if (!(ioamhram[0x140] & 0x80))
- dmaLength = 0;
-
- {
- unsigned long lOamDmaUpdate = lastOamDmaUpdate;
- lastOamDmaUpdate = DISABLED_TIME;
-
- while (length--) {
- const unsigned src = dmaSrc++ & 0xFFFF;
- const unsigned data = ((src & 0xE000) == 0x8000 || src > 0xFDFF) ? 0xFF : read(src, cycleCounter);
-
- cycleCounter += 2 << doubleSpeed;
-
- if (cycleCounter - 3 > lOamDmaUpdate) {
- oamDmaPos = (oamDmaPos + 1) & 0xFF;
- lOamDmaUpdate += 4;
-
- if (oamDmaPos < 0xA0) {
- if (oamDmaPos == 0)
- startOamDma(lOamDmaUpdate - 1);
-
- ioamhram[src & 0xFF] = data;
- } else if (oamDmaPos == 0xA0) {
- endOamDma(lOamDmaUpdate - 1);
- lOamDmaUpdate = DISABLED_TIME;
- }
- }
-
- nontrivial_write(0x8000 | (dmaDest++ & 0x1FFF), data, cycleCounter);
- }
-
- lastOamDmaUpdate = lOamDmaUpdate;
- }
-
- cycleCounter += 4;
-
- dmaSource = dmaSrc;
- dmaDestination = dmaDest;
- ioamhram[0x155] = ((dmaLength / 0x10 - 0x1) & 0xFF) | (ioamhram[0x155] & 0x80);
-
- if ((ioamhram[0x155] & 0x80) && display.hdmaIsEnabled()) {
- if (lastOamDmaUpdate != DISABLED_TIME)
- updateOamDma(cycleCounter);
-
- display.disableHdma(cycleCounter);
- }
- }
-
- break;
- case TIMA:
- tima.doIrqEvent(TimaInterruptRequester(intreq));
- break;
- case VIDEO:
- display.update(cycleCounter);
- break;
- case INTERRUPTS:
- if (halted()) {
- if (isCgb())
- cycleCounter += 4;
-
- intreq.unhalt();
- intreq.setEventTime(DISABLED_TIME);
- }
-
- if (ime()) {
- unsigned address;
- const unsigned pendingIrqs = intreq.pendingIrqs();
- const unsigned n = pendingIrqs & -pendingIrqs;
-
- if (n < 8) {
- static const unsigned char lut[] = { 0x40, 0x48, 0x48, 0x50 };
- address = lut[n-1];
- } else
- address = 0x50 + n;
-
- intreq.ackIrq(n);
- cycleCounter = interrupter.interrupt(address, cycleCounter, *this);
- }
-
- break;
- }
-
- return cycleCounter;
-}
-
-unsigned long Memory::stop(unsigned long cycleCounter) {
- cycleCounter += 4 << isDoubleSpeed();
-
- if (ioamhram[0x14D] & isCgb()) {
- sound.generate_samples(cycleCounter, isDoubleSpeed());
-
- display.speedChange(cycleCounter);
- ioamhram[0x14D] ^= 0x81;
-
- intreq.setEventTime((ioamhram[0x140] & 0x80) ? display.nextMode1IrqTime() : cycleCounter + (70224 << isDoubleSpeed()));
-
- if (intreq.eventTime(END) > cycleCounter) {
- intreq.setEventTime(cycleCounter + (isDoubleSpeed() ?
- (intreq.eventTime(END) - cycleCounter) << 1 : (intreq.eventTime(END) - cycleCounter) >> 1));
- }
- // when switching speed, it seems that the CPU spontaneously restarts soon?
- // otherwise, the cpu should be allowed to stay halted as long as needed
- // so only execute this line when switching speed
- intreq.setEventTime(cycleCounter + 0x20000 + isDoubleSpeed() * 8);
- }
-
- intreq.halt();
-
- return cycleCounter;
-}
-
-static void decCycles(unsigned long &counter, const unsigned long dec) {
- if (counter != DISABLED_TIME)
- counter -= dec;
-}
-
-void Memory::decEventCycles(const MemEventId eventId, const unsigned long dec) {
- if (intreq.eventTime(eventId) != DISABLED_TIME)
- intreq.setEventTime(eventId, intreq.eventTime(eventId) - dec);
-}
-
-unsigned long Memory::resetCounters(unsigned long cycleCounter) {
- if (lastOamDmaUpdate != DISABLED_TIME)
- updateOamDma(cycleCounter);
-
- updateIrqs(cycleCounter);
-
- const unsigned long oldCC = cycleCounter;
-
- {
- const unsigned long divinc = (cycleCounter - divLastUpdate) >> 8;
- ioamhram[0x104] = (ioamhram[0x104] + divinc) & 0xFF;
- divLastUpdate += divinc << 8;
- }
-
- const unsigned long dec = cycleCounter < 0x10000 ? 0 : (cycleCounter & ~0x7FFFul) - 0x8000;
-
- decCycles(divLastUpdate, dec);
- decCycles(lastOamDmaUpdate, dec);
- decEventCycles(SERIAL, dec);
- decEventCycles(OAM, dec);
- decEventCycles(BLIT, dec);
- decEventCycles(END, dec);
- decEventCycles(UNHALT, dec);
-
- cycleCounter -= dec;
-
- intreq.resetCc(oldCC, cycleCounter);
- tima.resetCc(oldCC, cycleCounter, TimaInterruptRequester(intreq));
- display.resetCc(oldCC, cycleCounter);
- sound.resetCounter(cycleCounter, oldCC, isDoubleSpeed());
-
- return cycleCounter;
-}
-
-void Memory::updateInput() {
+/***************************************************************************
+ * 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. *
+ ***************************************************************************/
+#include "memory.h"
+#include "video.h"
+#include "sound.h"
+#include "savestate.h"
+#include
+
+namespace gambatte {
+
+Memory::Memory(const Interrupter &interrupter_in)
+: readCallback(0),
+ writeCallback(0),
+ execCallback(0),
+ cdCallback(0),
+ getInput(0),
+ divLastUpdate(0),
+ lastOamDmaUpdate(DISABLED_TIME),
+ display(ioamhram, 0, VideoInterruptRequester(&intreq)),
+ interrupter(interrupter_in),
+ dmaSource(0),
+ dmaDestination(0),
+ oamDmaPos(0xFE),
+ serialCnt(0),
+ blanklcd(false),
+ LINKCABLE(false),
+ linkClockTrigger(false)
+{
+ intreq.setEventTime(144*456ul);
+ intreq.setEventTime(0);
+}
+
+void Memory::setStatePtrs(SaveState &state) {
+ state.mem.ioamhram.set(ioamhram, sizeof ioamhram);
+
+ cart.setStatePtrs(state);
+ display.setStatePtrs(state);
+ sound.setStatePtrs(state);
+}
+
+
+static inline int serialCntFrom(const unsigned long cyclesUntilDone, const bool cgbFast) {
+ return cgbFast ? (cyclesUntilDone + 0xF) >> 4 : (cyclesUntilDone + 0x1FF) >> 9;
+}
+
+void Memory::loadState(const SaveState &state) {
+ sound.loadState(state);
+ display.loadState(state, state.mem.oamDmaPos < 0xA0 ? cart.rdisabledRam() : ioamhram);
+ tima.loadState(state, TimaInterruptRequester(intreq));
+ cart.loadState(state);
+ intreq.loadState(state);
+
+ divLastUpdate = state.mem.divLastUpdate;
+ intreq.setEventTime(state.mem.nextSerialtime > state.cpu.cycleCounter ? state.mem.nextSerialtime : state.cpu.cycleCounter);
+ intreq.setEventTime(state.mem.unhaltTime);
+ lastOamDmaUpdate = state.mem.lastOamDmaUpdate;
+ dmaSource = state.mem.dmaSource;
+ dmaDestination = state.mem.dmaDestination;
+ oamDmaPos = state.mem.oamDmaPos;
+ serialCnt = intreq.eventTime(SERIAL) != DISABLED_TIME
+ ? serialCntFrom(intreq.eventTime(SERIAL) - state.cpu.cycleCounter, ioamhram[0x102] & isCgb() * 2)
+ : 8;
+
+ cart.setVrambank(ioamhram[0x14F] & isCgb());
+ cart.setOamDmaSrc(OAM_DMA_SRC_OFF);
+ cart.setWrambank(isCgb() && (ioamhram[0x170] & 0x07) ? ioamhram[0x170] & 0x07 : 1);
+
+ if (lastOamDmaUpdate != DISABLED_TIME) {
+ oamDmaInitSetup();
+
+ const unsigned oamEventPos = oamDmaPos < 0xA0 ? 0xA0 : 0x100;
+
+ intreq.setEventTime(lastOamDmaUpdate + (oamEventPos - oamDmaPos) * 4);
+ }
+
+ intreq.setEventTime((ioamhram[0x140] & 0x80) ? display.nextMode1IrqTime() : state.cpu.cycleCounter);
+ blanklcd = false;
+
+ if (!isCgb())
+ std::memset(cart.vramdata() + 0x2000, 0, 0x2000);
+}
+
+void Memory::setEndtime(const unsigned long cycleCounter, const unsigned long inc) {
+ if (intreq.eventTime(BLIT) <= cycleCounter)
+ intreq.setEventTime(intreq.eventTime(BLIT) + (70224 << isDoubleSpeed()));
+
+ intreq.setEventTime(cycleCounter + (inc << isDoubleSpeed()));
+}
+
+void Memory::updateSerial(const unsigned long cc) {
+ if (!LINKCABLE) {
+ if (intreq.eventTime(SERIAL) != DISABLED_TIME) {
+ if (intreq.eventTime(SERIAL) <= cc) {
+ ioamhram[0x101] = (((ioamhram[0x101] + 1) << serialCnt) - 1) & 0xFF;
+ ioamhram[0x102] &= 0x7F;
+ intreq.setEventTime(DISABLED_TIME);
+ intreq.flagIrq(8);
+ } else {
+ const int targetCnt = serialCntFrom(intreq.eventTime(SERIAL) - cc, ioamhram[0x102] & isCgb() * 2);
+ ioamhram[0x101] = (((ioamhram[0x101] + 1) << (serialCnt - targetCnt)) - 1) & 0xFF;
+ serialCnt = targetCnt;
+ }
+ }
+ }
+ else {
+ if (intreq.eventTime(SERIAL) != DISABLED_TIME) {
+ if (intreq.eventTime(SERIAL) <= cc) {
+ linkClockTrigger = true;
+ intreq.setEventTime(DISABLED_TIME);
+ }
+ }
+ }
+}
+
+void Memory::updateTimaIrq(const unsigned long cc) {
+ while (intreq.eventTime(TIMA) <= cc)
+ tima.doIrqEvent(TimaInterruptRequester(intreq));
+}
+
+void Memory::updateIrqs(const unsigned long cc) {
+ updateSerial(cc);
+ updateTimaIrq(cc);
+ display.update(cc);
+}
+
+unsigned long Memory::event(unsigned long cycleCounter) {
+ if (lastOamDmaUpdate != DISABLED_TIME)
+ updateOamDma(cycleCounter);
+
+ switch (intreq.minEventId()) {
+ case UNHALT:
+ intreq.unhalt();
+ intreq.setEventTime(DISABLED_TIME);
+ break;
+ case END:
+ intreq.setEventTime(DISABLED_TIME - 1);
+
+ while (cycleCounter >= intreq.minEventTime() && intreq.eventTime(END) != DISABLED_TIME)
+ cycleCounter = event(cycleCounter);
+
+ intreq.setEventTime(DISABLED_TIME);
+
+ break;
+ case BLIT:
+ {
+ const bool lcden = ioamhram[0x140] >> 7 & 1;
+ unsigned long blitTime = intreq.eventTime(BLIT);
+
+ if (lcden | blanklcd) {
+ display.updateScreen(blanklcd, cycleCounter);
+ intreq.setEventTime(DISABLED_TIME);
+ intreq.setEventTime(DISABLED_TIME);
+
+ while (cycleCounter >= intreq.minEventTime())
+ cycleCounter = event(cycleCounter);
+ } else
+ blitTime += 70224 << isDoubleSpeed();
+
+ blanklcd = lcden ^ 1;
+ intreq.setEventTime(blitTime);
+ }
+ break;
+ case SERIAL:
+ updateSerial(cycleCounter);
+ break;
+ case OAM:
+ intreq.setEventTime(lastOamDmaUpdate == DISABLED_TIME ?
+ static_cast(DISABLED_TIME) : intreq.eventTime(OAM) + 0xA0 * 4);
+ break;
+ case DMA:
+ {
+ const bool doubleSpeed = isDoubleSpeed();
+ unsigned dmaSrc = dmaSource;
+ unsigned dmaDest = dmaDestination;
+ unsigned dmaLength = ((ioamhram[0x155] & 0x7F) + 0x1) * 0x10;
+ unsigned length = hdmaReqFlagged(intreq) ? 0x10 : dmaLength;
+
+ ackDmaReq(&intreq);
+
+ if ((static_cast(dmaDest) + length) & 0x10000) {
+ length = 0x10000 - dmaDest;
+ ioamhram[0x155] |= 0x80;
+ }
+
+ dmaLength -= length;
+
+ if (!(ioamhram[0x140] & 0x80))
+ dmaLength = 0;
+
+ {
+ unsigned long lOamDmaUpdate = lastOamDmaUpdate;
+ lastOamDmaUpdate = DISABLED_TIME;
+
+ while (length--) {
+ const unsigned src = dmaSrc++ & 0xFFFF;
+ const unsigned data = ((src & 0xE000) == 0x8000 || src > 0xFDFF) ? 0xFF : read(src, cycleCounter);
+
+ cycleCounter += 2 << doubleSpeed;
+
+ if (cycleCounter - 3 > lOamDmaUpdate) {
+ oamDmaPos = (oamDmaPos + 1) & 0xFF;
+ lOamDmaUpdate += 4;
+
+ if (oamDmaPos < 0xA0) {
+ if (oamDmaPos == 0)
+ startOamDma(lOamDmaUpdate - 1);
+
+ ioamhram[src & 0xFF] = data;
+ } else if (oamDmaPos == 0xA0) {
+ endOamDma(lOamDmaUpdate - 1);
+ lOamDmaUpdate = DISABLED_TIME;
+ }
+ }
+
+ nontrivial_write(0x8000 | (dmaDest++ & 0x1FFF), data, cycleCounter);
+ }
+
+ lastOamDmaUpdate = lOamDmaUpdate;
+ }
+
+ cycleCounter += 4;
+
+ dmaSource = dmaSrc;
+ dmaDestination = dmaDest;
+ ioamhram[0x155] = ((dmaLength / 0x10 - 0x1) & 0xFF) | (ioamhram[0x155] & 0x80);
+
+ if ((ioamhram[0x155] & 0x80) && display.hdmaIsEnabled()) {
+ if (lastOamDmaUpdate != DISABLED_TIME)
+ updateOamDma(cycleCounter);
+
+ display.disableHdma(cycleCounter);
+ }
+ }
+
+ break;
+ case TIMA:
+ tima.doIrqEvent(TimaInterruptRequester(intreq));
+ break;
+ case VIDEO:
+ display.update(cycleCounter);
+ break;
+ case INTERRUPTS:
+ if (halted()) {
+ if (isCgb())
+ cycleCounter += 4;
+
+ intreq.unhalt();
+ intreq.setEventTime(DISABLED_TIME);
+ }
+
+ if (ime()) {
+ unsigned address;
+ const unsigned pendingIrqs = intreq.pendingIrqs();
+ const unsigned n = pendingIrqs & -pendingIrqs;
+
+ if (n < 8) {
+ static const unsigned char lut[] = { 0x40, 0x48, 0x48, 0x50 };
+ address = lut[n-1];
+ } else
+ address = 0x50 + n;
+
+ intreq.ackIrq(n);
+ cycleCounter = interrupter.interrupt(address, cycleCounter, *this);
+ }
+
+ break;
+ }
+
+ return cycleCounter;
+}
+
+unsigned long Memory::stop(unsigned long cycleCounter) {
+ cycleCounter += 4 << isDoubleSpeed();
+
+ if (ioamhram[0x14D] & isCgb()) {
+ sound.generate_samples(cycleCounter, isDoubleSpeed());
+
+ display.speedChange(cycleCounter);
+ ioamhram[0x14D] ^= 0x81;
+
+ intreq.setEventTime((ioamhram[0x140] & 0x80) ? display.nextMode1IrqTime() : cycleCounter + (70224 << isDoubleSpeed()));
+
+ if (intreq.eventTime(END) > cycleCounter) {
+ intreq.setEventTime(cycleCounter + (isDoubleSpeed() ?
+ (intreq.eventTime(END) - cycleCounter) << 1 : (intreq.eventTime(END) - cycleCounter) >> 1));
+ }
+ // when switching speed, it seems that the CPU spontaneously restarts soon?
+ // otherwise, the cpu should be allowed to stay halted as long as needed
+ // so only execute this line when switching speed
+ intreq.setEventTime(cycleCounter + 0x20000 + isDoubleSpeed() * 8);
+ }
+
+ intreq.halt();
+
+ return cycleCounter;
+}
+
+static void decCycles(unsigned long &counter, const unsigned long dec) {
+ if (counter != DISABLED_TIME)
+ counter -= dec;
+}
+
+void Memory::decEventCycles(const MemEventId eventId, const unsigned long dec) {
+ if (intreq.eventTime(eventId) != DISABLED_TIME)
+ intreq.setEventTime(eventId, intreq.eventTime(eventId) - dec);
+}
+
+unsigned long Memory::resetCounters(unsigned long cycleCounter) {
+ if (lastOamDmaUpdate != DISABLED_TIME)
+ updateOamDma(cycleCounter);
+
+ updateIrqs(cycleCounter);
+
+ const unsigned long oldCC = cycleCounter;
+
+ {
+ const unsigned long divinc = (cycleCounter - divLastUpdate) >> 8;
+ ioamhram[0x104] = (ioamhram[0x104] + divinc) & 0xFF;
+ divLastUpdate += divinc << 8;
+ }
+
+ const unsigned long dec = cycleCounter < 0x10000 ? 0 : (cycleCounter & ~0x7FFFul) - 0x8000;
+
+ decCycles(divLastUpdate, dec);
+ decCycles(lastOamDmaUpdate, dec);
+ decEventCycles(SERIAL, dec);
+ decEventCycles(OAM, dec);
+ decEventCycles(BLIT, dec);
+ decEventCycles(END, dec);
+ decEventCycles(UNHALT, dec);
+
+ cycleCounter -= dec;
+
+ intreq.resetCc(oldCC, cycleCounter);
+ tima.resetCc(oldCC, cycleCounter, TimaInterruptRequester(intreq));
+ display.resetCc(oldCC, cycleCounter);
+ sound.resetCounter(cycleCounter, oldCC, isDoubleSpeed());
+
+ return cycleCounter;
+}
+
+void Memory::updateInput() {
unsigned state = 0xF;
if ((ioamhram[0x100] & 0x30) != 0x30 && getInput) {
@@ -371,720 +371,725 @@ void Memory::updateInput() {
if (state != 0xF && (ioamhram[0x100] & 0xF) == 0xF)
intreq.flagIrq(0x10);
- ioamhram[0x100] = (ioamhram[0x100] & -0x10u) | state;
-}
-
-void Memory::updateOamDma(const unsigned long cycleCounter) {
- const unsigned char *const oamDmaSrc = oamDmaSrcPtr();
- unsigned cycles = (cycleCounter - lastOamDmaUpdate) >> 2;
-
- while (cycles--) {
- oamDmaPos = (oamDmaPos + 1) & 0xFF;
- lastOamDmaUpdate += 4;
-
- if (oamDmaPos < 0xA0) {
- if (oamDmaPos == 0)
- startOamDma(lastOamDmaUpdate - 1);
-
- ioamhram[oamDmaPos] = oamDmaSrc ? oamDmaSrc[oamDmaPos] : cart.rtcRead();
- } else if (oamDmaPos == 0xA0) {
- endOamDma(lastOamDmaUpdate - 1);
- lastOamDmaUpdate = DISABLED_TIME;
- break;
- }
- }
-}
-
-void Memory::oamDmaInitSetup() {
- if (ioamhram[0x146] < 0xA0) {
- cart.setOamDmaSrc(ioamhram[0x146] < 0x80 ? OAM_DMA_SRC_ROM : OAM_DMA_SRC_VRAM);
- } else if (ioamhram[0x146] < 0xFE - isCgb() * 0x1E) {
- cart.setOamDmaSrc(ioamhram[0x146] < 0xC0 ? OAM_DMA_SRC_SRAM : OAM_DMA_SRC_WRAM);
- } else
- cart.setOamDmaSrc(OAM_DMA_SRC_INVALID);
-}
-
-static const unsigned char * oamDmaSrcZero() {
- static unsigned char zeroMem[0xA0];
- return zeroMem;
-}
-
-const unsigned char * Memory::oamDmaSrcPtr() const {
- switch (cart.oamDmaSrc()) {
- case OAM_DMA_SRC_ROM: return cart.romdata(ioamhram[0x146] >> 6) + (ioamhram[0x146] << 8);
- case OAM_DMA_SRC_SRAM: return cart.rsrambankptr() ? cart.rsrambankptr() + (ioamhram[0x146] << 8) : 0;
- case OAM_DMA_SRC_VRAM: return cart.vrambankptr() + (ioamhram[0x146] << 8);
- case OAM_DMA_SRC_WRAM: return cart.wramdata(ioamhram[0x146] >> 4 & 1) + (ioamhram[0x146] << 8 & 0xFFF);
- case OAM_DMA_SRC_INVALID:
- case OAM_DMA_SRC_OFF: break;
- }
-
- return ioamhram[0x146] == 0xFF && !isCgb() ? oamDmaSrcZero() : cart.rdisabledRam();
-}
-
-void Memory::startOamDma(const unsigned long cycleCounter) {
- display.oamChange(cart.rdisabledRam(), cycleCounter);
-}
-
-void Memory::endOamDma(const unsigned long cycleCounter) {
- oamDmaPos = 0xFE;
- cart.setOamDmaSrc(OAM_DMA_SRC_OFF);
- display.oamChange(ioamhram, cycleCounter);
-}
-
-unsigned Memory::nontrivial_ff_read(const unsigned P, const unsigned long cycleCounter) {
- if (lastOamDmaUpdate != DISABLED_TIME)
- updateOamDma(cycleCounter);
-
- switch (P & 0x7F) {
- case 0x00:
- updateInput();
- break;
- case 0x01:
- case 0x02:
- updateSerial(cycleCounter);
- break;
- case 0x04:
- {
- const unsigned long divcycles = (cycleCounter - divLastUpdate) >> 8;
- ioamhram[0x104] = (ioamhram[0x104] + divcycles) & 0xFF;
- divLastUpdate += divcycles << 8;
- }
-
- break;
- case 0x05:
- ioamhram[0x105] = tima.tima(cycleCounter);
- break;
- case 0x0F:
- updateIrqs(cycleCounter);
- ioamhram[0x10F] = intreq.ifreg();
- break;
- case 0x26:
- if (ioamhram[0x126] & 0x80) {
- sound.generate_samples(cycleCounter, isDoubleSpeed());
- ioamhram[0x126] = 0xF0 | sound.getStatus();
- } else
- ioamhram[0x126] = 0x70;
-
- break;
- case 0x30:
- case 0x31:
- case 0x32:
- case 0x33:
- case 0x34:
- case 0x35:
- case 0x36:
- case 0x37:
- case 0x38:
- case 0x39:
- case 0x3A:
- case 0x3B:
- case 0x3C:
- case 0x3D:
- case 0x3E:
- case 0x3F:
- sound.generate_samples(cycleCounter, isDoubleSpeed());
- return sound.waveRamRead(P & 0xF);
- case 0x41:
- return ioamhram[0x141] | display.getStat(ioamhram[0x145], cycleCounter);
- case 0x44:
- return display.getLyReg(cycleCounter/*+4*/);
- case 0x69:
- return display.cgbBgColorRead(ioamhram[0x168] & 0x3F, cycleCounter);
- case 0x6B:
- return display.cgbSpColorRead(ioamhram[0x16A] & 0x3F, cycleCounter);
- default: break;
- }
-
- return ioamhram[P - 0xFE00];
-}
-
-static bool isInOamDmaConflictArea(const OamDmaSrc oamDmaSrc, const unsigned addr, const bool cgb) {
- struct Area { unsigned short areaUpper, exceptAreaLower, exceptAreaWidth, pad; };
-
- static const Area cgbAreas[] = {
- { 0xC000, 0x8000, 0x2000, 0 },
- { 0xC000, 0x8000, 0x2000, 0 },
- { 0xA000, 0x0000, 0x8000, 0 },
- { 0xFE00, 0x0000, 0xC000, 0 },
- { 0xC000, 0x8000, 0x2000, 0 },
- { 0x0000, 0x0000, 0x0000, 0 }
- };
-
- static const Area dmgAreas[] = {
- { 0xFE00, 0x8000, 0x2000, 0 },
- { 0xFE00, 0x8000, 0x2000, 0 },
- { 0xA000, 0x0000, 0x8000, 0 },
- { 0xFE00, 0x8000, 0x2000, 0 },
- { 0xFE00, 0x8000, 0x2000, 0 },
- { 0x0000, 0x0000, 0x0000, 0 }
- };
-
- const Area *const a = cgb ? cgbAreas : dmgAreas;
-
- return addr < a[oamDmaSrc].areaUpper && addr - a[oamDmaSrc].exceptAreaLower >= a[oamDmaSrc].exceptAreaWidth;
-}
-
-unsigned Memory::nontrivial_read(const unsigned P, const unsigned long cycleCounter) {
- if (P < 0xFF80) {
- if (lastOamDmaUpdate != DISABLED_TIME) {
- updateOamDma(cycleCounter);
-
- if (isInOamDmaConflictArea(cart.oamDmaSrc(), P, isCgb()) && oamDmaPos < 0xA0)
- return ioamhram[oamDmaPos];
- }
-
- if (P < 0xC000) {
- if (P < 0x8000)
- return cart.romdata(P >> 14)[P];
-
- if (P < 0xA000) {
- if (!display.vramAccessible(cycleCounter))
- return 0xFF;
-
- return cart.vrambankptr()[P];
- }
-
- if (cart.rsrambankptr())
- return cart.rsrambankptr()[P];
-
- return cart.rtcRead();
- }
-
- if (P < 0xFE00)
- return cart.wramdata(P >> 12 & 1)[P & 0xFFF];
-
- if (P >= 0xFF00)
- return nontrivial_ff_read(P, cycleCounter);
-
- if (!display.oamReadable(cycleCounter) || oamDmaPos < 0xA0)
- return 0xFF;
- }
-
- return ioamhram[P - 0xFE00];
-}
-
-unsigned Memory::nontrivial_peek(const unsigned P) {
- if (P < 0xC000) {
- if (P < 0x8000)
- return cart.romdata(P >> 14)[P];
-
- if (P < 0xA000) {
- return cart.vrambankptr()[P];
- }
-
- if (cart.rsrambankptr())
- return cart.rsrambankptr()[P];
-
- return cart.rtcRead(); // verified side-effect free
- }
- if (P < 0xFE00)
- return cart.wramdata(P >> 12 & 1)[P & 0xFFF];
- if (P >= 0xFF00 && P < 0xFF80)
- return nontrivial_ff_peek(P);
- return ioamhram[P - 0xFE00];
-}
-
-unsigned Memory::nontrivial_ff_peek(const unsigned P) {
- // some regs may be somewhat wrong with this
- return ioamhram[P - 0xFE00];
-}
-
-void Memory::nontrivial_ff_write(const unsigned P, unsigned data, const unsigned long cycleCounter) {
- if (lastOamDmaUpdate != DISABLED_TIME)
- updateOamDma(cycleCounter);
-
- switch (P & 0xFF) {
+ ioamhram[0x100] = (ioamhram[0x100] & -0x10u) | state;
+}
+
+void Memory::updateOamDma(const unsigned long cycleCounter) {
+ const unsigned char *const oamDmaSrc = oamDmaSrcPtr();
+ unsigned cycles = (cycleCounter - lastOamDmaUpdate) >> 2;
+
+ while (cycles--) {
+ oamDmaPos = (oamDmaPos + 1) & 0xFF;
+ lastOamDmaUpdate += 4;
+
+ if (oamDmaPos < 0xA0) {
+ if (oamDmaPos == 0)
+ startOamDma(lastOamDmaUpdate - 1);
+
+ ioamhram[oamDmaPos] = oamDmaSrc ? oamDmaSrc[oamDmaPos] : cart.rtcRead();
+ } else if (oamDmaPos == 0xA0) {
+ endOamDma(lastOamDmaUpdate - 1);
+ lastOamDmaUpdate = DISABLED_TIME;
+ break;
+ }
+ }
+}
+
+void Memory::oamDmaInitSetup() {
+ if (ioamhram[0x146] < 0xA0) {
+ cart.setOamDmaSrc(ioamhram[0x146] < 0x80 ? OAM_DMA_SRC_ROM : OAM_DMA_SRC_VRAM);
+ } else if (ioamhram[0x146] < 0xFE - isCgb() * 0x1E) {
+ cart.setOamDmaSrc(ioamhram[0x146] < 0xC0 ? OAM_DMA_SRC_SRAM : OAM_DMA_SRC_WRAM);
+ } else
+ cart.setOamDmaSrc(OAM_DMA_SRC_INVALID);
+}
+
+static const unsigned char * oamDmaSrcZero() {
+ static unsigned char zeroMem[0xA0];
+ return zeroMem;
+}
+
+const unsigned char * Memory::oamDmaSrcPtr() const {
+ switch (cart.oamDmaSrc()) {
+ case OAM_DMA_SRC_ROM: return cart.romdata(ioamhram[0x146] >> 6) + (ioamhram[0x146] << 8);
+ case OAM_DMA_SRC_SRAM: return cart.rsrambankptr() ? cart.rsrambankptr() + (ioamhram[0x146] << 8) : 0;
+ case OAM_DMA_SRC_VRAM: return cart.vrambankptr() + (ioamhram[0x146] << 8);
+ case OAM_DMA_SRC_WRAM: return cart.wramdata(ioamhram[0x146] >> 4 & 1) + (ioamhram[0x146] << 8 & 0xFFF);
+ case OAM_DMA_SRC_INVALID:
+ case OAM_DMA_SRC_OFF: break;
+ }
+
+ return ioamhram[0x146] == 0xFF && !isCgb() ? oamDmaSrcZero() : cart.rdisabledRam();
+}
+
+void Memory::startOamDma(const unsigned long cycleCounter) {
+ display.oamChange(cart.rdisabledRam(), cycleCounter);
+}
+
+void Memory::endOamDma(const unsigned long cycleCounter) {
+ oamDmaPos = 0xFE;
+ cart.setOamDmaSrc(OAM_DMA_SRC_OFF);
+ display.oamChange(ioamhram, cycleCounter);
+}
+
+unsigned Memory::nontrivial_ff_read(const unsigned P, const unsigned long cycleCounter) {
+ if (lastOamDmaUpdate != DISABLED_TIME)
+ updateOamDma(cycleCounter);
+
+ switch (P & 0x7F) {
+ case 0x00:
+ updateInput();
+ break;
+ case 0x01:
+ case 0x02:
+ updateSerial(cycleCounter);
+ break;
+ case 0x04:
+ {
+ const unsigned long divcycles = (cycleCounter - divLastUpdate) >> 8;
+ ioamhram[0x104] = (ioamhram[0x104] + divcycles) & 0xFF;
+ divLastUpdate += divcycles << 8;
+ }
+
+ break;
+ case 0x05:
+ ioamhram[0x105] = tima.tima(cycleCounter);
+ break;
+ case 0x0F:
+ updateIrqs(cycleCounter);
+ ioamhram[0x10F] = intreq.ifreg();
+ break;
+ case 0x26:
+ if (ioamhram[0x126] & 0x80) {
+ sound.generate_samples(cycleCounter, isDoubleSpeed());
+ ioamhram[0x126] = 0xF0 | sound.getStatus();
+ } else
+ ioamhram[0x126] = 0x70;
+
+ break;
+ case 0x30:
+ case 0x31:
+ case 0x32:
+ case 0x33:
+ case 0x34:
+ case 0x35:
+ case 0x36:
+ case 0x37:
+ case 0x38:
+ case 0x39:
+ case 0x3A:
+ case 0x3B:
+ case 0x3C:
+ case 0x3D:
+ case 0x3E:
+ case 0x3F:
+ sound.generate_samples(cycleCounter, isDoubleSpeed());
+ return sound.waveRamRead(P & 0xF);
+ case 0x41:
+ return ioamhram[0x141] | display.getStat(ioamhram[0x145], cycleCounter);
+ case 0x44:
+ return display.getLyReg(cycleCounter/*+4*/);
+ case 0x69:
+ return display.cgbBgColorRead(ioamhram[0x168] & 0x3F, cycleCounter);
+ case 0x6B:
+ return display.cgbSpColorRead(ioamhram[0x16A] & 0x3F, cycleCounter);
+ default: break;
+ }
+
+ return ioamhram[P - 0xFE00];
+}
+
+static bool isInOamDmaConflictArea(const OamDmaSrc oamDmaSrc, const unsigned addr, const bool cgb) {
+ struct Area { unsigned short areaUpper, exceptAreaLower, exceptAreaWidth, pad; };
+
+ static const Area cgbAreas[] = {
+ { 0xC000, 0x8000, 0x2000, 0 },
+ { 0xC000, 0x8000, 0x2000, 0 },
+ { 0xA000, 0x0000, 0x8000, 0 },
+ { 0xFE00, 0x0000, 0xC000, 0 },
+ { 0xC000, 0x8000, 0x2000, 0 },
+ { 0x0000, 0x0000, 0x0000, 0 }
+ };
+
+ static const Area dmgAreas[] = {
+ { 0xFE00, 0x8000, 0x2000, 0 },
+ { 0xFE00, 0x8000, 0x2000, 0 },
+ { 0xA000, 0x0000, 0x8000, 0 },
+ { 0xFE00, 0x8000, 0x2000, 0 },
+ { 0xFE00, 0x8000, 0x2000, 0 },
+ { 0x0000, 0x0000, 0x0000, 0 }
+ };
+
+ const Area *const a = cgb ? cgbAreas : dmgAreas;
+
+ return addr < a[oamDmaSrc].areaUpper && addr - a[oamDmaSrc].exceptAreaLower >= a[oamDmaSrc].exceptAreaWidth;
+}
+
+unsigned Memory::nontrivial_read(const unsigned P, const unsigned long cycleCounter) {
+ if (P < 0xFF80) {
+ if (lastOamDmaUpdate != DISABLED_TIME) {
+ updateOamDma(cycleCounter);
+
+ if (isInOamDmaConflictArea(cart.oamDmaSrc(), P, isCgb()) && oamDmaPos < 0xA0)
+ return ioamhram[oamDmaPos];
+ }
+
+ if (P < 0xC000) {
+ if (P < 0x8000)
+ return cart.romdata(P >> 14)[P];
+
+ if (P < 0xA000) {
+ if (!display.vramAccessible(cycleCounter))
+ return 0xFF;
+
+ return cart.vrambankptr()[P];
+ }
+
+ if (cart.rsrambankptr())
+ return cart.rsrambankptr()[P];
+
+ return cart.rtcRead();
+ }
+
+ if (P < 0xFE00)
+ return cart.wramdata(P >> 12 & 1)[P & 0xFFF];
+
+ if (P >= 0xFF00)
+ return nontrivial_ff_read(P, cycleCounter);
+
+ if (!display.oamReadable(cycleCounter) || oamDmaPos < 0xA0)
+ return 0xFF;
+ }
+
+ return ioamhram[P - 0xFE00];
+}
+
+unsigned Memory::nontrivial_peek(const unsigned P) {
+ if (P < 0xC000) {
+ if (P < 0x8000)
+ return cart.romdata(P >> 14)[P];
+
+ if (P < 0xA000) {
+ return cart.vrambankptr()[P];
+ }
+
+ if (cart.rsrambankptr())
+ return cart.rsrambankptr()[P];
+
+ return cart.rtcRead(); // verified side-effect free
+ }
+ if (P < 0xFE00)
+ return cart.wramdata(P >> 12 & 1)[P & 0xFFF];
+ if (P >= 0xFF00 && P < 0xFF80)
+ return nontrivial_ff_peek(P);
+ return ioamhram[P - 0xFE00];
+}
+
+unsigned Memory::nontrivial_ff_peek(const unsigned P) {
+ // some regs may be somewhat wrong with this
+ return ioamhram[P - 0xFE00];
+}
+
+void Memory::nontrivial_ff_write(const unsigned P, unsigned data, const unsigned long cycleCounter) {
+ if (lastOamDmaUpdate != DISABLED_TIME)
+ updateOamDma(cycleCounter);
+
+ switch (P & 0xFF) {
case 0x00:
if ((data ^ ioamhram[0x100]) & 0x30) {
ioamhram[0x100] = (ioamhram[0x100] & ~0x30u) | (data & 0x30);
updateInput();
}
- return;
- case 0x01:
- updateSerial(cycleCounter);
- break;
- case 0x02:
- updateSerial(cycleCounter);
-
- serialCnt = 8;
- intreq.setEventTime((data & 0x81) == 0x81
- ? (data & isCgb() * 2 ? (cycleCounter & ~0x7ul) + 0x10 * 8 : (cycleCounter & ~0xFFul) + 0x200 * 8)
- : static_cast(DISABLED_TIME));
-
- data |= 0x7E - isCgb() * 2;
- break;
- case 0x04:
- ioamhram[0x104] = 0;
- divLastUpdate = cycleCounter;
- return;
- case 0x05:
- tima.setTima(data, cycleCounter, TimaInterruptRequester(intreq));
- break;
- case 0x06:
- tima.setTma(data, cycleCounter, TimaInterruptRequester(intreq));
- break;
- case 0x07:
- data |= 0xF8;
- tima.setTac(data, cycleCounter, TimaInterruptRequester(intreq));
- break;
- case 0x0F:
- updateIrqs(cycleCounter);
- intreq.setIfreg(0xE0 | data);
- return;
- case 0x10:
- if (!sound.isEnabled()) return;
- sound.generate_samples(cycleCounter, isDoubleSpeed());
- sound.set_nr10(data);
- data |= 0x80;
- break;
- case 0x11:
- if (!sound.isEnabled()) {
- if (isCgb())
- return;
-
- data &= 0x3F;
- }
-
- sound.generate_samples(cycleCounter, isDoubleSpeed());
- sound.set_nr11(data);
- data |= 0x3F;
- break;
- case 0x12:
- if (!sound.isEnabled()) return;
- sound.generate_samples(cycleCounter, isDoubleSpeed());
- sound.set_nr12(data);
- break;
- case 0x13:
- if (!sound.isEnabled()) return;
- sound.generate_samples(cycleCounter, isDoubleSpeed());
- sound.set_nr13(data);
- return;
- case 0x14:
- if (!sound.isEnabled()) return;
- sound.generate_samples(cycleCounter, isDoubleSpeed());
- sound.set_nr14(data);
- data |= 0xBF;
- break;
- case 0x16:
- if (!sound.isEnabled()) {
- if (isCgb())
- return;
-
- data &= 0x3F;
- }
-
- sound.generate_samples(cycleCounter, isDoubleSpeed());
- sound.set_nr21(data);
- data |= 0x3F;
- break;
- case 0x17:
- if (!sound.isEnabled()) return;
- sound.generate_samples(cycleCounter, isDoubleSpeed());
- sound.set_nr22(data);
- break;
- case 0x18:
- if (!sound.isEnabled()) return;
- sound.generate_samples(cycleCounter, isDoubleSpeed());
- sound.set_nr23(data);
- return;
- case 0x19:
- if (!sound.isEnabled()) return;
- sound.generate_samples(cycleCounter, isDoubleSpeed());
- sound.set_nr24(data);
- data |= 0xBF;
- break;
- case 0x1A:
- if (!sound.isEnabled()) return;
- sound.generate_samples(cycleCounter, isDoubleSpeed());
- sound.set_nr30(data);
- data |= 0x7F;
- break;
- case 0x1B:
- if (!sound.isEnabled() && isCgb()) return;
- sound.generate_samples(cycleCounter, isDoubleSpeed());
- sound.set_nr31(data);
- return;
- case 0x1C:
- if (!sound.isEnabled()) return;
- sound.generate_samples(cycleCounter, isDoubleSpeed());
- sound.set_nr32(data);
- data |= 0x9F;
- break;
- case 0x1D:
- if (!sound.isEnabled()) return;
- sound.generate_samples(cycleCounter, isDoubleSpeed());
- sound.set_nr33(data);
- return;
- case 0x1E:
- if (!sound.isEnabled()) return;
- sound.generate_samples(cycleCounter, isDoubleSpeed());
- sound.set_nr34(data);
- data |= 0xBF;
- break;
- case 0x20:
- if (!sound.isEnabled() && isCgb()) return;
- sound.generate_samples(cycleCounter, isDoubleSpeed());
- sound.set_nr41(data);
- return;
- case 0x21:
- if (!sound.isEnabled()) return;
- sound.generate_samples(cycleCounter, isDoubleSpeed());
- sound.set_nr42(data);
- break;
- case 0x22:
- if (!sound.isEnabled()) return;
- sound.generate_samples(cycleCounter, isDoubleSpeed());
- sound.set_nr43(data);
- break;
- case 0x23:
- if (!sound.isEnabled()) return;
- sound.generate_samples(cycleCounter, isDoubleSpeed());
- sound.set_nr44(data);
- data |= 0xBF;
- break;
- case 0x24:
- if (!sound.isEnabled()) return;
- sound.generate_samples(cycleCounter, isDoubleSpeed());
- sound.set_so_volume(data);
- break;
- case 0x25:
- if (!sound.isEnabled()) return;
- sound.generate_samples(cycleCounter, isDoubleSpeed());
- sound.map_so(data);
- break;
- case 0x26:
- if ((ioamhram[0x126] ^ data) & 0x80) {
- sound.generate_samples(cycleCounter, isDoubleSpeed());
-
- if (!(data & 0x80)) {
- for (unsigned i = 0xFF10; i < 0xFF26; ++i)
- ff_write(i, 0, cycleCounter);
-
- sound.setEnabled(false);
- } else {
- sound.reset();
- sound.setEnabled(true);
- }
- }
-
- data = (data & 0x80) | (ioamhram[0x126] & 0x7F);
- break;
- case 0x30:
- case 0x31:
- case 0x32:
- case 0x33:
- case 0x34:
- case 0x35:
- case 0x36:
- case 0x37:
- case 0x38:
- case 0x39:
- case 0x3A:
- case 0x3B:
- case 0x3C:
- case 0x3D:
- case 0x3E:
- case 0x3F:
- sound.generate_samples(cycleCounter, isDoubleSpeed());
- sound.waveRamWrite(P & 0xF, data);
- break;
- case 0x40:
- if (ioamhram[0x140] != data) {
- if ((ioamhram[0x140] ^ data) & 0x80) {
- const unsigned lyc = display.getStat(ioamhram[0x145], cycleCounter) & 4;
- const bool hdmaEnabled = display.hdmaIsEnabled();
-
- display.lcdcChange(data, cycleCounter);
- ioamhram[0x144] = 0;
- ioamhram[0x141] &= 0xF8;
-
- if (data & 0x80) {
- intreq.setEventTime(display.nextMode1IrqTime() + (blanklcd ? 0 : 70224 << isDoubleSpeed()));
- } else {
- ioamhram[0x141] |= lyc;
- intreq.setEventTime(cycleCounter + (456 * 4 << isDoubleSpeed()));
-
- if (hdmaEnabled)
- flagHdmaReq(&intreq);
- }
- } else
- display.lcdcChange(data, cycleCounter);
-
- ioamhram[0x140] = data;
- }
-
- return;
- case 0x41:
- display.lcdstatChange(data, cycleCounter);
- data = (ioamhram[0x141] & 0x87) | (data & 0x78);
- break;
- case 0x42:
- display.scyChange(data, cycleCounter);
- break;
- case 0x43:
- display.scxChange(data, cycleCounter);
- break;
- case 0x45:
- display.lycRegChange(data, cycleCounter);
- break;
- case 0x46:
- if (lastOamDmaUpdate != DISABLED_TIME)
- endOamDma(cycleCounter);
-
- lastOamDmaUpdate = cycleCounter;
- intreq.setEventTime(cycleCounter + 8);
- ioamhram[0x146] = data;
- oamDmaInitSetup();
- return;
- case 0x47:
- if (!isCgb())
- display.dmgBgPaletteChange(data, cycleCounter);
-
- break;
- case 0x48:
- if (!isCgb())
- display.dmgSpPalette1Change(data, cycleCounter);
-
- break;
- case 0x49:
- if (!isCgb())
- display.dmgSpPalette2Change(data, cycleCounter);
-
- break;
- case 0x4A:
- display.wyChange(data, cycleCounter);
- break;
- case 0x4B:
- display.wxChange(data, cycleCounter);
- break;
-
- case 0x4D:
+ return;
+ case 0x01:
+ updateSerial(cycleCounter);
+ break;
+ case 0x02:
+ updateSerial(cycleCounter);
+
+ serialCnt = 8;
+ intreq.setEventTime((data & 0x81) == 0x81
+ ? (data & isCgb() * 2 ? (cycleCounter & ~0x7ul) + 0x10 * 8 : (cycleCounter & ~0xFFul) + 0x200 * 8)
+ : static_cast(DISABLED_TIME));
+
+ data |= 0x7E - isCgb() * 2;
+ break;
+ case 0x04:
+ ioamhram[0x104] = 0;
+ divLastUpdate = cycleCounter;
+ return;
+ case 0x05:
+ tima.setTima(data, cycleCounter, TimaInterruptRequester(intreq));
+ break;
+ case 0x06:
+ tima.setTma(data, cycleCounter, TimaInterruptRequester(intreq));
+ break;
+ case 0x07:
+ data |= 0xF8;
+ tima.setTac(data, cycleCounter, TimaInterruptRequester(intreq));
+ break;
+ case 0x0F:
+ updateIrqs(cycleCounter);
+ intreq.setIfreg(0xE0 | data);
+ return;
+ case 0x10:
+ if (!sound.isEnabled()) return;
+ sound.generate_samples(cycleCounter, isDoubleSpeed());
+ sound.set_nr10(data);
+ data |= 0x80;
+ break;
+ case 0x11:
+ if (!sound.isEnabled()) {
+ if (isCgb())
+ return;
+
+ data &= 0x3F;
+ }
+
+ sound.generate_samples(cycleCounter, isDoubleSpeed());
+ sound.set_nr11(data);
+ data |= 0x3F;
+ break;
+ case 0x12:
+ if (!sound.isEnabled()) return;
+ sound.generate_samples(cycleCounter, isDoubleSpeed());
+ sound.set_nr12(data);
+ break;
+ case 0x13:
+ if (!sound.isEnabled()) return;
+ sound.generate_samples(cycleCounter, isDoubleSpeed());
+ sound.set_nr13(data);
+ return;
+ case 0x14:
+ if (!sound.isEnabled()) return;
+ sound.generate_samples(cycleCounter, isDoubleSpeed());
+ sound.set_nr14(data);
+ data |= 0xBF;
+ break;
+ case 0x16:
+ if (!sound.isEnabled()) {
+ if (isCgb())
+ return;
+
+ data &= 0x3F;
+ }
+
+ sound.generate_samples(cycleCounter, isDoubleSpeed());
+ sound.set_nr21(data);
+ data |= 0x3F;
+ break;
+ case 0x17:
+ if (!sound.isEnabled()) return;
+ sound.generate_samples(cycleCounter, isDoubleSpeed());
+ sound.set_nr22(data);
+ break;
+ case 0x18:
+ if (!sound.isEnabled()) return;
+ sound.generate_samples(cycleCounter, isDoubleSpeed());
+ sound.set_nr23(data);
+ return;
+ case 0x19:
+ if (!sound.isEnabled()) return;
+ sound.generate_samples(cycleCounter, isDoubleSpeed());
+ sound.set_nr24(data);
+ data |= 0xBF;
+ break;
+ case 0x1A:
+ if (!sound.isEnabled()) return;
+ sound.generate_samples(cycleCounter, isDoubleSpeed());
+ sound.set_nr30(data);
+ data |= 0x7F;
+ break;
+ case 0x1B:
+ if (!sound.isEnabled() && isCgb()) return;
+ sound.generate_samples(cycleCounter, isDoubleSpeed());
+ sound.set_nr31(data);
+ return;
+ case 0x1C:
+ if (!sound.isEnabled()) return;
+ sound.generate_samples(cycleCounter, isDoubleSpeed());
+ sound.set_nr32(data);
+ data |= 0x9F;
+ break;
+ case 0x1D:
+ if (!sound.isEnabled()) return;
+ sound.generate_samples(cycleCounter, isDoubleSpeed());
+ sound.set_nr33(data);
+ return;
+ case 0x1E:
+ if (!sound.isEnabled()) return;
+ sound.generate_samples(cycleCounter, isDoubleSpeed());
+ sound.set_nr34(data);
+ data |= 0xBF;
+ break;
+ case 0x20:
+ if (!sound.isEnabled() && isCgb()) return;
+ sound.generate_samples(cycleCounter, isDoubleSpeed());
+ sound.set_nr41(data);
+ return;
+ case 0x21:
+ if (!sound.isEnabled()) return;
+ sound.generate_samples(cycleCounter, isDoubleSpeed());
+ sound.set_nr42(data);
+ break;
+ case 0x22:
+ if (!sound.isEnabled()) return;
+ sound.generate_samples(cycleCounter, isDoubleSpeed());
+ sound.set_nr43(data);
+ break;
+ case 0x23:
+ if (!sound.isEnabled()) return;
+ sound.generate_samples(cycleCounter, isDoubleSpeed());
+ sound.set_nr44(data);
+ data |= 0xBF;
+ break;
+ case 0x24:
+ if (!sound.isEnabled()) return;
+ sound.generate_samples(cycleCounter, isDoubleSpeed());
+ sound.set_so_volume(data);
+ break;
+ case 0x25:
+ if (!sound.isEnabled()) return;
+ sound.generate_samples(cycleCounter, isDoubleSpeed());
+ sound.map_so(data);
+ break;
+ case 0x26:
+ if ((ioamhram[0x126] ^ data) & 0x80) {
+ sound.generate_samples(cycleCounter, isDoubleSpeed());
+
+ if (!(data & 0x80)) {
+ for (unsigned i = 0xFF10; i < 0xFF26; ++i)
+ ff_write(i, 0, cycleCounter);
+
+ sound.setEnabled(false);
+ } else {
+ sound.reset();
+ sound.setEnabled(true);
+ }
+ }
+
+ data = (data & 0x80) | (ioamhram[0x126] & 0x7F);
+ break;
+ case 0x30:
+ case 0x31:
+ case 0x32:
+ case 0x33:
+ case 0x34:
+ case 0x35:
+ case 0x36:
+ case 0x37:
+ case 0x38:
+ case 0x39:
+ case 0x3A:
+ case 0x3B:
+ case 0x3C:
+ case 0x3D:
+ case 0x3E:
+ case 0x3F:
+ sound.generate_samples(cycleCounter, isDoubleSpeed());
+ sound.waveRamWrite(P & 0xF, data);
+ break;
+ case 0x40:
+ if (ioamhram[0x140] != data) {
+ if ((ioamhram[0x140] ^ data) & 0x80) {
+ const unsigned lyc = display.getStat(ioamhram[0x145], cycleCounter) & 4;
+ const bool hdmaEnabled = display.hdmaIsEnabled();
+
+ display.lcdcChange(data, cycleCounter);
+ ioamhram[0x144] = 0;
+ ioamhram[0x141] &= 0xF8;
+
+ if (data & 0x80) {
+ intreq.setEventTime(display.nextMode1IrqTime() + (blanklcd ? 0 : 70224 << isDoubleSpeed()));
+ } else {
+ ioamhram[0x141] |= lyc;
+ intreq.setEventTime(cycleCounter + (456 * 4 << isDoubleSpeed()));
+
+ if (hdmaEnabled)
+ flagHdmaReq(&intreq);
+ }
+ } else
+ display.lcdcChange(data, cycleCounter);
+
+ ioamhram[0x140] = data;
+ }
+
+ return;
+ case 0x41:
+ display.lcdstatChange(data, cycleCounter);
+ data = (ioamhram[0x141] & 0x87) | (data & 0x78);
+ break;
+ case 0x42:
+ display.scyChange(data, cycleCounter);
+ break;
+ case 0x43:
+ display.scxChange(data, cycleCounter);
+ break;
+ case 0x45:
+ display.lycRegChange(data, cycleCounter);
+ break;
+ case 0x46:
+ if (lastOamDmaUpdate != DISABLED_TIME)
+ endOamDma(cycleCounter);
+
+ lastOamDmaUpdate = cycleCounter;
+ intreq.setEventTime(cycleCounter + 8);
+ ioamhram[0x146] = data;
+ oamDmaInitSetup();
+ return;
+ case 0x47:
+ if (!isCgb())
+ display.dmgBgPaletteChange(data, cycleCounter);
+
+ break;
+ case 0x48:
+ if (!isCgb())
+ display.dmgSpPalette1Change(data, cycleCounter);
+
+ break;
+ case 0x49:
+ if (!isCgb())
+ display.dmgSpPalette2Change(data, cycleCounter);
+
+ break;
+ case 0x4A:
+ display.wyChange(data, cycleCounter);
+ break;
+ case 0x4B:
+ display.wxChange(data, cycleCounter);
+ break;
+
+ case 0x4D:
if (isCgb())
- ioamhram[0x14D] = (ioamhram[0x14D] & ~1u) | (data & 1); return;
- case 0x4F:
- if (isCgb()) {
- cart.setVrambank(data & 1);
- ioamhram[0x14F] = 0xFE | data;
- }
-
- return;
- case 0x51:
- dmaSource = data << 8 | (dmaSource & 0xFF);
- return;
- case 0x52:
- dmaSource = (dmaSource & 0xFF00) | (data & 0xF0);
- return;
- case 0x53:
- dmaDestination = data << 8 | (dmaDestination & 0xFF);
- return;
- case 0x54:
- dmaDestination = (dmaDestination & 0xFF00) | (data & 0xF0);
- return;
- case 0x55:
- if (isCgb()) {
- ioamhram[0x155] = data & 0x7F;
-
- if (display.hdmaIsEnabled()) {
- if (!(data & 0x80)) {
- ioamhram[0x155] |= 0x80;
- display.disableHdma(cycleCounter);
- }
- } else {
- if (data & 0x80) {
- if (ioamhram[0x140] & 0x80) {
- display.enableHdma(cycleCounter);
- } else
- flagHdmaReq(&intreq);
- } else
- flagGdmaReq(&intreq);
- }
- }
-
- return;
- case 0x56:
- if (isCgb())
- ioamhram[0x156] = data | 0x3E;
-
- return;
- case 0x68:
- if (isCgb())
- ioamhram[0x168] = data | 0x40;
-
- return;
- case 0x69:
- if (isCgb()) {
- const unsigned index = ioamhram[0x168] & 0x3F;
-
- display.cgbBgColorChange(index, data, cycleCounter);
-
- ioamhram[0x168] = (ioamhram[0x168] & ~0x3F) | ((index + (ioamhram[0x168] >> 7)) & 0x3F);
- }
-
- return;
- case 0x6A:
- if (isCgb())
- ioamhram[0x16A] = data | 0x40;
-
- return;
- case 0x6B:
- if (isCgb()) {
- const unsigned index = ioamhram[0x16A] & 0x3F;
-
- display.cgbSpColorChange(index, data, cycleCounter);
-
- ioamhram[0x16A] = (ioamhram[0x16A] & ~0x3F) | ((index + (ioamhram[0x16A] >> 7)) & 0x3F);
- }
-
- return;
- case 0x6C:
- if (isCgb())
- ioamhram[0x16C] = data | 0xFE;
-
- return;
- case 0x70:
- if (isCgb()) {
- cart.setWrambank((data & 0x07) ? (data & 0x07) : 1);
- ioamhram[0x170] = data | 0xF8;
- }
-
- return;
- case 0x72:
- case 0x73:
- case 0x74:
- if (isCgb())
- break;
-
- return;
- case 0x75:
- if (isCgb())
- ioamhram[0x175] = data | 0x8F;
-
- return;
- case 0xFF:
- intreq.setIereg(data);
- break;
- default:
- return;
- }
-
- ioamhram[P - 0xFE00] = data;
-}
-
-void Memory::nontrivial_write(const unsigned P, const unsigned data, const unsigned long cycleCounter) {
- if (lastOamDmaUpdate != DISABLED_TIME) {
- updateOamDma(cycleCounter);
-
- if (isInOamDmaConflictArea(cart.oamDmaSrc(), P, isCgb()) && oamDmaPos < 0xA0) {
- ioamhram[oamDmaPos] = data;
- return;
- }
- }
-
- if (P < 0xFE00) {
- if (P < 0xA000) {
- if (P < 0x8000) {
- cart.mbcWrite(P, data);
- } else if (display.vramAccessible(cycleCounter)) {
- display.vramChange(cycleCounter);
- cart.vrambankptr()[P] = data;
- }
- } else if (P < 0xC000) {
- if (cart.wsrambankptr())
- cart.wsrambankptr()[P] = data;
- else
- cart.rtcWrite(data);
- } else
- cart.wramdata(P >> 12 & 1)[P & 0xFFF] = data;
- } else if (P - 0xFF80u >= 0x7Fu) {
- if (P < 0xFF00) {
- if (display.oamWritable(cycleCounter) && oamDmaPos >= 0xA0 && (P < 0xFEA0 || isCgb())) {
- display.oamChange(cycleCounter);
- ioamhram[P - 0xFE00] = data;
- }
- } else
- nontrivial_ff_write(P, data, cycleCounter);
- } else
- ioamhram[P - 0xFE00] = data;
-}
-
-int Memory::loadROM(const char *romfiledata, unsigned romfilelength, const bool forceDmg, const bool multicartCompat) {
- if (const int fail = cart.loadROM(romfiledata, romfilelength, forceDmg, multicartCompat))
- return fail;
-
- sound.init(cart.isCgb());
- display.reset(ioamhram, cart.vramdata(), cart.isCgb());
-
- return 0;
-}
-
-unsigned Memory::fillSoundBuffer(const unsigned long cycleCounter) {
- sound.generate_samples(cycleCounter, isDoubleSpeed());
- return sound.fillBuffer();
-}
-
-void Memory::setDmgPaletteColor(unsigned palNum, unsigned colorNum, unsigned long rgb32) {
- display.setDmgPaletteColor(palNum, colorNum, rgb32);
-}
-
-void Memory::setCgbPalette(unsigned *lut) {
- display.setCgbPalette(lut);
-}
-
-bool Memory::getMemoryArea(int which, unsigned char **data, int *length) {
- if (!data || !length)
- return false;
-
- switch (which)
- {
- case 4: // oam
- *data = &ioamhram[0];
- *length = 160;
- return true;
- case 5: // hram
- *data = &ioamhram[384];
- *length = 128;
- return true;
- case 6: // bgpal
- *data = (unsigned char *)display.bgPalette();
- *length = 32;
- return true;
- case 7: // sppal
- *data = (unsigned char *)display.spPalette();
- *length = 32;
- return true;
- default: // pass to cartridge
- return cart.getMemoryArea(which, data, length);
- }
-}
-
-int Memory::LinkStatus(int which)
-{
- switch (which)
- {
- case 256: // ClockSignaled
- return linkClockTrigger;
- case 257: // AckClockSignal
- linkClockTrigger = false;
- return 0;
- case 258: // GetOut
- return ioamhram[0x101] & 0xff;
- case 259: // connect link cable
- LINKCABLE = true;
- return 0;
- default: // ShiftIn
- if (ioamhram[0x102] & 0x80) // was enabled
- {
- ioamhram[0x101] = which;
- ioamhram[0x102] &= 0x7F;
- intreq.flagIrq(8);
- }
- return 0;
- }
-
- return -1;
-}
-
+ ioamhram[0x14D] = (ioamhram[0x14D] & ~1u) | (data & 1); return;
+ case 0x4F:
+ if (isCgb()) {
+ cart.setVrambank(data & 1);
+ ioamhram[0x14F] = 0xFE | data;
+ }
+
+ return;
+ case 0x50:
+ // this is the register that turns off the bootrom
+ // it can only ever be written to once (with 1) once boot rom finishes
+ cart.bios_remap(data);
+ return;
+ case 0x51:
+ dmaSource = data << 8 | (dmaSource & 0xFF);
+ return;
+ case 0x52:
+ dmaSource = (dmaSource & 0xFF00) | (data & 0xF0);
+ return;
+ case 0x53:
+ dmaDestination = data << 8 | (dmaDestination & 0xFF);
+ return;
+ case 0x54:
+ dmaDestination = (dmaDestination & 0xFF00) | (data & 0xF0);
+ return;
+ case 0x55:
+ if (isCgb()) {
+ ioamhram[0x155] = data & 0x7F;
+
+ if (display.hdmaIsEnabled()) {
+ if (!(data & 0x80)) {
+ ioamhram[0x155] |= 0x80;
+ display.disableHdma(cycleCounter);
+ }
+ } else {
+ if (data & 0x80) {
+ if (ioamhram[0x140] & 0x80) {
+ display.enableHdma(cycleCounter);
+ } else
+ flagHdmaReq(&intreq);
+ } else
+ flagGdmaReq(&intreq);
+ }
+ }
+
+ return;
+ case 0x56:
+ if (isCgb())
+ ioamhram[0x156] = data | 0x3E;
+
+ return;
+ case 0x68:
+ if (isCgb())
+ ioamhram[0x168] = data | 0x40;
+
+ return;
+ case 0x69:
+ if (isCgb()) {
+ const unsigned index = ioamhram[0x168] & 0x3F;
+
+ display.cgbBgColorChange(index, data, cycleCounter);
+
+ ioamhram[0x168] = (ioamhram[0x168] & ~0x3F) | ((index + (ioamhram[0x168] >> 7)) & 0x3F);
+ }
+
+ return;
+ case 0x6A:
+ if (isCgb())
+ ioamhram[0x16A] = data | 0x40;
+
+ return;
+ case 0x6B:
+ if (isCgb()) {
+ const unsigned index = ioamhram[0x16A] & 0x3F;
+
+ display.cgbSpColorChange(index, data, cycleCounter);
+
+ ioamhram[0x16A] = (ioamhram[0x16A] & ~0x3F) | ((index + (ioamhram[0x16A] >> 7)) & 0x3F);
+ }
+
+ return;
+ case 0x6C:
+ if (isCgb())
+ ioamhram[0x16C] = data | 0xFE;
+
+ return;
+ case 0x70:
+ if (isCgb()) {
+ cart.setWrambank((data & 0x07) ? (data & 0x07) : 1);
+ ioamhram[0x170] = data | 0xF8;
+ }
+
+ return;
+ case 0x72:
+ case 0x73:
+ case 0x74:
+ if (isCgb())
+ break;
+
+ return;
+ case 0x75:
+ if (isCgb())
+ ioamhram[0x175] = data | 0x8F;
+
+ return;
+ case 0xFF:
+ intreq.setIereg(data);
+ break;
+ default:
+ return;
+ }
+
+ ioamhram[P - 0xFE00] = data;
+}
+
+void Memory::nontrivial_write(const unsigned P, const unsigned data, const unsigned long cycleCounter) {
+ if (lastOamDmaUpdate != DISABLED_TIME) {
+ updateOamDma(cycleCounter);
+
+ if (isInOamDmaConflictArea(cart.oamDmaSrc(), P, isCgb()) && oamDmaPos < 0xA0) {
+ ioamhram[oamDmaPos] = data;
+ return;
+ }
+ }
+
+ if (P < 0xFE00) {
+ if (P < 0xA000) {
+ if (P < 0x8000) {
+ cart.mbcWrite(P, data);
+ } else if (display.vramAccessible(cycleCounter)) {
+ display.vramChange(cycleCounter);
+ cart.vrambankptr()[P] = data;
+ }
+ } else if (P < 0xC000) {
+ if (cart.wsrambankptr())
+ cart.wsrambankptr()[P] = data;
+ else
+ cart.rtcWrite(data);
+ } else
+ cart.wramdata(P >> 12 & 1)[P & 0xFFF] = data;
+ } else if (P - 0xFF80u >= 0x7Fu) {
+ if (P < 0xFF00) {
+ if (display.oamWritable(cycleCounter) && oamDmaPos >= 0xA0 && (P < 0xFEA0 || isCgb())) {
+ display.oamChange(cycleCounter);
+ ioamhram[P - 0xFE00] = data;
+ }
+ } else
+ nontrivial_ff_write(P, data, cycleCounter);
+ } else
+ ioamhram[P - 0xFE00] = data;
+}
+
+int Memory::loadROM(const char *romfiledata, unsigned romfilelength, const char *biosfiledata, unsigned biosfilelength, const bool forceDmg, const bool multicartCompat) {
+ if (const int fail = cart.loadROM(romfiledata, romfilelength, biosfiledata, biosfilelength, forceDmg, multicartCompat))
+ return fail;
+
+ sound.init(cart.isCgb());
+ display.reset(ioamhram, cart.vramdata(), cart.isCgb());
+
+ return 0;
+}
+
+unsigned Memory::fillSoundBuffer(const unsigned long cycleCounter) {
+ sound.generate_samples(cycleCounter, isDoubleSpeed());
+ return sound.fillBuffer();
+}
+
+void Memory::setDmgPaletteColor(unsigned palNum, unsigned colorNum, unsigned long rgb32) {
+ display.setDmgPaletteColor(palNum, colorNum, rgb32);
+}
+
+void Memory::setCgbPalette(unsigned *lut) {
+ display.setCgbPalette(lut);
+}
+
+bool Memory::getMemoryArea(int which, unsigned char **data, int *length) {
+ if (!data || !length)
+ return false;
+
+ switch (which)
+ {
+ case 4: // oam
+ *data = &ioamhram[0];
+ *length = 160;
+ return true;
+ case 5: // hram
+ *data = &ioamhram[384];
+ *length = 128;
+ return true;
+ case 6: // bgpal
+ *data = (unsigned char *)display.bgPalette();
+ *length = 32;
+ return true;
+ case 7: // sppal
+ *data = (unsigned char *)display.spPalette();
+ *length = 32;
+ return true;
+ default: // pass to cartridge
+ return cart.getMemoryArea(which, data, length);
+ }
+}
+
+int Memory::LinkStatus(int which)
+{
+ switch (which)
+ {
+ case 256: // ClockSignaled
+ return linkClockTrigger;
+ case 257: // AckClockSignal
+ linkClockTrigger = false;
+ return 0;
+ case 258: // GetOut
+ return ioamhram[0x101] & 0xff;
+ case 259: // connect link cable
+ LINKCABLE = true;
+ return 0;
+ default: // ShiftIn
+ if (ioamhram[0x102] & 0x80) // was enabled
+ {
+ ioamhram[0x101] = which;
+ ioamhram[0x102] &= 0x7F;
+ intreq.flagIrq(8);
+ }
+ return 0;
+ }
+
+ return -1;
+}
+
SYNCFUNC(Memory)
{
SSS(cart);
@@ -1107,5 +1112,5 @@ SYNCFUNC(Memory)
NSS(LINKCABLE);
NSS(linkClockTrigger);
}
-
-}
+
+}
diff --git a/libgambatte/src/memory.h b/libgambatte/src/memory.h
index bbf9e89c6d..78a89a0ee4 100644
--- a/libgambatte/src/memory.h
+++ b/libgambatte/src/memory.h
@@ -1,293 +1,297 @@
-/***************************************************************************
- * 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
-
-#include "mem/cartridge.h"
-#include "video.h"
-#include "sound.h"
-#include "interrupter.h"
-#include "tima.h"
+/***************************************************************************
+ * 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
+
+#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];
-
- void (*readCallback)(unsigned);
- void (*writeCallback)(unsigned);
- void (*execCallback)(unsigned);
- CDCallback cdCallback;
-
- 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);
-
- bool loaded() const { return cart.loaded(); }
- 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();
-
- 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((cc - intreq.eventTime(BLIT)) >> isDoubleSpeed());
- }
-
- void halt() { 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) {
- 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 read(const unsigned P, const unsigned long cycleCounter) {
- if (readCallback)
- readCallback(P);
- if(cdCallback)
- {
- CDMapResult map = CDMap(P);
- if(map.type != eCDLog_AddrType_None)
- cdCallback(map.addr,map.type,eCDLog_Flags_Data);
- }
- 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);
- if(cdCallback)
- {
- CDMapResult map = CDMap(P);
- if(map.type != eCDLog_AddrType_None)
- cdCallback(map.addr,map.type,first?eCDLog_Flags_ExecFirst : eCDLog_Flags_ExecOperand);
- }
- return cart.rmem(P >> 12) ? cart.rmem(P >> 12)[P] : nontrivial_read(P, cycleCounter);
- }
-
- unsigned peek(const unsigned 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);
- 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(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(void (*callback)(unsigned)) {
- this->readCallback = callback;
- }
- void setWriteCallback(void (*callback)(unsigned)) {
- this->writeCallback = callback;
- }
- void setExecCallback(void (*callback)(unsigned)) {
- 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 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);
-
- int LinkStatus(int which);
-
+
+namespace gambatte {
+class InputGetter;
+class FilterInfo;
+
+class Memory {
+ Cartridge cart;
+ unsigned char ioamhram[0x200];
+
+ void (*readCallback)(unsigned);
+ void (*writeCallback)(unsigned);
+ void (*execCallback)(unsigned);
+ CDCallback cdCallback;
+
+ 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);
+
+ bool loaded() const { return cart.loaded(); }
+ const char * romTitle() const { return cart.romTitle(); }
+
+ void bios_reset(int setting) {
+ nontrivial_ff_write(0x50, setting, 0);
+ }
+
+ 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();
+
+ 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((cc - intreq.eventTime(BLIT)) >> isDoubleSpeed());
+ }
+
+ void halt() { 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) {
+ 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 read(const unsigned P, const unsigned long cycleCounter) {
+ if (readCallback)
+ readCallback(P);
+ if(cdCallback)
+ {
+ CDMapResult map = CDMap(P);
+ if(map.type != eCDLog_AddrType_None)
+ cdCallback(map.addr,map.type,eCDLog_Flags_Data);
+ }
+ 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);
+ if(cdCallback)
+ {
+ CDMapResult map = CDMap(P);
+ if(map.type != eCDLog_AddrType_None)
+ cdCallback(map.addr,map.type,first?eCDLog_Flags_ExecFirst : eCDLog_Flags_ExecOperand);
+ }
+ return cart.rmem(P >> 12) ? cart.rmem(P >> 12)[P] : nontrivial_read(P, cycleCounter);
+ }
+
+ unsigned peek(const unsigned 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);
+ 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(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, const char *biosfiledata, unsigned biosfilelength, bool forceDmg, bool multicartCompat);
+
+ void setInputGetter(unsigned (*getInput)()) {
+ this->getInput = getInput;
+ }
+
+ void setReadCallback(void (*callback)(unsigned)) {
+ this->readCallback = callback;
+ }
+ void setWriteCallback(void (*callback)(unsigned)) {
+ this->writeCallback = callback;
+ }
+ void setExecCallback(void (*callback)(unsigned)) {
+ 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 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);
+
+ int LinkStatus(int which);
+
templatevoid SyncState(NewState *ns);
-};
-
-}
-
-#endif
+};
+
+}
+
+#endif
diff --git a/libgambatte/src/savestate.h b/libgambatte/src/savestate.h
index 4110161ca0..be3f21322a 100644
--- a/libgambatte/src/savestate.h
+++ b/libgambatte/src/savestate.h
@@ -38,7 +38,7 @@ struct SaveState {
void set(T *ptr, const unsigned long sz) { this->ptr = ptr; this->sz = sz; }
friend class SaverList;
- friend void setInitState(SaveState &, bool, bool, std::uint32_t);
+ friend void setInitState(SaveState &, bool, bool, std::uint32_t, bool);
};
struct CPU {
@@ -78,6 +78,7 @@ struct SaveState {
bool enableRam;
bool rambankMode;
bool hdmaTransfer;
+ bool using_bios;
} mem;
struct PPU {
diff --git a/output/dll/libgambatte.dll b/output/dll/libgambatte.dll
index 87284591fd..ecd8fa7bbb 100644
Binary files a/output/dll/libgambatte.dll and b/output/dll/libgambatte.dll differ